Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/cli/src/commands/eval/last-config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
import { getAgentvHome } from '@agentv/core';
import { getAgentvConfigDir } from '@agentv/core';

const AGENTV_DIR = getAgentvHome();
const LAST_CONFIG_PATH = path.join(AGENTV_DIR, 'last-config.json');
const CONFIG_DIR = getAgentvConfigDir();
const LAST_CONFIG_PATH = path.join(CONFIG_DIR, 'last-config.json');

export interface LastConfig {
readonly timestamp: string;
Expand All @@ -25,6 +25,6 @@ export async function loadLastConfig(): Promise<LastConfig | undefined> {
}

export async function saveLastConfig(config: LastConfig): Promise<void> {
await mkdir(AGENTV_DIR, { recursive: true });
await mkdir(CONFIG_DIR, { recursive: true });
await writeFile(LAST_CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
}
8 changes: 4 additions & 4 deletions apps/cli/src/update-check.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { spawn } from 'node:child_process';
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
import { getAgentvHome } from '@agentv/core';
import { getAgentvConfigDir } from '@agentv/core';

const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
const AGENTV_DIR = getAgentvHome();
const CONFIG_DIR = getAgentvConfigDir();
const CACHE_FILE = 'version-check.json';
const NPM_REGISTRY_URL = 'https://registry.npmjs.org/agentv/latest';

Expand All @@ -17,7 +17,7 @@ export interface UpdateCache {
* Read the cached update info from disk. Returns null if missing or malformed.
*/
export async function getCachedUpdateInfo(path?: string): Promise<UpdateCache | null> {
const filePath = path ?? join(AGENTV_DIR, CACHE_FILE);
const filePath = path ?? join(CONFIG_DIR, CACHE_FILE);
try {
const raw = await readFile(filePath, 'utf-8');
const data = JSON.parse(raw);
Expand Down Expand Up @@ -67,7 +67,7 @@ export function buildNotice(currentVersion: string, latestVersion: string | null
* survives even if the parent calls process.exit().
*/
export function backgroundUpdateCheck(): void {
const dir = AGENTV_DIR;
const dir = CONFIG_DIR;
const filePath = join(dir, CACHE_FILE);

const script = `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ The `{timestamp}` placeholder is replaced with an ISO-like timestamp (e.g., `202

### AGENTV_HOME

Override the default `~/.agentv` directory for all global runtime data (workspaces, git cache, subagents, trace state, version check cache):
Override the data directory for heavy runtime artifacts — workspaces, workspace pool, subagents, trace state, git cache, and downloaded dependencies. Lightweight config and cache files (`version-check.json`, `last-config.json`, `projects.yaml`) always stay in `~/.agentv` regardless of this setting.

```bash
# Linux/macOS
Expand Down
32 changes: 29 additions & 3 deletions packages/core/src/benchmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@
* discoverBenchmarks() to scan a directory tree for `.agentv/` directories.
*/

import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from 'node:fs';
import {
copyFileSync,
existsSync,
mkdirSync,
readFileSync,
readdirSync,
statSync,
writeFileSync,
} from 'node:fs';
import path from 'node:path';

import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';

import { getAgentvHome } from './paths.js';
import { getAgentvConfigDir, getAgentvHome } from './paths.js';

// ── Types ───────────────────────────────────────────────────────────────

Expand All @@ -40,13 +48,31 @@ export interface BenchmarkRegistry {
// ── Registry path ───────────────────────────────────────────────────────

export function getBenchmarksRegistryPath(): string {
return path.join(getAgentvHome(), 'projects.yaml');
return path.join(getAgentvConfigDir(), 'projects.yaml');
}

/**
* One-time migration: if projects.yaml exists at the old AGENTV_HOME location
* but not in ~/.agentv, copy it over. This handles the case where users had
* AGENTV_HOME set and projects.yaml was created there before the config/data split.
*/
function migrateProjectsYaml(targetPath: string): void {
const dataHome = getAgentvHome();
const configDir = getAgentvConfigDir();
if (dataHome === configDir) return;
const legacyPath = path.join(dataHome, 'projects.yaml');
if (!existsSync(legacyPath)) return;
mkdirSync(path.dirname(targetPath), { recursive: true });
copyFileSync(legacyPath, targetPath);
}

// ── Load / Save ─────────────────────────────────────────────────────────

export function loadBenchmarkRegistry(): BenchmarkRegistry {
const registryPath = getBenchmarksRegistryPath();
if (!existsSync(registryPath)) {
migrateProjectsYaml(registryPath);
}
if (!existsSync(registryPath)) {
return { benchmarks: [] };
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export {
type ResultsRepoStatus,
} from './evaluation/results-repo.js';
export {
getAgentvConfigDir,
getAgentvHome,
getWorkspacesRoot,
getSubagentsRoot,
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@ import path from 'node:path';

let logged = false;

/**
* The default config directory (~/.agentv). Always resolves to the user's home
* directory regardless of AGENTV_HOME. Used for lightweight, machine-local files
* like version-check.json, last-config.json, and projects.yaml.
*/
export function getAgentvConfigDir(): string {
return path.join(os.homedir(), '.agentv');
}

/**
* The data root for heavy/large artifacts (workspaces, workspace-pool, subagents,
* trace-state, cache, deps). Respects AGENTV_HOME override so users can relocate
* bulky data to a different drive. Falls back to ~/.agentv when unset.
*/
export function getAgentvHome(): string {
const envHome = process.env.AGENTV_HOME;
if (envHome && envHome !== 'undefined') {
Expand Down
10 changes: 10 additions & 0 deletions packages/core/test/paths.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import path from 'node:path';

import {
_resetLoggedForTesting,
getAgentvConfigDir,
getAgentvHome,
getSubagentsRoot,
getTraceStateRoot,
Expand Down Expand Up @@ -75,4 +76,13 @@ describe('paths', () => {
expect(spy).not.toHaveBeenCalled();
spy.mockRestore();
});

it('getAgentvConfigDir always returns ~/.agentv regardless of AGENTV_HOME', () => {
process.env.AGENTV_HOME = '/data/agentv';
expect(getAgentvConfigDir()).toBe(path.join(os.homedir(), '.agentv'));
});

it('getAgentvConfigDir returns ~/.agentv when AGENTV_HOME is not set', () => {
expect(getAgentvConfigDir()).toBe(path.join(os.homedir(), '.agentv'));
});
});
Loading