@agentage/cli 0.37.2 → 0.38.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -83
- package/dist/cli.js +5 -8
- package/dist/commands/auth/setup.d.ts +6 -16
- package/dist/commands/auth/setup.js +9 -139
- package/dist/commands/status/status.d.ts +4 -3
- package/dist/commands/status/status.js +4 -27
- package/dist/commands/update/update.d.ts +3 -10
- package/dist/commands/update/update.js +24 -41
- package/dist/core/flag.d.ts +1 -0
- package/dist/core/flag.js +1 -0
- package/dist/lib/auth/api.d.ts +3 -2
- package/dist/lib/auth/api.js +50 -56
- package/dist/lib/auth/env-match.js +1 -0
- package/dist/lib/auth/introspect.js +10 -11
- package/dist/lib/auth/oauth.d.ts +2 -0
- package/dist/lib/auth/oauth.js +30 -28
- package/dist/lib/auth/sign-in.d.ts +20 -0
- package/dist/lib/auth/sign-in.js +95 -0
- package/dist/lib/fs/config.d.ts +1 -0
- package/dist/lib/fs/config.js +14 -21
- package/dist/lib/fs/file-lock.d.ts +7 -2
- package/dist/lib/fs/file-lock.js +64 -74
- package/dist/lib/fs/json-file.d.ts +3 -0
- package/dist/lib/fs/json-file.js +43 -0
- package/dist/lib/net/fetch.d.ts +10 -0
- package/dist/lib/net/fetch.js +13 -0
- package/dist/lib/net/http.js +51 -23
- package/dist/lib/net/origins.d.ts +0 -2
- package/dist/lib/net/origins.js +1 -5
- package/dist/lib/net/user-agent.d.ts +1 -6
- package/dist/lib/net/user-agent.js +3 -4
- package/dist/lib/npm/npm-cli.d.ts +17 -0
- package/dist/lib/npm/npm-cli.js +77 -0
- package/dist/lib/status/status-info.d.ts +0 -18
- package/dist/lib/status/status-info.js +2 -42
- package/dist/lib/update/update-cache.d.ts +1 -0
- package/dist/lib/update/update-cache.js +7 -11
- package/dist/lib/update/update-check.js +1 -4
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +2 -0
- package/dist/program.d.ts +18 -1
- package/dist/program.js +75 -44
- package/package.json +17 -12
- package/dist/commands/daemon/daemon-cmd.d.ts +0 -2
- package/dist/commands/daemon/daemon-cmd.js +0 -107
- package/dist/commands/memory/memory-verbs.d.ts +0 -21
- package/dist/commands/memory/memory-verbs.js +0 -98
- package/dist/commands/memory/memory.d.ts +0 -2
- package/dist/commands/memory/memory.js +0 -54
- package/dist/commands/vault/vault-sync.d.ts +0 -13
- package/dist/commands/vault/vault-sync.js +0 -90
- package/dist/commands/vault/vault.d.ts +0 -22
- package/dist/commands/vault/vault.js +0 -129
- package/dist/daemon/actions.d.ts +0 -5
- package/dist/daemon/actions.js +0 -22
- package/dist/daemon/client-provider.d.ts +0 -2
- package/dist/daemon/client-provider.js +0 -16
- package/dist/daemon/entry.d.ts +0 -8
- package/dist/daemon/entry.js +0 -113
- package/dist/daemon/guards.d.ts +0 -3
- package/dist/daemon/guards.js +0 -13
- package/dist/daemon/lifecycle.d.ts +0 -17
- package/dist/daemon/lifecycle.js +0 -151
- package/dist/daemon/mcp-http.d.ts +0 -3
- package/dist/daemon/mcp-http.js +0 -34
- package/dist/daemon/server.d.ts +0 -23
- package/dist/daemon/server.js +0 -135
- package/dist/daemon-entry.d.ts +0 -1
- package/dist/daemon-entry.js +0 -9
- package/dist/lib/auth/provision.d.ts +0 -14
- package/dist/lib/auth/provision.js +0 -49
- package/dist/lib/daemon/daemon-client.d.ts +0 -37
- package/dist/lib/daemon/daemon-client.js +0 -136
- package/dist/lib/daemon/daemon-pref.d.ts +0 -2
- package/dist/lib/daemon/daemon-pref.js +0 -10
- package/dist/lib/memory/memory-client.d.ts +0 -30
- package/dist/lib/memory/memory-client.js +0 -98
- package/dist/lib/status/format.d.ts +0 -1
- package/dist/lib/status/format.js +0 -12
- package/dist/lib/status/vaults-format.d.ts +0 -2
- package/dist/lib/status/vaults-format.js +0 -49
- package/dist/lib/status/vaults-status.d.ts +0 -12
- package/dist/lib/status/vaults-status.js +0 -54
- package/dist/lib/update/update-lock.d.ts +0 -2
- package/dist/lib/update/update-lock.js +0 -109
- package/dist/lib/vault/vault-registry.d.ts +0 -12
- package/dist/lib/vault/vault-registry.js +0 -81
- package/dist/lib/vault/vaults.d.ts +0 -10
- package/dist/lib/vault/vaults.js +0 -66
- package/dist/lib/vault/vaults.schema.d.ts +0 -2
- package/dist/lib/vault/vaults.schema.js +0 -10
- package/dist/mcp/local-server.d.ts +0 -4
- package/dist/mcp/local-server.js +0 -26
- package/dist/observability.d.ts +0 -4
- package/dist/observability.js +0 -35
- package/dist/sync/discover/watcher.d.ts +0 -26
- package/dist/sync/discover/watcher.js +0 -159
- package/dist/sync/git/conflict.d.ts +0 -1
- package/dist/sync/git/conflict.js +0 -16
- package/dist/sync/git/cycle.d.ts +0 -18
- package/dist/sync/git/cycle.js +0 -158
- package/dist/sync/git/git-exec.d.ts +0 -22
- package/dist/sync/git/git-exec.js +0 -56
- package/dist/sync/git/manager.d.ts +0 -28
- package/dist/sync/git/manager.js +0 -114
- package/dist/sync/git/planner.d.ts +0 -15
- package/dist/sync/git/planner.js +0 -46
- package/dist/sync/git/remote-url.d.ts +0 -3
- package/dist/sync/git/remote-url.js +0 -30
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
1
|
import { join } from 'node:path';
|
|
3
2
|
import { ensureConfigDir, getConfigDir } from '../fs/config.js';
|
|
3
|
+
import { isRecord, readJson, writeJsonAtomic } from '../fs/json-file.js';
|
|
4
4
|
import { fetchJsonUnref } from '../net/http.js';
|
|
5
5
|
import { compareVersions, INSTALL_HINT, REGISTRY_URL } from './update-check.js';
|
|
6
6
|
import { VERSION } from '../../utils/version.js';
|
|
@@ -8,18 +8,14 @@ const CACHE_FILE = 'update-check.json';
|
|
|
8
8
|
const TTL_MS = 60 * 60 * 1000; // passive checks refresh at most once an hour
|
|
9
9
|
const BG_TIMEOUT_MS = 3000; // hard cap on the whole background attempt, connect included
|
|
10
10
|
const cachePath = () => join(getConfigDir(), CACHE_FILE);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
catch {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
};
|
|
11
|
+
// A wrong-typed field reads as no cache: the post-action hint must never throw.
|
|
12
|
+
export const isUpdateCache = (value) => isRecord(value) &&
|
|
13
|
+
typeof value['checkedAt'] === 'number' &&
|
|
14
|
+
(value['latest'] === null || typeof value['latest'] === 'string');
|
|
15
|
+
export const readUpdateCache = () => readJson(cachePath(), isUpdateCache);
|
|
20
16
|
const writeUpdateCache = (latest, now) => {
|
|
21
17
|
ensureConfigDir();
|
|
22
|
-
|
|
18
|
+
writeJsonAtomic(cachePath(), { checkedAt: now, latest });
|
|
23
19
|
};
|
|
24
20
|
// The one dim hint line printed after a command, read purely from the cache (never the network),
|
|
25
21
|
// only when the cached latest is newer than us. null = print nothing.
|
|
@@ -7,10 +7,7 @@ export const REGISTRY_URL = 'https://registry.npmjs.org/@agentage/cli/latest';
|
|
|
7
7
|
// Compare dotted numeric versions (major.minor.patch); prerelease/build suffixes are
|
|
8
8
|
// ignored - good enough for an update hint. Returns -1 / 0 / 1.
|
|
9
9
|
export const compareVersions = (a, b) => {
|
|
10
|
-
const parts = (v) => v
|
|
11
|
-
.split('-')[0]
|
|
12
|
-
.split('.')
|
|
13
|
-
.map((n) => Number.parseInt(n, 10) || 0);
|
|
10
|
+
const parts = (v) => (v.split('-')[0] ?? '').split('.').map((n) => Number.parseInt(n, 10) || 0);
|
|
14
11
|
const pa = parts(a);
|
|
15
12
|
const pb = parts(b);
|
|
16
13
|
for (let i = 0; i < 3; i++) {
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PLUGIN_API_VERSION = "1.0.0";
|
package/dist/plugin.js
ADDED
package/dist/program.d.ts
CHANGED
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { type SetupOptions } from './commands/auth/setup.js';
|
|
3
|
+
import { type StatusOptions } from './commands/status/status.js';
|
|
4
|
+
import { type UpdateOptions } from './commands/update/update.js';
|
|
5
|
+
export interface ProgramDeps {
|
|
6
|
+
setup: (opts: SetupOptions) => Promise<void>;
|
|
7
|
+
status: (opts: StatusOptions) => Promise<void>;
|
|
8
|
+
update: (opts: UpdateOptions) => Promise<void>;
|
|
9
|
+
updateHint: () => string | null;
|
|
10
|
+
refreshUpdateCache: () => Promise<void>;
|
|
11
|
+
writeOut: (text: string) => void;
|
|
12
|
+
writeErr: (text: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const EXIT_OK = 0;
|
|
15
|
+
export declare const EXIT_FAILED = 1;
|
|
16
|
+
export declare const EXIT_USAGE = 2;
|
|
17
|
+
export declare const createProgram: (deps?: ProgramDeps) => Command;
|
|
18
|
+
export declare const run: (argv?: string[], deps?: ProgramDeps) => Promise<number>;
|
package/dist/program.js
CHANGED
|
@@ -1,50 +1,81 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { registerUpdate } from './commands/update/update.js';
|
|
8
|
-
import { registerVault } from './commands/vault/vault.js';
|
|
9
|
-
import { disableDaemon } from './lib/daemon/daemon-pref.js';
|
|
2
|
+
import { Command, CommanderError } from 'commander';
|
|
3
|
+
import { registerSetup, runSetup } from './commands/auth/setup.js';
|
|
4
|
+
import { registerStatus, runStatus } from './commands/status/status.js';
|
|
5
|
+
import { registerUpdate, runUpdate } from './commands/update/update.js';
|
|
6
|
+
import { ensureSignedIn, signOut } from './lib/auth/sign-in.js';
|
|
10
7
|
import { refreshUpdateCache, updateHint } from './lib/update/update-cache.js';
|
|
11
8
|
import { VERSION } from './utils/version.js';
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
9
|
+
const defaultDeps = {
|
|
10
|
+
setup: (opts) => runSetup(opts, {
|
|
11
|
+
ensureSignedIn: (signInOpts) => ensureSignedIn(signInOpts),
|
|
12
|
+
signOut: () => signOut(),
|
|
13
|
+
printStatus: () => runStatus({}),
|
|
14
|
+
}),
|
|
15
|
+
status: (opts) => runStatus(opts),
|
|
16
|
+
update: (opts) => runUpdate(opts),
|
|
17
|
+
updateHint,
|
|
18
|
+
refreshUpdateCache: () => refreshUpdateCache(),
|
|
19
|
+
writeOut: (text) => void process.stdout.write(text),
|
|
20
|
+
writeErr: (text) => void process.stderr.write(text),
|
|
21
|
+
};
|
|
22
|
+
export const EXIT_OK = 0;
|
|
23
|
+
export const EXIT_FAILED = 1;
|
|
24
|
+
export const EXIT_USAGE = 2;
|
|
25
|
+
const ACTION_FAILED = 'agentage.actionFailed';
|
|
26
|
+
const messageOf = (err) => (err instanceof Error ? err.message : String(err));
|
|
27
|
+
// One failure path for every command: a red stderr line, then exit 1 through run().
|
|
28
|
+
const withAction = (deps, fn, prefix = '') => async (opts) => {
|
|
29
|
+
try {
|
|
30
|
+
await fn(opts);
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
deps.writeErr(`${chalk.red(`${prefix}${messageOf(err)}`)}\n`);
|
|
34
|
+
throw new CommanderError(EXIT_FAILED, ACTION_FAILED, messageOf(err));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
// status and update report update state themselves; the hint never touches --json stdout.
|
|
38
|
+
const hintAfter = (deps) => (_program, action) => {
|
|
39
|
+
if (action.name() === 'status' || action.name() === 'update')
|
|
30
40
|
return;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
41
|
+
const hint = action.opts()['json'] ? null : deps.updateHint();
|
|
42
|
+
if (hint)
|
|
43
|
+
deps.writeErr(`${chalk.dim(hint)}\n`);
|
|
44
|
+
void deps.refreshUpdateCache();
|
|
45
|
+
};
|
|
46
|
+
export const createProgram = (deps = defaultDeps) => {
|
|
47
|
+
const program = new Command()
|
|
48
|
+
.name('agentage')
|
|
49
|
+
.description('Connect this machine to agentage from the terminal')
|
|
50
|
+
.version(VERSION)
|
|
51
|
+
.exitOverride()
|
|
52
|
+
.configureOutput({ writeOut: deps.writeOut, writeErr: deps.writeErr })
|
|
53
|
+
.addHelpText('after', '\nNew here? Run: agentage setup to connect this machine.')
|
|
54
|
+
.hook('postAction', hintAfter(deps));
|
|
55
|
+
registerSetup(program, withAction(deps, deps.setup, 'Setup failed: '));
|
|
56
|
+
registerStatus(program, withAction(deps, deps.status));
|
|
57
|
+
registerUpdate(program, withAction(deps, deps.update));
|
|
58
|
+
return program;
|
|
59
|
+
};
|
|
60
|
+
// Commander's own exit 0 (--help, --version) stays 0; any other commander error is usage.
|
|
61
|
+
const exitCodeOf = (err, deps) => {
|
|
62
|
+
if (!(err instanceof CommanderError)) {
|
|
63
|
+
deps.writeErr(`${chalk.red(messageOf(err))}\n`);
|
|
64
|
+
return EXIT_FAILED;
|
|
65
|
+
}
|
|
66
|
+
if (err.code === ACTION_FAILED)
|
|
67
|
+
return EXIT_FAILED;
|
|
68
|
+
return err.exitCode === 0 ? EXIT_OK : EXIT_USAGE;
|
|
69
|
+
};
|
|
70
|
+
// Returns the exit code instead of exiting, so piped stdout is never cut short.
|
|
71
|
+
export const run = async (argv = process.argv, deps = defaultDeps) => {
|
|
72
|
+
if (process.env['NO_COLOR'])
|
|
73
|
+
chalk.level = 0; // chalk ignores NO_COLOR on its own
|
|
74
|
+
try {
|
|
75
|
+
await createProgram(deps).parseAsync(argv);
|
|
76
|
+
return EXIT_OK;
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
return exitCodeOf(err, deps);
|
|
35
80
|
}
|
|
36
|
-
void refreshUpdateCache();
|
|
37
|
-
});
|
|
38
|
-
registerSetup(program);
|
|
39
|
-
registerStatus(program);
|
|
40
|
-
registerVault(program);
|
|
41
|
-
registerMemory(program);
|
|
42
|
-
registerDaemon(program);
|
|
43
|
-
registerUpdate(program);
|
|
44
|
-
// Called by the bin (src/cli.ts) once the observability bootstrap has run.
|
|
45
|
-
export const run = async () => {
|
|
46
|
-
await program.parseAsync().catch((err) => {
|
|
47
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
48
|
-
process.exit(1);
|
|
49
|
-
});
|
|
50
81
|
};
|
package/package.json
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentage/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.38.1",
|
|
4
4
|
"description": "The agentage CLI - connect this machine to agentage from the terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./plugin": {
|
|
14
|
+
"types": "./dist/plugin.d.ts",
|
|
15
|
+
"default": "./dist/plugin.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
8
19
|
"bin": {
|
|
9
20
|
"agentage": "./dist/cli.js"
|
|
10
21
|
},
|
|
@@ -25,11 +36,11 @@
|
|
|
25
36
|
},
|
|
26
37
|
"scripts": {
|
|
27
38
|
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
28
|
-
"type-check": "tsc --noEmit",
|
|
29
|
-
"lint": "eslint src",
|
|
30
|
-
"lint:fix": "eslint src --fix",
|
|
31
|
-
"format": "prettier --write \"{src,e2e}/**/*.ts\"",
|
|
32
|
-
"format:check": "prettier --check \"{src,e2e}/**/*.ts\"",
|
|
39
|
+
"type-check": "tsc --noEmit && tsc -p fixtures",
|
|
40
|
+
"lint": "eslint src e2e fixtures",
|
|
41
|
+
"lint:fix": "eslint src e2e fixtures --fix",
|
|
42
|
+
"format": "prettier --write \"{src,e2e}/**/*.ts\" \"fixtures/**/*.{js,json}\"",
|
|
43
|
+
"format:check": "prettier --check \"{src,e2e}/**/*.ts\" \"fixtures/**/*.{js,json}\"",
|
|
33
44
|
"test": "vitest run",
|
|
34
45
|
"test:watch": "vitest",
|
|
35
46
|
"test:coverage": "vitest run --coverage",
|
|
@@ -40,17 +51,11 @@
|
|
|
40
51
|
"prepublishOnly": "npm run verify"
|
|
41
52
|
},
|
|
42
53
|
"dependencies": {
|
|
43
|
-
"@agentage/memory-core": "^0.5.0",
|
|
44
|
-
"@agentage/observability": "^1.4.0",
|
|
45
|
-
"@agentage/server-memory": "^0.11.0",
|
|
46
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
47
|
-
"@opentelemetry/api": "^1.9.0",
|
|
48
54
|
"chalk": "^6.0.0",
|
|
49
55
|
"commander": "^15.0.0",
|
|
50
56
|
"open": "^11.0.0"
|
|
51
57
|
},
|
|
52
58
|
"devDependencies": {
|
|
53
|
-
"@anthropic-ai/sdk": "0.135.0",
|
|
54
59
|
"@playwright/test": "latest",
|
|
55
60
|
"@types/node": "latest",
|
|
56
61
|
"@typescript-eslint/eslint-plugin": "latest",
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { isDaemonRunning, resolvePort, signalPid, stopDaemonSafely, } from '../../daemon/lifecycle.js';
|
|
3
|
-
import { health, mismatchNotice, spawnDaemon, syncStatus } from '../../lib/daemon/daemon-client.js';
|
|
4
|
-
const startAction = async (opts = {}) => {
|
|
5
|
-
const port = resolvePort();
|
|
6
|
-
const existing = await health(port);
|
|
7
|
-
if (existing) {
|
|
8
|
-
console.log(chalk.gray(`Daemon already running (pid ${existing.pid}, port ${port}).`));
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
const noMcp = opts.mcp === false;
|
|
12
|
-
const outcome = await spawnDaemon(port, { noMcp });
|
|
13
|
-
if (!outcome.ok) {
|
|
14
|
-
if (outcome.reason === 'port-in-use') {
|
|
15
|
-
console.error(chalk.red(`Port ${port} is in use by another process - set AGENTAGE_DAEMON_PORT to use a different port.`));
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
console.error(chalk.red('Daemon failed to start.'));
|
|
19
|
-
}
|
|
20
|
-
process.exitCode = 1;
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
const h = await health(port);
|
|
24
|
-
const mcp = noMcp ? 'off' : 'on';
|
|
25
|
-
console.log(chalk.green(`Daemon started (pid ${h?.pid ?? '?'}, port ${port}, mcp ${mcp}).`));
|
|
26
|
-
};
|
|
27
|
-
// Detect the daemon the same way `start` does (tokenless /health), so a legacy daemon that never
|
|
28
|
-
// wrote this config dir's pidfile is not misreported as "not running". With a pidfile we own, use
|
|
29
|
-
// the safe pid-confirming stop; otherwise fall back to signalling the pid /health reports, or - if
|
|
30
|
-
// none is available - report the truth rather than a false "not running".
|
|
31
|
-
const stopAction = async () => {
|
|
32
|
-
if (isDaemonRunning()) {
|
|
33
|
-
if (await stopDaemonSafely())
|
|
34
|
-
console.log(chalk.green('Daemon stopped.'));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
const port = resolvePort();
|
|
38
|
-
const h = await health(port);
|
|
39
|
-
if (!h) {
|
|
40
|
-
console.log(chalk.gray('Daemon is not running.'));
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
if (typeof h.pid === 'number' && signalPid(h.pid)) {
|
|
44
|
-
console.log(chalk.green(`Daemon stopped (pid ${h.pid}).`));
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const who = typeof h.pid === 'number' ? `pid ${h.pid}` : `port ${port}`;
|
|
48
|
-
console.error(chalk.yellow(`Daemon is running (${who}) but has no pidfile to stop it safely; stop it with: kill ${h.pid ?? '<pid>'}`));
|
|
49
|
-
process.exitCode = 1;
|
|
50
|
-
};
|
|
51
|
-
const statusAction = async () => {
|
|
52
|
-
const port = resolvePort();
|
|
53
|
-
const h = await health(port);
|
|
54
|
-
if (!h) {
|
|
55
|
-
console.log(isDaemonRunning()
|
|
56
|
-
? chalk.yellow(`Daemon pid file present but unreachable on port ${port}.`)
|
|
57
|
-
: chalk.gray('Daemon is not running.'));
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
console.log(`pid ${h.pid ?? '?'}`);
|
|
61
|
-
console.log(`port ${port}`);
|
|
62
|
-
if (typeof h.uptime === 'number')
|
|
63
|
-
console.log(`uptime ${h.uptime}s`);
|
|
64
|
-
if (typeof h.served === 'number')
|
|
65
|
-
console.log(`served ${h.served}`);
|
|
66
|
-
console.log(`mcp ${h.mcp === false ? 'off' : 'on'}`);
|
|
67
|
-
console.log(`version ${h.version}`);
|
|
68
|
-
const notice = mismatchNotice(h.version);
|
|
69
|
-
if (notice)
|
|
70
|
-
console.log(chalk.yellow(notice));
|
|
71
|
-
const sync = await syncStatus(port);
|
|
72
|
-
if (sync && sync.vaults.length > 0) {
|
|
73
|
-
console.log('sync');
|
|
74
|
-
for (const v of sync.vaults) {
|
|
75
|
-
const cadence = v.intervalSeconds > 0 ? `every ${v.intervalSeconds}s` : 'manual';
|
|
76
|
-
const state = v.running
|
|
77
|
-
? 'running'
|
|
78
|
-
: v.lastError
|
|
79
|
-
? `error: ${v.lastError}`
|
|
80
|
-
: v.lastRun
|
|
81
|
-
? `ok ${v.lastRun}`
|
|
82
|
-
: 'scheduled';
|
|
83
|
-
console.log(` ${v.vault.padEnd(16)} ${cadence.padEnd(12)} ${state}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (sync?.discover && sync.discover.roots.length > 0) {
|
|
87
|
-
console.log(`discover roots (${sync.discover.roots.length})`);
|
|
88
|
-
for (const root of sync.discover.roots)
|
|
89
|
-
console.log(` ${root}`);
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
export const registerDaemon = (program) => {
|
|
93
|
-
const daemon = program.command('daemon').description('Manage the local engine daemon');
|
|
94
|
-
daemon
|
|
95
|
-
.command('start')
|
|
96
|
-
.description('Start the daemon (idempotent)')
|
|
97
|
-
.option('--no-mcp', 'do not serve the local MCP endpoint at /mcp')
|
|
98
|
-
.action((opts) => startAction(opts));
|
|
99
|
-
daemon
|
|
100
|
-
.command('stop')
|
|
101
|
-
.description('Stop the daemon')
|
|
102
|
-
.action(() => stopAction());
|
|
103
|
-
daemon
|
|
104
|
-
.command('status')
|
|
105
|
-
.description('Show the daemon pid, uptime, and version')
|
|
106
|
-
.action(() => statusAction());
|
|
107
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { type MemoryClient } from '../../lib/memory/memory-client.js';
|
|
2
|
-
export interface CommonOpts {
|
|
3
|
-
vault?: string;
|
|
4
|
-
json?: boolean;
|
|
5
|
-
}
|
|
6
|
-
export declare const runSearch: (query: string, opts: CommonOpts & {
|
|
7
|
-
limit?: string;
|
|
8
|
-
}, client?: MemoryClient) => Promise<void>;
|
|
9
|
-
export declare const runRead: (ref: string, opts: CommonOpts, client?: MemoryClient) => Promise<void>;
|
|
10
|
-
export declare const runWrite: (ref: string, opts: CommonOpts & {
|
|
11
|
-
body?: string;
|
|
12
|
-
frontmatter?: string;
|
|
13
|
-
}, client?: MemoryClient) => Promise<void>;
|
|
14
|
-
export declare const runEdit: (ref: string, opts: CommonOpts & {
|
|
15
|
-
old?: string;
|
|
16
|
-
new?: string;
|
|
17
|
-
body?: string;
|
|
18
|
-
append?: boolean;
|
|
19
|
-
}, client?: MemoryClient) => Promise<void>;
|
|
20
|
-
export declare const runList: (folder: string | undefined, opts: CommonOpts, client?: MemoryClient) => Promise<void>;
|
|
21
|
-
export declare const runDelete: (ref: string, opts: CommonOpts, client?: MemoryClient) => Promise<void>;
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { ensureDaemon } from '../../lib/daemon/daemon-client.js';
|
|
3
|
-
import { daemonDisabled } from '../../lib/daemon/daemon-pref.js';
|
|
4
|
-
import { createDirectClient } from '../../lib/memory/memory-client.js';
|
|
5
|
-
import { loadVaultsConfig } from '../../lib/vault/vaults.js';
|
|
6
|
-
// Default engine path (DO3/DO4): the daemon - single writer, autostarted - when reachable; the
|
|
7
|
-
// in-process DirectClient as a seamless fallback (--no-daemon, sandbox/CI, or fork blocked).
|
|
8
|
-
const resolveClient = async () => {
|
|
9
|
-
const direct = () => createDirectClient(loadVaultsConfig().config);
|
|
10
|
-
if (daemonDisabled())
|
|
11
|
-
return direct();
|
|
12
|
-
const daemon = await ensureDaemon();
|
|
13
|
-
return daemon ?? direct();
|
|
14
|
-
};
|
|
15
|
-
const readStdin = async () => {
|
|
16
|
-
const chunks = [];
|
|
17
|
-
for await (const chunk of process.stdin)
|
|
18
|
-
chunks.push(chunk);
|
|
19
|
-
return Buffer.concat(chunks).toString('utf-8');
|
|
20
|
-
};
|
|
21
|
-
// --frontmatter must be a JSON object; a raw parser error or a non-object value is unfriendly.
|
|
22
|
-
const parseFrontmatter = (raw) => {
|
|
23
|
-
if (!raw)
|
|
24
|
-
return undefined;
|
|
25
|
-
let parsed;
|
|
26
|
-
try {
|
|
27
|
-
parsed = JSON.parse(raw);
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
31
|
-
throw new Error(`--frontmatter must be a JSON object, e.g. '{"tags":["x"]}': ${detail}`);
|
|
32
|
-
}
|
|
33
|
-
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
34
|
-
throw new Error(`--frontmatter must be a JSON object, e.g. '{"tags":["x"]}'`);
|
|
35
|
-
return parsed;
|
|
36
|
-
};
|
|
37
|
-
const emit = (json, data, human) => {
|
|
38
|
-
if (json)
|
|
39
|
-
console.log(JSON.stringify(data, null, 2));
|
|
40
|
-
else
|
|
41
|
-
human();
|
|
42
|
-
};
|
|
43
|
-
// Flatten a folder-tree to the file paths it contains, in tree order.
|
|
44
|
-
const treeFiles = (entries) => entries.flatMap((e) => (e.type === 'file' ? [e.path] : e.entries ? treeFiles(e.entries) : []));
|
|
45
|
-
export const runSearch = async (query, opts, client) => {
|
|
46
|
-
const c = client ?? (await resolveClient());
|
|
47
|
-
const out = await c.search(query, {
|
|
48
|
-
vault: opts.vault,
|
|
49
|
-
limit: opts.limit ? Number.parseInt(opts.limit, 10) : undefined,
|
|
50
|
-
});
|
|
51
|
-
emit(opts.json ?? false, out, () => {
|
|
52
|
-
if (out.results.length === 0)
|
|
53
|
-
console.log('No matches.');
|
|
54
|
-
for (const h of out.results)
|
|
55
|
-
console.log(`${h.path}\n ${chalk.gray(h.snippet)}`);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
export const runRead = async (ref, opts, client) => {
|
|
59
|
-
const c = client ?? (await resolveClient());
|
|
60
|
-
const doc = await c.read(ref, { vault: opts.vault });
|
|
61
|
-
emit(opts.json ?? false, doc, () => console.log(doc.body));
|
|
62
|
-
};
|
|
63
|
-
export const runWrite = async (ref, opts, client) => {
|
|
64
|
-
const c = client ?? (await resolveClient());
|
|
65
|
-
const inlineBody = opts.body !== undefined && opts.body !== '-';
|
|
66
|
-
if (!inlineBody && process.stdin.isTTY)
|
|
67
|
-
throw new Error('provide --body, or pipe content on stdin');
|
|
68
|
-
const body = inlineBody ? opts.body : await readStdin();
|
|
69
|
-
const frontmatter = parseFrontmatter(opts.frontmatter);
|
|
70
|
-
const out = await c.write(ref, body, { vault: opts.vault, frontmatter });
|
|
71
|
-
emit(opts.json ?? false, out, () => console.log(chalk.green(`Wrote ${out.path}`)));
|
|
72
|
-
};
|
|
73
|
-
export const runEdit = async (ref, opts, client) => {
|
|
74
|
-
const c = client ?? (await resolveClient());
|
|
75
|
-
if (opts.old === undefined && opts.body === undefined)
|
|
76
|
-
throw new Error('specify --old/--new for a replacement or --body to overwrite');
|
|
77
|
-
const op = opts.old !== undefined
|
|
78
|
-
? { mode: 'str_replace', old_str: opts.old, new_str: opts.new ?? '' }
|
|
79
|
-
: { mode: opts.append ? 'append' : 'replace', body: opts.body };
|
|
80
|
-
const out = await c.edit(ref, op, { vault: opts.vault });
|
|
81
|
-
emit(opts.json ?? false, out, () => console.log(chalk.green(`Edited ${out.path}`)));
|
|
82
|
-
};
|
|
83
|
-
export const runList = async (folder, opts, client) => {
|
|
84
|
-
const c = client ?? (await resolveClient());
|
|
85
|
-
const out = await c.list(folder, { vault: opts.vault });
|
|
86
|
-
emit(opts.json ?? false, out, () => {
|
|
87
|
-
const files = treeFiles(out.entries);
|
|
88
|
-
if (files.length === 0)
|
|
89
|
-
console.log('No documents.');
|
|
90
|
-
for (const p of files)
|
|
91
|
-
console.log(p);
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
export const runDelete = async (ref, opts, client) => {
|
|
95
|
-
const c = client ?? (await resolveClient());
|
|
96
|
-
const out = await c.delete(ref, { vault: opts.vault });
|
|
97
|
-
emit(opts.json ?? false, out, () => console.log(`Deleted ${out.path} (recoverable from git history)`));
|
|
98
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { translateEngineMessage } from '../../lib/memory/memory-client.js';
|
|
3
|
-
import { runDelete, runEdit, runList, runRead, runSearch, runWrite, } from './memory-verbs.js';
|
|
4
|
-
const guard = (fn) => fn().catch((err) => {
|
|
5
|
-
const message = translateEngineMessage(err instanceof Error ? err.message : String(err));
|
|
6
|
-
console.error(chalk.red(message));
|
|
7
|
-
process.exitCode = 1;
|
|
8
|
-
});
|
|
9
|
-
export const registerMemory = (program) => {
|
|
10
|
-
const memory = program.command('memory').description('Read + write memory, offline');
|
|
11
|
-
memory
|
|
12
|
-
.command('search <query...>')
|
|
13
|
-
.description('Search a vault (git grep)')
|
|
14
|
-
.option('--vault <name>', 'target vault')
|
|
15
|
-
.option('--limit <n>', 'max hits (default 20)')
|
|
16
|
-
.option('--json', 'machine-readable output')
|
|
17
|
-
.action((query, opts) => guard(() => runSearch(query.join(' '), opts)));
|
|
18
|
-
memory
|
|
19
|
-
.command('read <ref>')
|
|
20
|
-
.description('Print a document (@<vault>/<path> or <path> --vault)')
|
|
21
|
-
.option('--vault <name>', 'target vault')
|
|
22
|
-
.option('--json', 'machine-readable output')
|
|
23
|
-
.action((ref, opts) => guard(() => runRead(ref, opts)));
|
|
24
|
-
memory
|
|
25
|
-
.command('write <ref>')
|
|
26
|
-
.description('Create or overwrite a document (body from --body or stdin)')
|
|
27
|
-
.option('--vault <name>', 'target vault')
|
|
28
|
-
.option('--body <text>', 'document body (omit or "-" to read stdin)')
|
|
29
|
-
.option('--frontmatter <json>', 'frontmatter as a JSON object')
|
|
30
|
-
.option('--json', 'machine-readable output')
|
|
31
|
-
.action((ref, opts) => guard(() => runWrite(ref, opts)));
|
|
32
|
-
memory
|
|
33
|
-
.command('edit <ref>')
|
|
34
|
-
.description('Edit a document: str_replace (--old/--new) or --body (--append)')
|
|
35
|
-
.option('--vault <name>', 'target vault')
|
|
36
|
-
.option('--old <str>', 'exact, unique substring to replace')
|
|
37
|
-
.option('--new <str>', 'replacement (omit to delete the match)')
|
|
38
|
-
.option('--body <text>', 'replace the whole body')
|
|
39
|
-
.option('--append', 'append --body instead of replacing')
|
|
40
|
-
.option('--json', 'machine-readable output')
|
|
41
|
-
.action((ref, opts) => guard(() => runEdit(ref, opts)));
|
|
42
|
-
memory
|
|
43
|
-
.command('list [folder]')
|
|
44
|
-
.description('List documents in a vault (optionally under a folder)')
|
|
45
|
-
.option('--vault <name>', 'target vault')
|
|
46
|
-
.option('--json', 'machine-readable output')
|
|
47
|
-
.action((folder, opts) => guard(() => runList(folder, opts)));
|
|
48
|
-
memory
|
|
49
|
-
.command('delete <ref>')
|
|
50
|
-
.description('Delete a document (recoverable from git history)')
|
|
51
|
-
.option('--vault <name>', 'target vault')
|
|
52
|
-
.option('--json', 'machine-readable output')
|
|
53
|
-
.action((ref, opts) => guard(() => runDelete(ref, opts)));
|
|
54
|
-
};
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { type VaultsConfig } from '@agentage/memory-core';
|
|
2
|
-
import { type SyncResult } from '../../sync/git/cycle.js';
|
|
3
|
-
import { type SyncTarget } from '../../sync/git/planner.js';
|
|
4
|
-
export interface VaultSyncDeps {
|
|
5
|
-
loadConfig: () => VaultsConfig;
|
|
6
|
-
daemonPort: () => Promise<number | null>;
|
|
7
|
-
runViaDaemon: (port: number, vault: string) => Promise<SyncResult>;
|
|
8
|
-
runGitInProcess: (target: SyncTarget) => Promise<SyncResult>;
|
|
9
|
-
log: (msg: string) => void;
|
|
10
|
-
}
|
|
11
|
-
export declare const ACCOUNT_NO_CHANNEL = "not synced - account vaults have no sync channel";
|
|
12
|
-
export declare const runVaultSync: (name: string | undefined, deps: VaultSyncDeps) => Promise<void>;
|
|
13
|
-
export declare const defaultVaultSyncDeps: () => VaultSyncDeps;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { isAccountVault } from '@agentage/memory-core';
|
|
3
|
-
import { health, syncRun } from '../../lib/daemon/daemon-client.js';
|
|
4
|
-
import { daemonDisabled } from '../../lib/daemon/daemon-pref.js';
|
|
5
|
-
import { loadVaultsConfig } from '../../lib/vault/vaults.js';
|
|
6
|
-
import { resolvePort } from '../../daemon/lifecycle.js';
|
|
7
|
-
import { runSyncCycle } from '../../sync/git/cycle.js';
|
|
8
|
-
import { syncTargets } from '../../sync/git/planner.js';
|
|
9
|
-
import { redactRemoteUrl } from '../../sync/git/remote-url.js';
|
|
10
|
-
export const ACCOUNT_NO_CHANNEL = 'not synced - account vaults have no sync channel';
|
|
11
|
-
const describeGit = (r) => {
|
|
12
|
-
if (!r.ok)
|
|
13
|
-
return chalk.red(`failed (${r.reason ?? 'error'})${r.error ? `: ${r.error}` : ''}`);
|
|
14
|
-
if (r.skipped)
|
|
15
|
-
return chalk.yellow(`skipped (${r.skipped})`);
|
|
16
|
-
const bits = [];
|
|
17
|
-
if (r.committed)
|
|
18
|
-
bits.push('committed');
|
|
19
|
-
if (r.conflicts.length)
|
|
20
|
-
bits.push(`${r.conflicts.length} conflict copy(ies)`);
|
|
21
|
-
if (r.pushed)
|
|
22
|
-
bits.push('pushed');
|
|
23
|
-
return chalk.green(bits.length ? bits.join(', ') : 'up to date');
|
|
24
|
-
};
|
|
25
|
-
const report = (log, r) => {
|
|
26
|
-
log(`${r.vault} -> ${redactRemoteUrl(r.remote)}: ${describeGit(r)}`);
|
|
27
|
-
for (const c of r.conflicts)
|
|
28
|
-
log(` kept remote copy: ${c}`);
|
|
29
|
-
};
|
|
30
|
-
// Account vaults whose only origin is the reserved `agentage` remote: nothing syncs them. They are
|
|
31
|
-
// named, never silently skipped, so `vault sync` cannot read as "everything is up to date".
|
|
32
|
-
const unsyncableAccountVaults = (config, gitTargets) => {
|
|
33
|
-
const git = new Set(gitTargets.map((t) => t.vault));
|
|
34
|
-
return Object.entries(config.vaults ?? {})
|
|
35
|
-
.filter(([vault, entry]) => isAccountVault(entry) && !git.has(vault))
|
|
36
|
-
.map(([vault]) => vault);
|
|
37
|
-
};
|
|
38
|
-
const reportAccounts = (log, vaults) => {
|
|
39
|
-
for (const vault of vaults)
|
|
40
|
-
log(`${vault} (account): ${chalk.yellow(ACCOUNT_NO_CHANNEL)}`);
|
|
41
|
-
};
|
|
42
|
-
// `agentage vault sync [name]`: sync one vault (or every syncable vault). Git-origin vaults commit
|
|
43
|
-
// + push + pull-rebase; account (agentage) vaults have no sync channel and are reported as such.
|
|
44
|
-
// Prefers a running daemon (single writer), else runs the cycle in-process. Works for interval-0
|
|
45
|
-
// (manual-only) vaults and with the daemon down. Failures are surfaced, not thrown (V6: never a crash).
|
|
46
|
-
export const runVaultSync = async (name, deps) => {
|
|
47
|
-
const config = deps.loadConfig();
|
|
48
|
-
// A named vault that is not registered is an error (mirrors `vault remove`), not a silent no-op.
|
|
49
|
-
if (name && !(config.vaults ?? {})[name])
|
|
50
|
-
throw new Error(`vault '${name}' not found`);
|
|
51
|
-
const gitTargets = syncTargets(config).filter((t) => !name || t.vault === name);
|
|
52
|
-
const accounts = unsyncableAccountVaults(config, gitTargets).filter((v) => !name || v === name);
|
|
53
|
-
if (gitTargets.length === 0) {
|
|
54
|
-
reportAccounts(deps.log, accounts);
|
|
55
|
-
if (accounts.length === 0)
|
|
56
|
-
deps.log(name
|
|
57
|
-
? `No syncable origin configured for vault '${name}'.`
|
|
58
|
-
: 'No syncable vaults. Add one with `agentage vault add <name>`.');
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const vaults = [...new Set(gitTargets.map((t) => t.vault))];
|
|
62
|
-
deps.log(`Syncing ${vaults.length} vault(s)...`);
|
|
63
|
-
const port = await deps.daemonPort();
|
|
64
|
-
if (port !== null) {
|
|
65
|
-
for (const vault of vaults) {
|
|
66
|
-
deps.log(`${vault}...`);
|
|
67
|
-
report(deps.log, await deps.runViaDaemon(port, vault));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
for (const target of gitTargets) {
|
|
72
|
-
deps.log(`${target.vault}...`);
|
|
73
|
-
report(deps.log, await deps.runGitInProcess(target));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
reportAccounts(deps.log, accounts);
|
|
77
|
-
};
|
|
78
|
-
const resolveDaemonPort = async () => {
|
|
79
|
-
if (daemonDisabled())
|
|
80
|
-
return null;
|
|
81
|
-
const port = resolvePort();
|
|
82
|
-
return (await health(port)) ? port : null;
|
|
83
|
-
};
|
|
84
|
-
export const defaultVaultSyncDeps = () => ({
|
|
85
|
-
loadConfig: () => loadVaultsConfig().config,
|
|
86
|
-
daemonPort: resolveDaemonPort,
|
|
87
|
-
runViaDaemon: syncRun,
|
|
88
|
-
runGitInProcess: runSyncCycle,
|
|
89
|
-
log: (msg) => console.log(msg),
|
|
90
|
-
});
|