@agentage/cli 0.0.3 → 0.25.0
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/CHANGELOG.md +68 -0
- package/README.md +79 -23
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +44 -4
- package/dist/commands/{setup.d.ts → auth/setup.d.ts} +6 -3
- package/dist/commands/{setup.js → auth/setup.js} +56 -11
- package/dist/commands/daemon/daemon-cmd.d.ts +2 -0
- package/dist/commands/daemon/daemon-cmd.js +124 -0
- package/dist/commands/memory/memory-verbs.d.ts +21 -0
- package/dist/commands/memory/memory-verbs.js +98 -0
- package/dist/commands/memory/memory.d.ts +2 -0
- package/dist/commands/memory/memory.js +54 -0
- package/dist/commands/{status.d.ts → status/status.d.ts} +2 -2
- package/dist/commands/status/status.js +88 -0
- package/dist/commands/update/update.d.ts +23 -0
- package/dist/commands/update/update.js +89 -0
- package/dist/commands/vault/vault-sync.d.ts +15 -0
- package/dist/commands/vault/vault-sync.js +100 -0
- package/dist/commands/vault/vault.d.ts +22 -0
- package/dist/commands/vault/vault.js +128 -0
- package/dist/daemon/actions.d.ts +5 -0
- package/dist/daemon/actions.js +22 -0
- package/dist/daemon/client-provider.d.ts +2 -0
- package/dist/daemon/client-provider.js +16 -0
- package/dist/daemon/guards.d.ts +3 -0
- package/dist/daemon/guards.js +13 -0
- package/dist/daemon/lifecycle.d.ts +17 -0
- package/dist/daemon/lifecycle.js +151 -0
- package/dist/daemon/mcp-http.d.ts +3 -0
- package/dist/daemon/mcp-http.js +34 -0
- package/dist/daemon/server.d.ts +26 -0
- package/dist/daemon/server.js +136 -0
- package/dist/daemon-entry.d.ts +7 -0
- package/dist/daemon-entry.js +128 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/lib/auth/api.d.ts +8 -0
- package/dist/lib/auth/api.js +99 -0
- package/dist/lib/auth/auth-errors.d.ts +7 -0
- package/dist/lib/auth/auth-errors.js +22 -0
- package/dist/lib/{callback-server.d.ts → auth/callback-server.d.ts} +0 -1
- package/dist/lib/{callback-server.js → auth/callback-server.js} +2 -2
- package/dist/lib/auth/credentials.d.ts +12 -0
- package/dist/lib/auth/credentials.js +50 -0
- package/dist/lib/auth/env-match.d.ts +9 -0
- package/dist/lib/auth/env-match.js +17 -0
- package/dist/lib/auth/introspect.d.ts +7 -0
- package/dist/lib/auth/introspect.js +89 -0
- package/dist/lib/{oauth.d.ts → auth/oauth.d.ts} +6 -2
- package/dist/lib/{oauth.js → auth/oauth.js} +26 -7
- package/dist/lib/auth/provision.d.ts +14 -0
- package/dist/lib/auth/provision.js +71 -0
- package/dist/lib/daemon/daemon-client.d.ts +39 -0
- package/dist/lib/daemon/daemon-client.js +134 -0
- package/dist/lib/daemon/daemon-pref.d.ts +2 -0
- package/dist/lib/daemon/daemon-pref.js +10 -0
- package/dist/lib/{config.d.ts → fs/config.d.ts} +2 -1
- package/dist/lib/fs/config.js +55 -0
- package/dist/lib/fs/file-lock.d.ts +3 -0
- package/dist/lib/fs/file-lock.js +163 -0
- package/dist/lib/memory/memory-client.d.ts +30 -0
- package/dist/lib/memory/memory-client.js +98 -0
- package/dist/lib/net/http.d.ts +6 -0
- package/dist/lib/net/http.js +32 -0
- package/dist/lib/{origins.d.ts → net/origins.d.ts} +1 -1
- package/dist/lib/net/origins.js +39 -0
- package/dist/lib/net/user-agent.d.ts +6 -0
- package/dist/lib/net/user-agent.js +7 -0
- package/dist/lib/status/format.d.ts +1 -0
- package/dist/lib/status/format.js +12 -0
- package/dist/lib/status/status-info.d.ts +46 -0
- package/dist/lib/status/status-info.js +109 -0
- package/dist/lib/status/vaults-format.d.ts +2 -0
- package/dist/lib/status/vaults-format.js +44 -0
- package/dist/lib/status/vaults-status.d.ts +12 -0
- package/dist/lib/status/vaults-status.js +53 -0
- package/dist/lib/update/update-cache.d.ts +14 -0
- package/dist/lib/update/update-cache.js +63 -0
- package/dist/lib/update/update-check.d.ts +27 -0
- package/dist/lib/update/update-check.js +50 -0
- package/dist/lib/update/update-lock.d.ts +2 -0
- package/dist/lib/update/update-lock.js +109 -0
- package/dist/lib/vault/vault-registry.d.ts +12 -0
- package/dist/lib/vault/vault-registry.js +82 -0
- package/dist/lib/vault/vaults.d.ts +10 -0
- package/dist/lib/vault/vaults.js +66 -0
- package/dist/lib/vault/vaults.schema.d.ts +2 -0
- package/dist/lib/vault/vaults.schema.js +10 -0
- package/dist/mcp/local-server.d.ts +4 -0
- package/dist/mcp/local-server.js +26 -0
- package/dist/sync/couch/cycle.d.ts +2 -0
- package/dist/sync/couch/cycle.js +58 -0
- package/dist/sync/couch/discovery.d.ts +22 -0
- package/dist/sync/couch/discovery.js +34 -0
- package/dist/sync/couch/file-store.d.ts +2 -0
- package/dist/sync/couch/file-store.js +47 -0
- package/dist/sync/couch/local-commit.d.ts +2 -0
- package/dist/sync/couch/local-commit.js +24 -0
- package/dist/sync/couch/manager.d.ts +4 -0
- package/dist/sync/couch/manager.fixtures.d.ts +20 -0
- package/dist/sync/couch/manager.fixtures.js +56 -0
- package/dist/sync/couch/manager.js +126 -0
- package/dist/sync/couch/manager.types.d.ts +81 -0
- package/dist/sync/couch/manager.types.js +1 -0
- package/dist/sync/couch/mutation-target.d.ts +5 -0
- package/dist/sync/couch/mutation-target.js +33 -0
- package/dist/sync/couch/push-on-write.d.ts +3 -0
- package/dist/sync/couch/push-on-write.js +33 -0
- package/dist/sync/couch/state-store.d.ts +3 -0
- package/dist/sync/couch/state-store.js +28 -0
- package/dist/sync/couch/targets.d.ts +9 -0
- package/dist/sync/couch/targets.js +23 -0
- package/dist/sync/couch/wire.d.ts +6 -0
- package/dist/sync/couch/wire.js +16 -0
- package/dist/sync/discover/watcher.d.ts +26 -0
- package/dist/sync/discover/watcher.js +159 -0
- package/dist/sync/git/conflict.d.ts +1 -0
- package/dist/sync/git/conflict.js +16 -0
- package/dist/sync/git/cycle.d.ts +18 -0
- package/dist/sync/git/cycle.js +158 -0
- package/dist/sync/git/git-exec.d.ts +22 -0
- package/dist/sync/git/git-exec.js +56 -0
- package/dist/sync/git/manager.d.ts +30 -0
- package/dist/sync/git/manager.js +114 -0
- package/dist/sync/git/planner.d.ts +15 -0
- package/dist/sync/git/planner.js +46 -0
- package/dist/sync/git/remote-url.d.ts +3 -0
- package/dist/sync/git/remote-url.js +30 -0
- package/dist/utils/version.d.ts +0 -1
- package/dist/utils/version.js +0 -1
- package/package.json +20 -7
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/setup.d.ts.map +0 -1
- package/dist/commands/setup.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -36
- package/dist/commands/status.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/api.d.ts +0 -12
- package/dist/lib/api.d.ts.map +0 -1
- package/dist/lib/api.js +0 -46
- package/dist/lib/api.js.map +0 -1
- package/dist/lib/callback-server.d.ts.map +0 -1
- package/dist/lib/callback-server.js.map +0 -1
- package/dist/lib/config.d.ts.map +0 -1
- package/dist/lib/config.js +0 -34
- package/dist/lib/config.js.map +0 -1
- package/dist/lib/oauth.d.ts.map +0 -1
- package/dist/lib/oauth.js.map +0 -1
- package/dist/lib/origins.d.ts.map +0 -1
- package/dist/lib/origins.js +0 -26
- package/dist/lib/origins.js.map +0 -1
- package/dist/lib/status-info.d.ts +0 -18
- package/dist/lib/status-info.d.ts.map +0 -1
- package/dist/lib/status-info.js +0 -39
- package/dist/lib/status-info.js.map +0 -1
- package/dist/utils/version.d.ts.map +0 -1
- package/dist/utils/version.js.map +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
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,8 +1,8 @@
|
|
|
1
1
|
import { type Command } from 'commander';
|
|
2
|
-
import { type StatusReport } from '
|
|
2
|
+
import { type StatusReport } from '../../lib/status/status-info.js';
|
|
3
3
|
export declare const printStatus: (report: StatusReport) => void;
|
|
4
4
|
export declare const runStatus: (opts?: {
|
|
5
5
|
json?: boolean;
|
|
6
|
+
token?: string;
|
|
6
7
|
}) => Promise<void>;
|
|
7
8
|
export declare const registerStatus: (program: Command) => void;
|
|
8
|
-
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { resolveAuth } from '../../lib/auth/credentials.js';
|
|
3
|
+
import { siteFqdn } from '../../lib/net/origins.js';
|
|
4
|
+
import { formatUptime } from '../../lib/status/format.js';
|
|
5
|
+
import { gatherStatus, } from '../../lib/status/status-info.js';
|
|
6
|
+
import { vaultLines } from '../../lib/status/vaults-format.js';
|
|
7
|
+
import { INSTALL_HINT } from '../../lib/update/update-check.js';
|
|
8
|
+
const mark = (good) => (good ? chalk.green('✓') : chalk.red('✗'));
|
|
9
|
+
const row = (label, value) => {
|
|
10
|
+
console.log(`${label.padEnd(10)} ${value}`);
|
|
11
|
+
};
|
|
12
|
+
// The signed-in line never shows an absolute expiry: it is the short-lived, auto-refreshed
|
|
13
|
+
// access-token expiry, which misreads as "yesterday" near midnight in positive-UTC zones.
|
|
14
|
+
// Introspection already proved the session is active server-side.
|
|
15
|
+
const authLine = (auth) => {
|
|
16
|
+
// Env mismatch: the credential is valid but for another target - neutral `!`, not the expired ✗.
|
|
17
|
+
if (auth.mismatch)
|
|
18
|
+
return `${chalk.yellow('!')} ${auth.note ?? 'signed in to another environment'}`;
|
|
19
|
+
const via = auth.pat ? ' via token' : '';
|
|
20
|
+
if (!auth.signedIn)
|
|
21
|
+
return `${mark(false)} ${auth.note ?? 'not signed in'}`;
|
|
22
|
+
// Transient: we hold a valid-looking token but could not re-verify - a non-terminal `~`, never ✗.
|
|
23
|
+
if (auth.transient)
|
|
24
|
+
return `${chalk.yellow('~')} ${auth.note ?? 'signed in'}${via}`;
|
|
25
|
+
return `${mark(true)} signed in${via} (session active)`;
|
|
26
|
+
};
|
|
27
|
+
const updateLine = (update) => {
|
|
28
|
+
switch (update.status.kind) {
|
|
29
|
+
case 'current':
|
|
30
|
+
return `${mark(true)} up to date`;
|
|
31
|
+
case 'update-available':
|
|
32
|
+
return chalk.yellow(`↑ ${update.status.latest} available - ${INSTALL_HINT}`);
|
|
33
|
+
case 'unsupported':
|
|
34
|
+
return chalk.red(`${mark(false)} unsupported, update required - ${INSTALL_HINT}`);
|
|
35
|
+
case 'unknown':
|
|
36
|
+
return chalk.dim('- update check unavailable');
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const daemonLine = (d, cliVersion) => {
|
|
40
|
+
if (!d.running)
|
|
41
|
+
return `${mark(false)} stopped - run: agentage daemon start`;
|
|
42
|
+
const up = d.uptimeSeconds !== undefined ? `, up ${formatUptime(d.uptimeSeconds)}` : '';
|
|
43
|
+
const stale = d.daemonVersion && d.daemonVersion !== cliVersion
|
|
44
|
+
? chalk.yellow(` (version ${d.daemonVersion} != cli ${cliVersion})`)
|
|
45
|
+
: '';
|
|
46
|
+
return `${mark(true)} running (pid ${d.pid ?? '?'}, port ${d.port}${up})${stale}`;
|
|
47
|
+
};
|
|
48
|
+
const mcpLine = (d) => d.mcp ? `${mark(true)} serving at http://127.0.0.1:${d.port}/mcp` : `${mark(false)} off`;
|
|
49
|
+
// Daemon rows honor version-mismatch inline (appended to the daemon row) and print mcp only when
|
|
50
|
+
// running; the per-vault sync breakdown now lives in its own `vaults` block (printStatus).
|
|
51
|
+
const printDaemon = (d, cliVersion) => {
|
|
52
|
+
row('daemon', daemonLine(d, cliVersion));
|
|
53
|
+
if (!d.running)
|
|
54
|
+
return;
|
|
55
|
+
row('mcp', mcpLine(d));
|
|
56
|
+
};
|
|
57
|
+
export const printStatus = (report) => {
|
|
58
|
+
row('version', report.version);
|
|
59
|
+
row('update', updateLine(report.update));
|
|
60
|
+
const t = report.target;
|
|
61
|
+
const targetSuffix = t.reachable ? '' : ' - unreachable';
|
|
62
|
+
row('target', `${mark(t.reachable)} ${t.fqdn} (${t.env})${targetSuffix}`);
|
|
63
|
+
row('auth', authLine(report.auth));
|
|
64
|
+
row('endpoint', `${mark(report.endpoint.reachable)} ${report.endpoint.url} ` +
|
|
65
|
+
(report.endpoint.reachable ? 'reachable' : 'unreachable'));
|
|
66
|
+
if (report.daemon)
|
|
67
|
+
printDaemon(report.daemon, report.version);
|
|
68
|
+
for (const line of vaultLines(report.vaults))
|
|
69
|
+
console.log(line);
|
|
70
|
+
if (report.update.message)
|
|
71
|
+
console.log(chalk.yellow(`\n${report.update.message}`));
|
|
72
|
+
};
|
|
73
|
+
export const runStatus = async (opts = {}) => {
|
|
74
|
+
const report = await gatherStatus(resolveAuth({ token: opts.token }), siteFqdn());
|
|
75
|
+
if (opts.json) {
|
|
76
|
+
console.log(JSON.stringify(report, null, 2));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
printStatus(report);
|
|
80
|
+
};
|
|
81
|
+
export const registerStatus = (program) => {
|
|
82
|
+
program
|
|
83
|
+
.command('status')
|
|
84
|
+
.description('Show CLI, account, and endpoint status')
|
|
85
|
+
.option('--json', 'machine-readable output')
|
|
86
|
+
.option('--token <token>', 'authenticate with a personal access token (aga_...); or set AGENTAGE_TOKEN')
|
|
87
|
+
.action(runStatus);
|
|
88
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Command } from 'commander';
|
|
2
|
+
import { type SpawnOutcome } from '../../lib/daemon/daemon-client.js';
|
|
3
|
+
import { type UpdateInfo } from '../../lib/update/update-check.js';
|
|
4
|
+
export type RestartOutcome = 'restarted' | 'failed' | 'not-running';
|
|
5
|
+
export interface RestartDeps {
|
|
6
|
+
running?: () => boolean;
|
|
7
|
+
stop?: () => Promise<boolean>;
|
|
8
|
+
start?: (port: number) => Promise<SpawnOutcome>;
|
|
9
|
+
}
|
|
10
|
+
export declare const restartDaemonIfRunning: (deps?: RestartDeps) => Promise<RestartOutcome>;
|
|
11
|
+
export interface UpdateDeps {
|
|
12
|
+
check: (installed: string) => Promise<UpdateInfo>;
|
|
13
|
+
install: () => Promise<void>;
|
|
14
|
+
restartDaemon: () => Promise<RestartOutcome>;
|
|
15
|
+
acquireLock: () => boolean;
|
|
16
|
+
releaseLock: () => void;
|
|
17
|
+
log: (msg: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface UpdateOptions {
|
|
20
|
+
check?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare const runUpdate: (opts: UpdateOptions, deps?: UpdateDeps) => Promise<void>;
|
|
23
|
+
export declare const registerUpdate: (program: Command) => void;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { isDaemonRunning, resolvePort, stopDaemonAndWait } from '../../daemon/lifecycle.js';
|
|
5
|
+
import { spawnDaemon } from '../../lib/daemon/daemon-client.js';
|
|
6
|
+
import { checkForUpdate, INSTALL_HINT } from '../../lib/update/update-check.js';
|
|
7
|
+
import { acquireUpdateLock, releaseUpdateLock } from '../../lib/update/update-lock.js';
|
|
8
|
+
import { VERSION } from '../../utils/version.js';
|
|
9
|
+
const pexec = promisify(execFile);
|
|
10
|
+
// Restart a running daemon so it picks up the freshly installed binary; a stopped daemon is left
|
|
11
|
+
// stopped. Waits for the old process to exit (port free) before spawning, and reports honestly
|
|
12
|
+
// when the new daemon did not come up.
|
|
13
|
+
export const restartDaemonIfRunning = async (deps = {}) => {
|
|
14
|
+
const running = deps.running ?? isDaemonRunning;
|
|
15
|
+
if (!running())
|
|
16
|
+
return 'not-running';
|
|
17
|
+
await (deps.stop ?? stopDaemonAndWait)();
|
|
18
|
+
const up = await (deps.start ?? spawnDaemon)(resolvePort());
|
|
19
|
+
return up.ok ? 'restarted' : 'failed';
|
|
20
|
+
};
|
|
21
|
+
const defaultDeps = {
|
|
22
|
+
check: checkForUpdate,
|
|
23
|
+
install: async () => {
|
|
24
|
+
await pexec('npm', ['install', '-g', '@agentage/cli@latest']);
|
|
25
|
+
},
|
|
26
|
+
restartDaemon: () => restartDaemonIfRunning(),
|
|
27
|
+
acquireLock: () => acquireUpdateLock(),
|
|
28
|
+
releaseLock: releaseUpdateLock,
|
|
29
|
+
log: (msg) => console.log(msg),
|
|
30
|
+
};
|
|
31
|
+
const describe = (info) => {
|
|
32
|
+
const s = info.status;
|
|
33
|
+
switch (s.kind) {
|
|
34
|
+
case 'current':
|
|
35
|
+
return chalk.green(`Already on the latest version (${VERSION}).`);
|
|
36
|
+
case 'update-available':
|
|
37
|
+
return chalk.yellow(`Update available: ${VERSION} -> ${s.latest}.`);
|
|
38
|
+
case 'unsupported':
|
|
39
|
+
return chalk.red(`Unsupported version ${VERSION} - update required (latest ${s.latest ?? '?'}).`);
|
|
40
|
+
case 'unknown':
|
|
41
|
+
return chalk.yellow(`Couldn't reach the registry - try again later. ${INSTALL_HINT}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Install, then restart a running daemon so its in-process engine runs the new version.
|
|
45
|
+
const install = async (deps) => {
|
|
46
|
+
deps.log('Installing the latest @agentage/cli...');
|
|
47
|
+
await deps.install();
|
|
48
|
+
deps.log(chalk.green('Updated. Run `agentage status` to confirm.'));
|
|
49
|
+
const outcome = await deps.restartDaemon();
|
|
50
|
+
if (outcome === 'restarted')
|
|
51
|
+
deps.log(chalk.green('Restarted the daemon on the new version.'));
|
|
52
|
+
if (outcome === 'failed')
|
|
53
|
+
deps.log(chalk.yellow('Daemon did not restart cleanly - run `agentage daemon start`.'));
|
|
54
|
+
};
|
|
55
|
+
// --check reports the verdict and never installs. Otherwise, install only when the registry says
|
|
56
|
+
// we're behind (available/unsupported), guarded by a single-writer lock; current/unreachable just
|
|
57
|
+
// report.
|
|
58
|
+
export const runUpdate = async (opts, deps = defaultDeps) => {
|
|
59
|
+
const info = await deps.check(VERSION);
|
|
60
|
+
deps.log(describe(info));
|
|
61
|
+
const behind = info.status.kind === 'update-available' || info.status.kind === 'unsupported';
|
|
62
|
+
if (opts.check || !behind)
|
|
63
|
+
return;
|
|
64
|
+
if (!deps.acquireLock()) {
|
|
65
|
+
deps.log(chalk.yellow('Another update is already in progress; skipping.'));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
await install(deps);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
deps.releaseLock();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
export const registerUpdate = (program) => {
|
|
76
|
+
program
|
|
77
|
+
.command('update')
|
|
78
|
+
.description('Update @agentage/cli to the latest published version')
|
|
79
|
+
.option('--check', 'report whether an update is available, without installing')
|
|
80
|
+
.action(async (opts) => {
|
|
81
|
+
try {
|
|
82
|
+
await runUpdate(opts);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type VaultsConfig } from '@agentage/memory-core';
|
|
2
|
+
import { type SyncRunResult } from '../../lib/daemon/daemon-client.js';
|
|
3
|
+
import { type SyncResult } from '../../sync/git/cycle.js';
|
|
4
|
+
import { type CouchSyncResult } from '../../sync/couch/manager.js';
|
|
5
|
+
import { type SyncTarget } from '../../sync/git/planner.js';
|
|
6
|
+
export interface VaultSyncDeps {
|
|
7
|
+
loadConfig: () => VaultsConfig;
|
|
8
|
+
daemonPort: () => Promise<number | null>;
|
|
9
|
+
runViaDaemon: (port: number, vault: string) => Promise<SyncRunResult>;
|
|
10
|
+
runGitInProcess: (target: SyncTarget) => Promise<SyncResult>;
|
|
11
|
+
runCouchInProcess: (vault: string) => Promise<CouchSyncResult>;
|
|
12
|
+
log: (msg: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare const runVaultSync: (name: string | undefined, deps: VaultSyncDeps) => Promise<void>;
|
|
15
|
+
export declare const defaultVaultSyncDeps: () => VaultSyncDeps;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { health, syncRun } from '../../lib/daemon/daemon-client.js';
|
|
3
|
+
import { daemonDisabled } from '../../lib/daemon/daemon-pref.js';
|
|
4
|
+
import { loadVaultsConfig } from '../../lib/vault/vaults.js';
|
|
5
|
+
import { resolvePort } from '../../daemon/lifecycle.js';
|
|
6
|
+
import { runSyncCycle } from '../../sync/git/cycle.js';
|
|
7
|
+
import { createCouchSyncManager } from '../../sync/couch/manager.js';
|
|
8
|
+
import { couchTargets } from '../../sync/couch/targets.js';
|
|
9
|
+
import { syncTargets } from '../../sync/git/planner.js';
|
|
10
|
+
import { redactRemoteUrl } from '../../sync/git/remote-url.js';
|
|
11
|
+
const isCouch = (r) => 'channel' in r && r.channel === 'couch';
|
|
12
|
+
const describeGit = (r) => {
|
|
13
|
+
if (!r.ok)
|
|
14
|
+
return chalk.red(`failed (${r.reason ?? 'error'})${r.error ? `: ${r.error}` : ''}`);
|
|
15
|
+
if (r.skipped)
|
|
16
|
+
return chalk.yellow(`skipped (${r.skipped})`);
|
|
17
|
+
const bits = [];
|
|
18
|
+
if (r.committed)
|
|
19
|
+
bits.push('committed');
|
|
20
|
+
if (r.conflicts.length)
|
|
21
|
+
bits.push(`${r.conflicts.length} conflict copy(ies)`);
|
|
22
|
+
if (r.pushed)
|
|
23
|
+
bits.push('pushed');
|
|
24
|
+
return chalk.green(bits.length ? bits.join(', ') : 'up to date');
|
|
25
|
+
};
|
|
26
|
+
const describeCouch = (r) => {
|
|
27
|
+
if (r.paused)
|
|
28
|
+
return chalk.yellow(`paused (${r.paused})`);
|
|
29
|
+
if (!r.ok)
|
|
30
|
+
return chalk.red(`failed${r.error ? `: ${r.error}` : ''}`);
|
|
31
|
+
const bits = [];
|
|
32
|
+
if (r.committed)
|
|
33
|
+
bits.push('committed');
|
|
34
|
+
if (r.pulled)
|
|
35
|
+
bits.push('pulled');
|
|
36
|
+
if (r.pendingCount)
|
|
37
|
+
bits.push(`${r.pendingCount} pending`);
|
|
38
|
+
return chalk.green(bits.length ? bits.join(', ') : 'up to date');
|
|
39
|
+
};
|
|
40
|
+
const report = (log, r) => {
|
|
41
|
+
if (isCouch(r)) {
|
|
42
|
+
log(`${r.vault} (account): ${describeCouch(r)}`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
log(`${r.vault} -> ${redactRemoteUrl(r.remote)}: ${describeGit(r)}`);
|
|
46
|
+
for (const c of r.conflicts)
|
|
47
|
+
log(` kept remote copy: ${c}`);
|
|
48
|
+
};
|
|
49
|
+
// `agentage vault sync [name]`: sync one vault (or every syncable vault). Git-origin vaults
|
|
50
|
+
// commit + push + pull-rebase; account (agentage) vaults sync the couch channel. Prefers a running
|
|
51
|
+
// daemon (single writer), else runs the cycle in-process. Works for interval-0 (manual-only) vaults
|
|
52
|
+
// and with the daemon down. Failures are surfaced, not thrown (V6: never a crash).
|
|
53
|
+
export const runVaultSync = async (name, deps) => {
|
|
54
|
+
const config = deps.loadConfig();
|
|
55
|
+
// A named vault that is not registered is an error (mirrors `vault remove`), not a silent no-op.
|
|
56
|
+
if (name && !(config.vaults ?? {})[name])
|
|
57
|
+
throw new Error(`vault '${name}' not found`);
|
|
58
|
+
const gitTargets = syncTargets(config).filter((t) => !name || t.vault === name);
|
|
59
|
+
const couchVaults = couchTargets(config)
|
|
60
|
+
.filter((t) => !name || t.vault === name)
|
|
61
|
+
.map((t) => t.vault);
|
|
62
|
+
if (gitTargets.length === 0 && couchVaults.length === 0) {
|
|
63
|
+
deps.log(name
|
|
64
|
+
? `No syncable origin configured for vault '${name}'.`
|
|
65
|
+
: 'No syncable vaults. Add one with `agentage vault add <name>`.');
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const vaults = [...new Set([...gitTargets.map((t) => t.vault), ...couchVaults])];
|
|
69
|
+
deps.log(`Syncing ${vaults.length} vault(s)...`);
|
|
70
|
+
const port = await deps.daemonPort();
|
|
71
|
+
if (port !== null) {
|
|
72
|
+
for (const vault of vaults) {
|
|
73
|
+
deps.log(`${vault}...`);
|
|
74
|
+
report(deps.log, await deps.runViaDaemon(port, vault));
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
for (const target of gitTargets) {
|
|
79
|
+
deps.log(`${target.vault}...`);
|
|
80
|
+
report(deps.log, await deps.runGitInProcess(target));
|
|
81
|
+
}
|
|
82
|
+
for (const vault of couchVaults) {
|
|
83
|
+
deps.log(`${vault}...`);
|
|
84
|
+
report(deps.log, await deps.runCouchInProcess(vault));
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const resolveDaemonPort = async () => {
|
|
88
|
+
if (daemonDisabled())
|
|
89
|
+
return null;
|
|
90
|
+
const port = resolvePort();
|
|
91
|
+
return (await health(port)) ? port : null;
|
|
92
|
+
};
|
|
93
|
+
export const defaultVaultSyncDeps = () => ({
|
|
94
|
+
loadConfig: () => loadVaultsConfig().config,
|
|
95
|
+
daemonPort: resolveDaemonPort,
|
|
96
|
+
runViaDaemon: syncRun,
|
|
97
|
+
runGitInProcess: runSyncCycle,
|
|
98
|
+
runCouchInProcess: (vault) => createCouchSyncManager().runNow(vault),
|
|
99
|
+
log: (msg) => console.log(msg),
|
|
100
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type Command } from 'commander';
|
|
2
|
+
import { type VaultsConfig } from '@agentage/memory-core';
|
|
3
|
+
import { type ProvisionResult } from '../../lib/auth/provision.js';
|
|
4
|
+
import { type LoadedVaults } from '../../lib/vault/vaults.js';
|
|
5
|
+
export interface VaultDeps {
|
|
6
|
+
load: () => LoadedVaults;
|
|
7
|
+
mutate: (fn: (config: VaultsConfig) => VaultsConfig | null | void) => Promise<VaultsConfig>;
|
|
8
|
+
ensureDir: (path: string) => void;
|
|
9
|
+
provision: (name: string) => Promise<ProvisionResult>;
|
|
10
|
+
log: (msg: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface VaultAddOptions {
|
|
13
|
+
local?: string | boolean;
|
|
14
|
+
git?: string;
|
|
15
|
+
path?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const runVaultAdd: (name: string, opts: VaultAddOptions, deps?: VaultDeps) => Promise<void>;
|
|
18
|
+
export declare const runVaultRemove: (name: string, deps?: VaultDeps) => Promise<void>;
|
|
19
|
+
export declare const runVaultList: (opts: {
|
|
20
|
+
json?: boolean;
|
|
21
|
+
}, deps?: VaultDeps) => void;
|
|
22
|
+
export declare const registerVault: (program: Command) => void;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { isAccountVault } from '@agentage/memory-core';
|
|
3
|
+
import { addVault, appendDiscoverIgnore, ensureVaultDir, formatVaultLine, redactEntry, removeVault, vaultType, } from '../../lib/vault/vault-registry.js';
|
|
4
|
+
import { defaultProvisionDeps, provisionAccountVault, } from '../../lib/auth/provision.js';
|
|
5
|
+
import { loadVaultsConfig, mutateVaultsConfig } from '../../lib/vault/vaults.js';
|
|
6
|
+
import { assertSafeRemoteUrl, redactRemoteUrl } from '../../sync/git/remote-url.js';
|
|
7
|
+
import { defaultVaultSyncDeps, runVaultSync } from './vault-sync.js';
|
|
8
|
+
const defaultDeps = {
|
|
9
|
+
load: loadVaultsConfig,
|
|
10
|
+
mutate: mutateVaultsConfig,
|
|
11
|
+
ensureDir: ensureVaultDir,
|
|
12
|
+
provision: (name) => provisionAccountVault(name, defaultProvisionDeps()),
|
|
13
|
+
log: (msg) => console.log(msg),
|
|
14
|
+
};
|
|
15
|
+
const buildEntry = (name, opts) => {
|
|
16
|
+
const hasLocal = opts.local !== undefined;
|
|
17
|
+
if (hasLocal && opts.git)
|
|
18
|
+
throw new Error('choose one of --local or --git, not both');
|
|
19
|
+
if (opts.path !== undefined && (hasLocal || opts.git))
|
|
20
|
+
throw new Error('--path applies only to an account vault (drop --local and --git)');
|
|
21
|
+
// A --git vault is a local working copy that syncs to an external git remote (path + origin);
|
|
22
|
+
// the daemon commits/pushes and pulls it per its interval.
|
|
23
|
+
if (opts.git) {
|
|
24
|
+
assertSafeRemoteUrl(opts.git);
|
|
25
|
+
return { path: `~/vaults/${name}`, origin: [{ remote: opts.git }], mcp: ['local'] };
|
|
26
|
+
}
|
|
27
|
+
if (hasLocal) {
|
|
28
|
+
const path = typeof opts.local === 'string' ? opts.local : `~/vaults/${name}`;
|
|
29
|
+
return { path, mcp: ['local'] };
|
|
30
|
+
}
|
|
31
|
+
// No --local/--git: an account vault - a local mirror synced to the account (agentage) channel.
|
|
32
|
+
return { path: opts.path ?? `~/vaults/${name}`, origin: [{ remote: 'agentage' }] };
|
|
33
|
+
};
|
|
34
|
+
export const runVaultAdd = async (name, opts, deps = defaultDeps) => {
|
|
35
|
+
const entry = buildEntry(name, opts);
|
|
36
|
+
// The dup check + save run together under the lock, against the FRESH on-disk config.
|
|
37
|
+
await deps.mutate((config) => addVault(config, name, entry));
|
|
38
|
+
if (entry.path)
|
|
39
|
+
deps.ensureDir(entry.path);
|
|
40
|
+
const kind = vaultType(entry);
|
|
41
|
+
const where = entry.path ?? entry.origin?.[0]?.remote ?? '';
|
|
42
|
+
const via = kind === 'git' && entry.origin?.length ? ` <- ${redactRemoteUrl(entry.origin[0].remote)}` : '';
|
|
43
|
+
deps.log(chalk.green(`Added vault '${name}' (${kind}) -> ${where}${via}`));
|
|
44
|
+
// Offline-first: the local entry is saved first; provisioning the account channel is never fatal.
|
|
45
|
+
if (isAccountVault(entry))
|
|
46
|
+
deps.log((await deps.provision(name)).message);
|
|
47
|
+
};
|
|
48
|
+
export const runVaultRemove = async (name, deps = defaultDeps) => {
|
|
49
|
+
let wasDefault = false;
|
|
50
|
+
let ignoredRoot = null;
|
|
51
|
+
// The removal and the discover-ignore append run as one locked read-modify-write, against the
|
|
52
|
+
// FRESH on-disk config, else a concurrent writer's update is lost or the next scan re-adds the folder.
|
|
53
|
+
const next = await deps.mutate((config) => {
|
|
54
|
+
wasDefault = config.default === name;
|
|
55
|
+
const path = config.vaults?.[name]?.path;
|
|
56
|
+
let updated = removeVault(config, name);
|
|
57
|
+
const ignored = path ? appendDiscoverIgnore(updated, name, path) : null;
|
|
58
|
+
if (ignored) {
|
|
59
|
+
updated = ignored.config;
|
|
60
|
+
ignoredRoot = ignored.root;
|
|
61
|
+
}
|
|
62
|
+
return updated;
|
|
63
|
+
});
|
|
64
|
+
deps.log(`Removed vault '${name}' (files left on disk).`);
|
|
65
|
+
if (ignoredRoot)
|
|
66
|
+
deps.log(`Added '${name}' to ${ignoredRoot} ignore so it is not re-discovered.`);
|
|
67
|
+
if (wasDefault && next.default)
|
|
68
|
+
deps.log(`Default vault is now '${next.default}'.`);
|
|
69
|
+
};
|
|
70
|
+
export const runVaultList = (opts, deps = defaultDeps) => {
|
|
71
|
+
const { config } = deps.load();
|
|
72
|
+
const vaults = config.vaults ?? {};
|
|
73
|
+
const names = Object.keys(vaults);
|
|
74
|
+
if (opts.json) {
|
|
75
|
+
// Backward-compatible: still the name-keyed map, each entry annotated with its honest type.
|
|
76
|
+
// Origin remotes are redacted so a credentialed URL never leaks into machine output.
|
|
77
|
+
const out = Object.fromEntries(names.map((n) => [n, { ...redactEntry(vaults[n]), type: vaultType(vaults[n]) }]));
|
|
78
|
+
deps.log(JSON.stringify(out, null, 2));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (names.length === 0) {
|
|
82
|
+
deps.log('No vaults registered. Add one with `agentage vault add <name> --local`.');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
for (const name of names) {
|
|
86
|
+
const suffix = name === config.default ? ' (default)' : '';
|
|
87
|
+
deps.log(formatVaultLine(name, vaults[name]) + suffix);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const guard = (fn) => {
|
|
91
|
+
try {
|
|
92
|
+
fn();
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const guardAsync = (fn) => fn().catch((err) => {
|
|
100
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
});
|
|
103
|
+
export const registerVault = (program) => {
|
|
104
|
+
const vault = program.command('vault').description('Manage local memory vaults');
|
|
105
|
+
vault
|
|
106
|
+
.command('list')
|
|
107
|
+
.description('List registered vaults')
|
|
108
|
+
.option('--json', 'machine-readable output')
|
|
109
|
+
.action((opts) => guard(() => runVaultList(opts)));
|
|
110
|
+
vault
|
|
111
|
+
.command('add <name>')
|
|
112
|
+
.description('Register a vault (account by default; --local or --git for a self-hosted one)')
|
|
113
|
+
.option('--local [path]', 'a local folder (default ~/vaults/<name>)')
|
|
114
|
+
.option('--git <remote>', 'a vault synced to an external git remote')
|
|
115
|
+
.option('--path <dir>', 'account vault local mirror dir (default ~/vaults/<name>)')
|
|
116
|
+
.action((name, opts) => guardAsync(() => runVaultAdd(name, opts)));
|
|
117
|
+
vault
|
|
118
|
+
.command('remove <name>')
|
|
119
|
+
.description('Unregister a vault (files stay on disk)')
|
|
120
|
+
.action((name) => guardAsync(() => runVaultRemove(name)));
|
|
121
|
+
vault
|
|
122
|
+
.command('sync [name]')
|
|
123
|
+
.description('Sync vaults now (git commit/push/pull, or the account channel)')
|
|
124
|
+
.action((name) => runVaultSync(name, defaultVaultSyncDeps()).catch((err) => {
|
|
125
|
+
console.error(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
126
|
+
process.exitCode = 1;
|
|
127
|
+
}));
|
|
128
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type MemoryClient } from '../lib/memory/memory-client.js';
|
|
2
|
+
export declare const MEMORY_VERBS: readonly ["search", "read", "write", "edit", "list", "delete"];
|
|
3
|
+
export type MemoryVerb = (typeof MEMORY_VERBS)[number];
|
|
4
|
+
export declare const isMemoryVerb: (v: string) => v is MemoryVerb;
|
|
5
|
+
export declare const dispatchMemory: (client: MemoryClient, verb: MemoryVerb, body: unknown) => Promise<unknown>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export const MEMORY_VERBS = ['search', 'read', 'write', 'edit', 'list', 'delete'];
|
|
2
|
+
export const isMemoryVerb = (v) => MEMORY_VERBS.includes(v);
|
|
3
|
+
// Map one wire payload to the matching MemoryClient call. The daemon and the CLI share this verb
|
|
4
|
+
// set so a daemon request runs the exact method a DirectClient would run in-process (DO2).
|
|
5
|
+
export const dispatchMemory = (client, verb, body) => {
|
|
6
|
+
const p = (body ?? {});
|
|
7
|
+
switch (verb) {
|
|
8
|
+
case 'search':
|
|
9
|
+
return client.search(p['query'], p['opts']);
|
|
10
|
+
case 'read':
|
|
11
|
+
return client.read(p['ref'], p['opts']);
|
|
12
|
+
case 'write':
|
|
13
|
+
return client.write(p['ref'], p['body'], p['opts']);
|
|
14
|
+
case 'edit':
|
|
15
|
+
return client.edit(p['ref'], p['op'], p['opts']);
|
|
16
|
+
case 'list':
|
|
17
|
+
return client.list(p['folder'], p['opts']);
|
|
18
|
+
case 'delete':
|
|
19
|
+
return client.delete(p['ref'], p['opts']);
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`unknown verb: ${verb}`);
|
|
22
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { existsSync, statSync } from 'node:fs';
|
|
2
|
+
import { createDirectClient } from '../lib/memory/memory-client.js';
|
|
3
|
+
import { loadVaultsConfig, vaultsJsonPath } from '../lib/vault/vaults.js';
|
|
4
|
+
// One in-process engine per daemon, rebuilt only when vaults.json changes on disk, so a
|
|
5
|
+
// `vault add` between requests is picked up without a daemon restart.
|
|
6
|
+
export const createClientProvider = () => {
|
|
7
|
+
let cached;
|
|
8
|
+
return () => {
|
|
9
|
+
const path = vaultsJsonPath();
|
|
10
|
+
const mtime = existsSync(path) ? statSync(path).mtimeMs : 0;
|
|
11
|
+
if (!cached || cached.mtime !== mtime) {
|
|
12
|
+
cached = { client: createDirectClient(loadVaultsConfig().config), mtime };
|
|
13
|
+
}
|
|
14
|
+
return cached.client;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Web-origin defense for the loopback daemon: a Host allow-list blocks DNS-rebinding (an attacker
|
|
2
|
+
// domain that later resolves to 127.0.0.1 still sends its own Host), and an Origin allow-list blocks
|
|
3
|
+
// a browser page from POSTing to the daemon. Both are pure so they unit-test without a socket.
|
|
4
|
+
// The only Host values a genuine loopback client sends, pinned to the actually-bound port.
|
|
5
|
+
export const loopbackHosts = (port) => [
|
|
6
|
+
`127.0.0.1:${port}`,
|
|
7
|
+
`localhost:${port}`,
|
|
8
|
+
`[::1]:${port}`,
|
|
9
|
+
];
|
|
10
|
+
export const isAllowedHost = (host, port) => host !== undefined && loopbackHosts(port).includes(host);
|
|
11
|
+
// A missing Origin is fine (non-browser clients omit it); a present one must be loopback (any port).
|
|
12
|
+
const LOOPBACK_ORIGIN = /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?$/;
|
|
13
|
+
export const isAllowedOrigin = (origin) => origin === undefined || LOOPBACK_ORIGIN.test(origin);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const DEFAULT_DAEMON_PORT = 4243;
|
|
2
|
+
export declare const EADDRINUSE_EXIT_CODE = 3;
|
|
3
|
+
export declare const writePidFile: (pid: number) => void;
|
|
4
|
+
export declare const writePortFile: (port: number) => void;
|
|
5
|
+
export declare const generateDaemonToken: () => string;
|
|
6
|
+
export declare const writeTokenFile: (token: string) => void;
|
|
7
|
+
export declare const readDaemonToken: () => string | null;
|
|
8
|
+
export declare const removePidFile: () => void;
|
|
9
|
+
export declare const removePortFile: () => void;
|
|
10
|
+
export declare const removeTokenFile: () => void;
|
|
11
|
+
export declare const resolvePort: () => number;
|
|
12
|
+
export declare const isProcessAlive: (pid: number) => boolean;
|
|
13
|
+
export declare const signalPid: (pid: number) => boolean;
|
|
14
|
+
export declare const isDaemonRunning: () => boolean;
|
|
15
|
+
export declare const stopDaemon: () => boolean;
|
|
16
|
+
export declare const stopDaemonSafely: (probe?: (port: number) => Promise<number | null>) => Promise<boolean>;
|
|
17
|
+
export declare const stopDaemonAndWait: (timeoutMs?: number) => Promise<boolean>;
|