@phnx-labs/agents-cli 1.20.73 → 1.20.76
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 +989 -0
- package/README.md +36 -10
- package/dist/bin/agents +0 -0
- package/dist/commands/apply.js +21 -3
- package/dist/commands/attach.d.ts +10 -0
- package/dist/commands/attach.js +41 -0
- package/dist/commands/computer.js +3 -3
- package/dist/commands/detach-core.d.ts +46 -0
- package/dist/commands/detach-core.js +61 -0
- package/dist/commands/detach.d.ts +5 -0
- package/dist/commands/detach.js +171 -0
- package/dist/commands/doctor.js +31 -1
- package/dist/commands/exec.js +31 -3
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.js +215 -0
- package/dist/commands/feed.d.ts +7 -1
- package/dist/commands/feed.js +47 -4
- package/dist/commands/go.d.ts +9 -2
- package/dist/commands/go.js +16 -6
- package/dist/commands/harness.d.ts +14 -0
- package/dist/commands/harness.js +145 -0
- package/dist/commands/import.js +87 -9
- package/dist/commands/inspect.js +5 -2
- package/dist/commands/profiles.d.ts +20 -0
- package/dist/commands/profiles.js +68 -21
- package/dist/commands/repo.js +14 -0
- package/dist/commands/routines.js +15 -2
- package/dist/commands/secrets.js +44 -21
- package/dist/commands/sessions-browser.js +1 -1
- package/dist/commands/sessions-export.js +19 -5
- package/dist/commands/sessions-migrate.d.ts +29 -0
- package/dist/commands/sessions-migrate.js +596 -0
- package/dist/commands/sessions-picker.js +16 -1
- package/dist/commands/sessions.d.ts +36 -13
- package/dist/commands/sessions.js +210 -40
- package/dist/commands/setup-computer.js +2 -2
- package/dist/commands/setup.js +6 -1
- package/dist/commands/ssh.js +71 -35
- package/dist/commands/status.js +10 -2
- package/dist/commands/versions.js +51 -11
- package/dist/commands/view.d.ts +5 -0
- package/dist/commands/view.js +99 -31
- package/dist/commands/watchdog.d.ts +7 -2
- package/dist/commands/watchdog.js +73 -57
- package/dist/index.js +59 -7
- package/dist/lib/activity.d.ts +14 -4
- package/dist/lib/activity.js +17 -5
- package/dist/lib/actor.d.ts +50 -0
- package/dist/lib/actor.js +166 -0
- package/dist/lib/agent-spec/provider.js +2 -1
- package/dist/lib/agent-spec/resolve.js +19 -5
- package/dist/lib/agent-spec/types.d.ts +9 -1
- package/dist/lib/agents.d.ts +56 -0
- package/dist/lib/agents.js +133 -7
- package/dist/lib/cloud/codex.d.ts +2 -0
- package/dist/lib/cloud/codex.js +14 -3
- package/dist/lib/cloud/session-index.d.ts +32 -0
- package/dist/lib/cloud/session-index.js +58 -0
- package/dist/lib/cloud/store.d.ts +7 -0
- package/dist/lib/cloud/store.js +25 -0
- package/dist/lib/config-transfer.d.ts +16 -0
- package/dist/lib/config-transfer.js +60 -0
- package/dist/lib/daemon.js +18 -2
- package/dist/lib/devices/connect.d.ts +15 -1
- package/dist/lib/devices/connect.js +15 -1
- package/dist/lib/devices/fleet.d.ts +21 -0
- package/dist/lib/devices/fleet.js +26 -0
- package/dist/lib/devices/health-report.d.ts +38 -0
- package/dist/lib/devices/health-report.js +214 -0
- package/dist/lib/devices/health.js +4 -1
- package/dist/lib/devices/reachability.d.ts +31 -0
- package/dist/lib/devices/reachability.js +40 -0
- package/dist/lib/devices/registry.d.ts +33 -0
- package/dist/lib/devices/registry.js +37 -0
- package/dist/lib/devices/resolve-target.d.ts +15 -27
- package/dist/lib/devices/resolve-target.js +63 -102
- package/dist/lib/devices/sync.d.ts +18 -0
- package/dist/lib/devices/sync.js +23 -1
- package/dist/lib/devices/tailscale.d.ts +3 -0
- package/dist/lib/devices/tailscale.js +1 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/exec.d.ts +66 -0
- package/dist/lib/exec.js +195 -6
- package/dist/lib/export.d.ts +72 -0
- package/dist/lib/export.js +269 -0
- package/dist/lib/feed-post.d.ts +63 -0
- package/dist/lib/feed-post.js +204 -0
- package/dist/lib/fleet/apply.d.ts +32 -2
- package/dist/lib/fleet/apply.js +97 -10
- package/dist/lib/fleet/types.d.ts +11 -0
- package/dist/lib/fs-walk.d.ts +13 -0
- package/dist/lib/fs-walk.js +16 -7
- package/dist/lib/hooks.d.ts +1 -0
- package/dist/lib/hooks.js +156 -0
- package/dist/lib/hosts/dispatch.d.ts +7 -0
- package/dist/lib/hosts/dispatch.js +2 -0
- package/dist/lib/hosts/passthrough.js +2 -0
- package/dist/lib/hosts/reconnect.d.ts +78 -0
- package/dist/lib/hosts/reconnect.js +127 -0
- package/dist/lib/hosts/registry.d.ts +75 -14
- package/dist/lib/hosts/registry.js +205 -30
- package/dist/lib/hosts/remote-cmd.js +1 -0
- package/dist/lib/hosts/run-target.d.ts +13 -5
- package/dist/lib/hosts/run-target.js +26 -10
- package/dist/lib/hosts/session-index.d.ts +18 -1
- package/dist/lib/hosts/session-index.js +37 -2
- package/dist/lib/hosts/session-marker.d.ts +33 -0
- package/dist/lib/hosts/session-marker.js +51 -0
- package/dist/lib/hosts/tasks.d.ts +8 -4
- package/dist/lib/import.d.ts +25 -0
- package/dist/lib/import.js +107 -2
- package/dist/lib/isolation-boundary-report.d.ts +10 -0
- package/dist/lib/isolation-boundary-report.js +35 -0
- package/dist/lib/menubar/install-menubar.d.ts +20 -0
- package/dist/lib/menubar/install-menubar.js +45 -1
- package/dist/lib/migrate.d.ts +16 -0
- package/dist/lib/migrate.js +36 -0
- package/dist/lib/models.d.ts +27 -0
- package/dist/lib/models.js +54 -1
- package/dist/lib/overdue.d.ts +7 -2
- package/dist/lib/overdue.js +18 -11
- package/dist/lib/picker.js +4 -1
- package/dist/lib/platform/process.d.ts +17 -0
- package/dist/lib/platform/process.js +70 -0
- package/dist/lib/profiles-presets.js +9 -7
- package/dist/lib/profiles.d.ts +31 -0
- package/dist/lib/profiles.js +70 -0
- package/dist/lib/project-resources.js +20 -5
- package/dist/lib/pty-server.d.ts +2 -10
- package/dist/lib/pty-server.js +4 -38
- package/dist/lib/registry.d.ts +1 -1
- package/dist/lib/registry.js +48 -8
- package/dist/lib/rotate.d.ts +18 -0
- package/dist/lib/rotate.js +28 -0
- package/dist/lib/routines.d.ts +26 -0
- package/dist/lib/routines.js +19 -2
- package/dist/lib/runner.js +104 -7
- package/dist/lib/secrets/agent.d.ts +66 -1
- package/dist/lib/secrets/agent.js +154 -90
- package/dist/lib/secrets/bundles.d.ts +34 -0
- package/dist/lib/secrets/bundles.js +179 -19
- package/dist/lib/secrets/index.d.ts +15 -1
- package/dist/lib/secrets/index.js +21 -3
- package/dist/lib/secrets/rc-hygiene.d.ts +55 -0
- package/dist/lib/secrets/rc-hygiene.js +154 -0
- package/dist/lib/secrets/remote.d.ts +7 -4
- package/dist/lib/secrets/remote.js +7 -4
- package/dist/lib/secrets/sync-commands.d.ts +21 -0
- package/dist/lib/secrets/sync-commands.js +21 -0
- package/dist/lib/self-update.d.ts +23 -2
- package/dist/lib/self-update.js +86 -5
- package/dist/lib/session/active.d.ts +114 -7
- package/dist/lib/session/active.js +323 -52
- package/dist/lib/session/cloud.js +2 -1
- package/dist/lib/session/db.d.ts +48 -0
- package/dist/lib/session/db.js +238 -14
- package/dist/lib/session/detached.d.ts +30 -0
- package/dist/lib/session/detached.js +92 -0
- package/dist/lib/session/discover.d.ts +465 -2
- package/dist/lib/session/discover.js +1648 -468
- package/dist/lib/session/fork.js +2 -1
- package/dist/lib/session/hook-sessions.d.ts +43 -0
- package/dist/lib/session/hook-sessions.js +135 -0
- package/dist/lib/session/linear.d.ts +6 -0
- package/dist/lib/session/linear.js +55 -0
- package/dist/lib/session/migrate-targets.d.ts +65 -0
- package/dist/lib/session/migrate-targets.js +94 -0
- package/dist/lib/session/migrations.d.ts +37 -0
- package/dist/lib/session/migrations.js +60 -0
- package/dist/lib/session/parse.d.ts +18 -0
- package/dist/lib/session/parse.js +130 -30
- package/dist/lib/session/pid-registry.d.ts +34 -2
- package/dist/lib/session/pid-registry.js +49 -2
- package/dist/lib/session/render.d.ts +7 -2
- package/dist/lib/session/render.js +22 -10
- package/dist/lib/session/short-id.d.ts +17 -0
- package/dist/lib/session/short-id.js +20 -0
- package/dist/lib/session/state.js +6 -2
- package/dist/lib/shims.d.ts +27 -1
- package/dist/lib/shims.js +88 -6
- package/dist/lib/sqlite.d.ts +3 -2
- package/dist/lib/sqlite.js +27 -4
- package/dist/lib/staleness/detectors/commands.js +1 -1
- package/dist/lib/staleness/detectors/workflows.js +13 -2
- package/dist/lib/staleness/writers/commands.js +7 -7
- package/dist/lib/staleness/writers/workflows.d.ts +4 -2
- package/dist/lib/startup/command-registry.d.ts +2 -0
- package/dist/lib/startup/command-registry.js +5 -0
- package/dist/lib/state.d.ts +1 -1
- package/dist/lib/state.js +15 -36
- package/dist/lib/teams/agents.d.ts +19 -10
- package/dist/lib/teams/agents.js +40 -39
- package/dist/lib/types.d.ts +48 -2
- package/dist/lib/uninstall.js +1 -45
- package/dist/lib/usage.d.ts +33 -1
- package/dist/lib/usage.js +172 -12
- package/dist/lib/versions.d.ts +22 -2
- package/dist/lib/versions.js +98 -10
- package/dist/lib/watchdog/log.d.ts +43 -0
- package/dist/lib/watchdog/log.js +69 -0
- package/dist/lib/watchdog/routine.d.ts +44 -0
- package/dist/lib/watchdog/routine.js +69 -0
- package/dist/lib/watchdog/runner.d.ts +51 -7
- package/dist/lib/watchdog/runner.js +239 -64
- package/dist/lib/watchdog/watchdog.d.ts +1 -1
- package/dist/lib/watchdog/watchdog.js +31 -16
- package/dist/lib/workflows.d.ts +16 -0
- package/dist/lib/workflows.js +110 -1
- package/package.json +1 -1
package/dist/lib/sqlite.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Picks `bun:sqlite` under Bun and `node:sqlite` under Node (>=22.5). Avoids
|
|
5
5
|
* the native `better-sqlite3` addon entirely so there is no prebuild compile
|
|
6
|
-
* and no Node/Bun ABI mismatch
|
|
7
|
-
*
|
|
6
|
+
* and no Node/Bun ABI mismatch. Both runtimes are production: `dist/index.js`
|
|
7
|
+
* runs under Node, while the signed standalone `dist/bin/agents` (what the
|
|
8
|
+
* shims exec) embeds Bun.
|
|
8
9
|
*
|
|
9
10
|
* Exposes the small better-sqlite3-shaped surface area the rest of the
|
|
10
11
|
* codebase already uses: `prepare/exec/pragma/transaction/close` on the DB,
|
|
@@ -21,9 +22,31 @@ const sqliteMod = isBun
|
|
|
21
22
|
// bun:sqlite exports `Database`; node:sqlite exports `DatabaseSync`.
|
|
22
23
|
const NativeDatabase = sqliteMod.Database
|
|
23
24
|
?? sqliteMod.DatabaseSync;
|
|
25
|
+
/**
|
|
26
|
+
* bun:sqlite binds a named-parameter object ONLY when its keys carry the SQL
|
|
27
|
+
* sigil (`{ '@id': … }` for `VALUES (@id)`); bare keys (`{ id: … }`) match
|
|
28
|
+
* nothing and every parameter stays NULL, so the first NOT NULL column raises a
|
|
29
|
+
* constraint error and the write is lost. node:sqlite accepts the bare keys.
|
|
30
|
+
* `strict: true` makes bun accept them too, so the bare-key call shape this
|
|
31
|
+
* codebase uses works on both runtimes. node:sqlite has no such option and
|
|
32
|
+
* rejects a second argument that isn't an object, so the argument list is built
|
|
33
|
+
* per runtime.
|
|
34
|
+
*
|
|
35
|
+
* The two runtimes are still not interchangeable at the edges, and only bun's
|
|
36
|
+
* half is exercised by the shipped binary rather than by vitest — so keep binds
|
|
37
|
+
* inside the intersection:
|
|
38
|
+
* - omit a named key: bun throws `Missing parameter "x"`, node binds NULL.
|
|
39
|
+
* - pass an extra named key: bun accepts it, node throws `Unknown named
|
|
40
|
+
* parameter`.
|
|
41
|
+
* - use sigil keys (`{'@id': …}`): node accepts them, strict bun rejects them.
|
|
42
|
+
* - a single non-plain object positional arg (e.g. `run(new Date())`) reaches
|
|
43
|
+
* the named path via bindArgs below and throws under strict bun.
|
|
44
|
+
*/
|
|
45
|
+
const NATIVE_ARGS = isBun ? [{ strict: true }] : [];
|
|
24
46
|
function bindArgs(params) {
|
|
25
47
|
// Both bindings accept positional `(a, b, c)` and named `({ a, b, c })`
|
|
26
|
-
// forms
|
|
48
|
+
// forms — bun only under `strict: true` (see NATIVE_ARGS). Pass an object
|
|
49
|
+
// through unchanged so callers using named binds work.
|
|
27
50
|
if (params.length === 1 &&
|
|
28
51
|
params[0] !== null &&
|
|
29
52
|
typeof params[0] === 'object' &&
|
|
@@ -51,7 +74,7 @@ class StatementImpl {
|
|
|
51
74
|
class Database {
|
|
52
75
|
inner;
|
|
53
76
|
constructor(filename) {
|
|
54
|
-
this.inner = new NativeDatabase(filename);
|
|
77
|
+
this.inner = new NativeDatabase(filename, ...NATIVE_ARGS);
|
|
55
78
|
}
|
|
56
79
|
prepare(sql) {
|
|
57
80
|
return new StatementImpl(this.inner.prepare(sql));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Commands detector — mirrors versions.ts:343-357. Inspects the version home,
|
|
3
3
|
* returns command names. Honors the commands-as-skills marker for skills-only
|
|
4
|
-
* agents (
|
|
4
|
+
* agents (kimi, Codex >= 0.117.0, …); falls back to scanning
|
|
5
5
|
* `{agentDir}/<commandsSubdir>/` for the native path.
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from 'fs';
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workflows detector — scans
|
|
3
|
-
*
|
|
2
|
+
* Workflows detector — scans the agent-specific on-disk layout for synced
|
|
3
|
+
* workflow names (Claude WORKFLOW.md trees, Kimi flow skills, Antigravity
|
|
4
|
+
* global_workflows, Goose recipes, OpenClaw Lobster, Grok Rhai).
|
|
4
5
|
*/
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as os from 'os';
|
|
7
8
|
import * as path from 'path';
|
|
8
9
|
import * as yaml from 'yaml';
|
|
9
10
|
import { capableAgents } from '../../capabilities.js';
|
|
11
|
+
import { grokWorkflowMarker } from '../../workflows.js';
|
|
10
12
|
import { lazyAgentMap } from '../writers/lazy-map.js';
|
|
11
13
|
function buildWorkflowsDetector(agent) {
|
|
12
14
|
return {
|
|
@@ -93,6 +95,15 @@ function buildWorkflowsDetector(agent) {
|
|
|
93
95
|
})
|
|
94
96
|
.map(d => d.name.slice(0, -'.lobster'.length));
|
|
95
97
|
}
|
|
98
|
+
if (agent === 'grok') {
|
|
99
|
+
const workflowsDir = path.join(versionHome, '.grok', 'workflows');
|
|
100
|
+
if (!fs.existsSync(workflowsDir))
|
|
101
|
+
return [];
|
|
102
|
+
return fs.readdirSync(workflowsDir, { withFileTypes: true })
|
|
103
|
+
.filter(d => d.isFile() && d.name.endsWith('.rhai') && !d.name.startsWith('.'))
|
|
104
|
+
.filter(d => grokWorkflowMarker(path.join(workflowsDir, d.name)) === d.name.slice(0, -'.rhai'.length))
|
|
105
|
+
.map(d => d.name.slice(0, -'.rhai'.length));
|
|
106
|
+
}
|
|
96
107
|
const workflowsDir = path.join(versionHome, 'workflows');
|
|
97
108
|
if (!fs.existsSync(workflowsDir))
|
|
98
109
|
return [];
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Two physical formats, picked per-(agent, version) at write time:
|
|
5
5
|
*
|
|
6
6
|
* - command-as-skill — fires when `shouldInstallCommandAsSkill(agent, version)`
|
|
7
|
-
* is true. Used for
|
|
8
|
-
*
|
|
9
|
-
* Writes `{agentDir}/skills/<name>/SKILL.md` with the
|
|
10
|
-
* marker; the agent picks it up as a slash-command equivalent.
|
|
7
|
+
* is true. Used for Codex >= 0.117.0 (commands capability ends, skills
|
|
8
|
+
* capability remains) and agents with skills but no native command-file dir
|
|
9
|
+
* such as kimi. Writes `{agentDir}/skills/<name>/SKILL.md` with the
|
|
10
|
+
* `agents_command` marker; the agent picks it up as a slash-command equivalent.
|
|
11
11
|
*
|
|
12
12
|
* - native command file — `{agentDir}/<commandsSubdir>/<name>.md` (or .toml
|
|
13
13
|
* when the agent's format is toml). Standard path for Claude, Codex
|
|
@@ -83,8 +83,8 @@ function buildCommandsWriter(agent) {
|
|
|
83
83
|
// Built lazily on first access — see lazy-map.ts for the cycle rationale.
|
|
84
84
|
//
|
|
85
85
|
// Registration covers two cases:
|
|
86
|
-
// - native commands (claude, codex < 0.117.0, gemini, etc.) — `commands` cap
|
|
87
|
-
// - commands-as-skills (
|
|
86
|
+
// - native commands (claude, codex < 0.117.0, gemini, grok, etc.) — `commands` cap
|
|
87
|
+
// - commands-as-skills (kimi, codex >= 0.117.0)
|
|
88
88
|
//
|
|
89
89
|
// Agents that have skills but use a NATIVE non-file slash-command system
|
|
90
90
|
// (openclaw → Gateway-based commands) are NOT registered. They declare
|
|
@@ -97,7 +97,7 @@ export const commandsWriters = lazyAgentMap(() => {
|
|
|
97
97
|
if (cfg.capabilities.commands === false && (!cfg.skillsDir || cfg.skillsDir === ''))
|
|
98
98
|
continue;
|
|
99
99
|
// Skills-capable agent with no native command-file dir: convert commands to
|
|
100
|
-
// skills by default (
|
|
100
|
+
// skills by default (kimi, …). Opt out only agents with their own
|
|
101
101
|
// slash-command runtime (openclaw).
|
|
102
102
|
if (cfg.capabilities.commands === false && (!cfg.commandsSubdir || cfg.commandsSubdir === '')) {
|
|
103
103
|
if (cfg.nativeCommandRuntime)
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Workflows writer — copies each workflow
|
|
3
|
-
*
|
|
2
|
+
* Workflows writer — copies each selected workflow into the agent-specific
|
|
3
|
+
* on-disk layout via `syncWorkflowToVersion` (Claude: WORKFLOW.md tree under
|
|
4
|
+
* `{versionHome}/workflows/`; Grok: native `.rhai` under
|
|
5
|
+
* `{versionHome}/.grok/workflows/`).
|
|
4
6
|
*/
|
|
5
7
|
import type { AgentId } from '../../types.js';
|
|
6
8
|
import type { ResourceWriter } from './types.js';
|
|
@@ -41,6 +41,7 @@ export declare const loadWorkflows: ModuleLoader;
|
|
|
41
41
|
export declare const loadWorktree: ModuleLoader;
|
|
42
42
|
export declare const loadVersions: ModuleLoader;
|
|
43
43
|
export declare const loadImport: ModuleLoader;
|
|
44
|
+
export declare const loadExport: ModuleLoader;
|
|
44
45
|
export declare const loadPackages: ModuleLoader;
|
|
45
46
|
export declare const loadRoutines: ModuleLoader;
|
|
46
47
|
export declare const loadMonitors: ModuleLoader;
|
|
@@ -56,6 +57,7 @@ export declare const loadApply: ModuleLoader;
|
|
|
56
57
|
export declare const loadCheck: ModuleLoader;
|
|
57
58
|
export declare const loadStatus: ModuleLoader;
|
|
58
59
|
export declare const loadProfiles: ModuleLoader;
|
|
60
|
+
export declare const loadHarness: ModuleLoader;
|
|
59
61
|
export declare const loadSecrets: ModuleLoader;
|
|
60
62
|
export declare const loadLogin: ModuleLoader;
|
|
61
63
|
export declare const loadWallet: ModuleLoader;
|
|
@@ -19,6 +19,7 @@ export const loadWorkflows = async () => (await import('../../commands/workflows
|
|
|
19
19
|
export const loadWorktree = async () => (await import('../../commands/worktree.js')).registerWorktreeCommands;
|
|
20
20
|
export const loadVersions = async () => (await import('../../commands/versions.js')).registerVersionsCommands;
|
|
21
21
|
export const loadImport = async () => (await import('../../commands/import.js')).registerImportCommand;
|
|
22
|
+
export const loadExport = async () => (await import('../../commands/export.js')).registerExportCommand;
|
|
22
23
|
export const loadPackages = async () => (await import('../../commands/packages.js')).registerPackagesCommands;
|
|
23
24
|
export const loadRoutines = async () => (await import('../../commands/routines.js')).registerRoutinesCommands;
|
|
24
25
|
export const loadMonitors = async () => (await import('../../commands/monitors.js')).registerMonitorsCommands;
|
|
@@ -34,6 +35,7 @@ export const loadApply = async () => (await import('../../commands/apply.js')).r
|
|
|
34
35
|
export const loadCheck = async () => (await import('../../commands/check.js')).registerCheckCommand;
|
|
35
36
|
export const loadStatus = async () => (await import('../../commands/status.js')).registerStatusCommand;
|
|
36
37
|
export const loadProfiles = async () => (await import('../../commands/profiles.js')).registerProfilesCommands;
|
|
38
|
+
export const loadHarness = async () => (await import('../../commands/harness.js')).registerHarnessCommands;
|
|
37
39
|
export const loadSecrets = async () => (await import('../../commands/secrets.js')).registerSecretsCommands;
|
|
38
40
|
export const loadLogin = async () => (await import('../../commands/login.js')).registerLoginCommands;
|
|
39
41
|
export const loadWallet = async () => (await import('../../commands/wallet.js')).registerWalletCommands;
|
|
@@ -127,6 +129,7 @@ export const COMMAND_LOADERS = {
|
|
|
127
129
|
purge: [loadVersions],
|
|
128
130
|
prune: [loadVersions, loadPrune],
|
|
129
131
|
import: [loadImport],
|
|
132
|
+
export: [loadExport],
|
|
130
133
|
registry: [loadPackages],
|
|
131
134
|
search: [loadPackages],
|
|
132
135
|
install: [loadPackages],
|
|
@@ -144,6 +147,8 @@ export const COMMAND_LOADERS = {
|
|
|
144
147
|
status: [loadStatus],
|
|
145
148
|
profile: [loadProfiles],
|
|
146
149
|
profiles: [loadProfiles],
|
|
150
|
+
harness: [loadHarness],
|
|
151
|
+
harnesses: [loadHarness],
|
|
147
152
|
secrets: [loadSecrets],
|
|
148
153
|
login: [loadLogin],
|
|
149
154
|
logout: [loadLogin],
|
package/dist/lib/state.d.ts
CHANGED
|
@@ -165,7 +165,7 @@ export declare function getDriveDir(): string;
|
|
|
165
165
|
export declare function getTrashDir(): string;
|
|
166
166
|
/** Path to local session indexer storage (~/.agents/.history/sessions/). */
|
|
167
167
|
export declare function getSessionsDir(): string;
|
|
168
|
-
/** Path to the session index database (~/.agents/.history/sessions.db). */
|
|
168
|
+
/** Path to the session index database (~/.agents/.history/sessions/sessions.db). */
|
|
169
169
|
export declare function getSessionsDbPath(): string;
|
|
170
170
|
/** Path to teams config + registry (~/.agents/teams/). */
|
|
171
171
|
export declare function getTeamsDir(): string;
|
package/dist/lib/state.js
CHANGED
|
@@ -27,7 +27,6 @@ import * as path from 'path';
|
|
|
27
27
|
import * as os from 'os';
|
|
28
28
|
import * as yaml from 'yaml';
|
|
29
29
|
import { ensureLockTarget, atomicWriteFileSync, withFileLock } from './fs-atomic.js';
|
|
30
|
-
import { SEEDED_REGISTRIES } from './types.js';
|
|
31
30
|
import { machineId } from './machine-id.js';
|
|
32
31
|
const HOME = process.env.HOME ?? os.homedir();
|
|
33
32
|
/**
|
|
@@ -376,7 +375,7 @@ export function getDriveDir() { return DRIVE_DIR; }
|
|
|
376
375
|
export function getTrashDir() { return TRASH_DIR; }
|
|
377
376
|
/** Path to local session indexer storage (~/.agents/.history/sessions/). */
|
|
378
377
|
export function getSessionsDir() { return SESSIONS_DIR; }
|
|
379
|
-
/** Path to the session index database (~/.agents/.history/sessions.db). */
|
|
378
|
+
/** Path to the session index database (~/.agents/.history/sessions/sessions.db). */
|
|
380
379
|
export function getSessionsDbPath() { return SESSIONS_DB_PATH; }
|
|
381
380
|
/** Path to teams config + registry (~/.agents/teams/). */
|
|
382
381
|
export function getTeamsDir() { return TEAMS_DIR; }
|
|
@@ -606,18 +605,25 @@ function writeIfChanged(filePath, content) {
|
|
|
606
605
|
* `agents:` / `versions:` are not written (no empty committed files).
|
|
607
606
|
*/
|
|
608
607
|
function writeMetaUnlocked(meta) {
|
|
609
|
-
const { agents, versions, defaultBrowserProfile, ...central } = meta;
|
|
608
|
+
const { agents, isolatedAgents, versions, defaultBrowserProfile, ...central } = meta;
|
|
610
609
|
// Write the machine-local files FIRST, then strip central — so a crash mid-write
|
|
611
610
|
// never removes pins/versions from central before they're persisted elsewhere.
|
|
612
611
|
const devicePath = getDeviceMetaPath();
|
|
613
612
|
const hasAgents = !!agents && Object.keys(agents).length > 0;
|
|
613
|
+
// The isolated pointer names a version installed on THIS machine, exactly like a
|
|
614
|
+
// global pin, so it belongs beside `agents:` in the device file rather than in the
|
|
615
|
+
// central doc that syncs — otherwise another machine inherits a pointer to a copy
|
|
616
|
+
// it does not have.
|
|
617
|
+
const hasIsolatedAgents = !!isolatedAgents && Object.keys(isolatedAgents).length > 0;
|
|
614
618
|
const hasDefaultBrowser = !!defaultBrowserProfile;
|
|
615
|
-
if (hasAgents || hasDefaultBrowser) {
|
|
619
|
+
if (hasAgents || hasIsolatedAgents || hasDefaultBrowser) {
|
|
616
620
|
// Device-local doc carries `agents:` pins and `defaultBrowserProfile:` — both
|
|
617
621
|
// are per-machine and must never land in central agents.yaml (which syncs).
|
|
618
622
|
const deviceDoc = {};
|
|
619
623
|
if (hasAgents)
|
|
620
624
|
deviceDoc.agents = agents;
|
|
625
|
+
if (hasIsolatedAgents)
|
|
626
|
+
deviceDoc.isolatedAgents = isolatedAgents;
|
|
621
627
|
if (hasDefaultBrowser)
|
|
622
628
|
deviceDoc.defaultBrowserProfile = defaultBrowserProfile;
|
|
623
629
|
fs.mkdirSync(path.dirname(devicePath), { recursive: true });
|
|
@@ -640,8 +646,9 @@ function writeMetaUnlocked(meta) {
|
|
|
640
646
|
}
|
|
641
647
|
/**
|
|
642
648
|
* Overlay this machine's local state onto a central-portable Meta:
|
|
643
|
-
* - `agents:` from the device file (device wins; the union
|
|
644
|
-
* one-level merge and self-heals a pre-migration central that
|
|
649
|
+
* - `agents:` and `isolatedAgents:` from the device file (device wins; the union
|
|
650
|
+
* both preserves the one-level merge and self-heals a pre-migration central that
|
|
651
|
+
* still has pins)
|
|
645
652
|
* - `defaultBrowserProfile:` from the device file (device is the sole source;
|
|
646
653
|
* the field is stripped from central on write, so nothing to merge against)
|
|
647
654
|
* - `versions:` from the history JSON (wholesale replace; falls back to
|
|
@@ -654,6 +661,8 @@ function overlayMachineLocal(meta) {
|
|
|
654
661
|
const dm = yaml.parse(fs.readFileSync(devicePath, 'utf-8'));
|
|
655
662
|
if (dm?.agents)
|
|
656
663
|
meta.agents = { ...meta.agents, ...dm.agents };
|
|
664
|
+
if (dm?.isolatedAgents)
|
|
665
|
+
meta.isolatedAgents = { ...meta.isolatedAgents, ...dm.isolatedAgents };
|
|
657
666
|
if (dm?.defaultBrowserProfile)
|
|
658
667
|
meta.defaultBrowserProfile = dm.defaultBrowserProfile;
|
|
659
668
|
}
|
|
@@ -670,29 +679,6 @@ function overlayMachineLocal(meta) {
|
|
|
670
679
|
}
|
|
671
680
|
return meta;
|
|
672
681
|
}
|
|
673
|
-
function applyRegistrySeeds(meta) {
|
|
674
|
-
const seeded = new Set(meta.seededPresets || []);
|
|
675
|
-
let changed = false;
|
|
676
|
-
for (const [type, presets] of Object.entries(SEEDED_REGISTRIES)) {
|
|
677
|
-
for (const [name, config] of Object.entries(presets)) {
|
|
678
|
-
const key = `${type}.${name}`;
|
|
679
|
-
if (seeded.has(key))
|
|
680
|
-
continue;
|
|
681
|
-
if (!meta.registries)
|
|
682
|
-
meta.registries = { mcp: {}, skill: {} };
|
|
683
|
-
if (!meta.registries[type])
|
|
684
|
-
meta.registries[type] = {};
|
|
685
|
-
if (!meta.registries[type][name]) {
|
|
686
|
-
meta.registries[type][name] = { ...config };
|
|
687
|
-
}
|
|
688
|
-
seeded.add(key);
|
|
689
|
-
changed = true;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
if (changed)
|
|
693
|
-
meta.seededPresets = [...seeded];
|
|
694
|
-
return changed;
|
|
695
|
-
}
|
|
696
682
|
/**
|
|
697
683
|
* One-shot migration: move agents.yaml from system repo to user repo.
|
|
698
684
|
* Idempotent — no-ops if user file already exists or system file absent.
|
|
@@ -803,17 +789,10 @@ export function readMeta() {
|
|
|
803
789
|
};
|
|
804
790
|
}
|
|
805
791
|
overlayMachineLocal(meta);
|
|
806
|
-
if (applyRegistrySeeds(meta)) {
|
|
807
|
-
writeMeta(meta);
|
|
808
|
-
return rememberMeta(meta);
|
|
809
|
-
}
|
|
810
792
|
return rememberMeta(meta);
|
|
811
793
|
}
|
|
812
794
|
const meta = createDefaultMeta();
|
|
813
795
|
overlayMachineLocal(meta);
|
|
814
|
-
if (applyRegistrySeeds(meta)) {
|
|
815
|
-
writeMeta(meta);
|
|
816
|
-
}
|
|
817
796
|
return rememberMeta(meta);
|
|
818
797
|
}
|
|
819
798
|
/** Serialize and write agents.yaml to the user repo, invalidating the in-memory cache. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { captureProcessStartTime } from '../platform/index.js';
|
|
1
2
|
import { AgentType } from './parsers.js';
|
|
2
3
|
/**
|
|
3
4
|
* Compute the Lowest Common Ancestor (LCA) of multiple file paths.
|
|
@@ -26,18 +27,25 @@ export type { AgentType } from './parsers.js';
|
|
|
26
27
|
*/
|
|
27
28
|
export declare function buildSentinelCommand(cmd: string[], exitCodePath: string): string;
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
30
|
+
* Env for a locally-spawned teammate. Freezes ONE actor for the whole spawn
|
|
31
|
+
* tree: actorEnv(resolveActor()) stamps AGENTS_ACTOR* onto the child env, so the
|
|
32
|
+
* teammate's inner `agents run` reads it via inheritedActor and short-circuits
|
|
33
|
+
* computeActor instead of re-resolving — every teammate under one orchestrator
|
|
34
|
+
* shares the orchestrator's single frozen actor (see actor.ts). Precedence:
|
|
35
|
+
* process env < actor < the teammate's --env overrides, so an explicit override
|
|
36
|
+
* still wins. Single source of truth shared by launchProcess() and its test.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildTeammateSpawnEnv(envOverrides: Record<string, string> | null): NodeJS.ProcessEnv;
|
|
39
|
+
/**
|
|
40
|
+
* Re-exported from `platform/process.ts`, which owns the one implementation.
|
|
35
41
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
42
|
+
* This module used to carry its own near-identical copy, and that copy had no
|
|
43
|
+
* Windows branch — it fell through to `ps`, which does not exist there, so
|
|
44
|
+
* `captureProcessStartTime` always returned null and the pid-reuse guard at
|
|
45
|
+
* `stop()` was silently inert on Windows. That is exactly how `agents teams stop`
|
|
46
|
+
* ends up SIGKILLing an unrelated process group once the OS recycles a pid.
|
|
39
47
|
*/
|
|
40
|
-
export
|
|
48
|
+
export { captureProcessStartTime };
|
|
41
49
|
/**
|
|
42
50
|
* Reasoning-intensity knob. Passed through to `agents run --effort`, which
|
|
43
51
|
* translates it into per-agent reasoning flags (claude --effort, codex
|
|
@@ -130,6 +138,7 @@ export declare class AgentProcess {
|
|
|
130
138
|
startedAt: Date;
|
|
131
139
|
completedAt: Date | null;
|
|
132
140
|
parentSessionId: string | null;
|
|
141
|
+
actor: string | null;
|
|
133
142
|
cloudSessionId: string | null;
|
|
134
143
|
cloudProvider: string | null;
|
|
135
144
|
prUrl: string | null;
|
package/dist/lib/teams/agents.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* dependency scheduling via --after, per-teammate model/effort overrides, and
|
|
8
8
|
* multiple permission modes (plan, edit, full).
|
|
9
9
|
*/
|
|
10
|
-
import { spawn, execSync
|
|
10
|
+
import { spawn, execSync } from 'child_process';
|
|
11
11
|
import { getAgentsInvocation } from '../daemon.js';
|
|
12
12
|
import * as fs from 'fs/promises';
|
|
13
13
|
import * as fsSync from 'fs';
|
|
@@ -15,7 +15,7 @@ import * as path from 'path';
|
|
|
15
15
|
import * as os from 'os';
|
|
16
16
|
import { randomUUID } from 'crypto';
|
|
17
17
|
import { resolveAgentsDir } from './persistence.js';
|
|
18
|
-
import { findExecutable } from '../platform/index.js';
|
|
18
|
+
import { findExecutable, captureProcessStartTime } from '../platform/index.js';
|
|
19
19
|
import { normalizeEvents } from './parsers.js';
|
|
20
20
|
import { debug } from './debug.js';
|
|
21
21
|
import { setGeminiAutoUpdateDisabled, updateGeminiSettings } from '../gemini-settings.js';
|
|
@@ -23,6 +23,7 @@ import { getAgentsDir as getSystemAgentsDir, getShimsDir } from '../state.js';
|
|
|
23
23
|
import { AGENTS, getAccountInfo } from '../agents.js';
|
|
24
24
|
import { resolveVersion, isVersionInstalled, verifyInstalledBinaryLaunches } from '../versions.js';
|
|
25
25
|
import { sanitizeProcessEnv } from '../secrets/bundles.js';
|
|
26
|
+
import { resolveActor, actorEnv } from '../actor.js';
|
|
26
27
|
import { recordRunName } from '../session/run-names.js';
|
|
27
28
|
import { sshExec, shellQuote } from '../ssh-exec.js';
|
|
28
29
|
import { resolveHost } from '../hosts/registry.js';
|
|
@@ -169,42 +170,31 @@ export function buildSentinelCommand(cmd, exitCodePath) {
|
|
|
169
170
|
return `${cmd.map(shSingleQuote).join(' ')}; echo $? > ${shSingleQuote(exitCodePath)}`;
|
|
170
171
|
}
|
|
171
172
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
* Linux: field 22 of /proc/<pid>/stat (starttime in clock ticks since boot).
|
|
180
|
-
* macOS: output of `ps -o lstart= -p <pid>` (start time in human format).
|
|
181
|
-
* Returns null on any error so callers can skip the guard rather than crash.
|
|
173
|
+
* Env for a locally-spawned teammate. Freezes ONE actor for the whole spawn
|
|
174
|
+
* tree: actorEnv(resolveActor()) stamps AGENTS_ACTOR* onto the child env, so the
|
|
175
|
+
* teammate's inner `agents run` reads it via inheritedActor and short-circuits
|
|
176
|
+
* computeActor instead of re-resolving — every teammate under one orchestrator
|
|
177
|
+
* shares the orchestrator's single frozen actor (see actor.ts). Precedence:
|
|
178
|
+
* process env < actor < the teammate's --env overrides, so an explicit override
|
|
179
|
+
* still wins. Single source of truth shared by launchProcess() and its test.
|
|
182
180
|
*/
|
|
183
|
-
export function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const lastParen = stat.lastIndexOf(')');
|
|
190
|
-
if (lastParen < 0)
|
|
191
|
-
return null;
|
|
192
|
-
const tail = stat.slice(lastParen + 2);
|
|
193
|
-
const fields = tail.split(' ');
|
|
194
|
-
// After comm we are at field 3; starttime is field 22, so index 19 here.
|
|
195
|
-
return fields[19] || null;
|
|
196
|
-
}
|
|
197
|
-
const out = execFileSync('ps', ['-o', 'lstart=', '-p', String(pid)], {
|
|
198
|
-
encoding: 'utf-8',
|
|
199
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
200
|
-
});
|
|
201
|
-
const trimmed = out.trim();
|
|
202
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
203
|
-
}
|
|
204
|
-
catch {
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
181
|
+
export function buildTeammateSpawnEnv(envOverrides) {
|
|
182
|
+
return {
|
|
183
|
+
...sanitizeProcessEnv(process.env),
|
|
184
|
+
...actorEnv(resolveActor()),
|
|
185
|
+
...(envOverrides ?? {}),
|
|
186
|
+
};
|
|
207
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Re-exported from `platform/process.ts`, which owns the one implementation.
|
|
190
|
+
*
|
|
191
|
+
* This module used to carry its own near-identical copy, and that copy had no
|
|
192
|
+
* Windows branch — it fell through to `ps`, which does not exist there, so
|
|
193
|
+
* `captureProcessStartTime` always returned null and the pid-reuse guard at
|
|
194
|
+
* `stop()` was silently inert on Windows. That is exactly how `agents teams stop`
|
|
195
|
+
* ends up SIGKILLing an unrelated process group once the OS recycles a pid.
|
|
196
|
+
*/
|
|
197
|
+
export { captureProcessStartTime };
|
|
208
198
|
/** Agent types the team runner supports. */
|
|
209
199
|
const TEAM_AGENT_TYPES = ['codex', 'cursor', 'gemini', 'claude', 'opencode', 'grok', 'antigravity', 'kimi', 'droid'];
|
|
210
200
|
// Suffix appended to all prompts to ensure agents provide a summary
|
|
@@ -479,6 +469,12 @@ export class AgentProcess {
|
|
|
479
469
|
startedAt = new Date();
|
|
480
470
|
completedAt = null;
|
|
481
471
|
parentSessionId = null;
|
|
472
|
+
// Frozen actor (resolveActor().id) this teammate runs under. Stamped onto the
|
|
473
|
+
// local spawn env via actorEnv (buildTeammateSpawnEnv) so the teammate's inner
|
|
474
|
+
// `agents run` inherits one actor for the whole tree instead of re-resolving,
|
|
475
|
+
// and persisted so the record shows who ran it. Set from the resolved actor at
|
|
476
|
+
// construction; loadFromDisk restores the persisted value.
|
|
477
|
+
actor = null;
|
|
482
478
|
cloudSessionId = null;
|
|
483
479
|
cloudProvider = null;
|
|
484
480
|
prUrl = null;
|
|
@@ -564,6 +560,7 @@ export class AgentProcess {
|
|
|
564
560
|
this.completedAt = completedAt;
|
|
565
561
|
this.baseDir = baseDir;
|
|
566
562
|
this.parentSessionId = parentSessionId;
|
|
563
|
+
this.actor = resolveActor().id;
|
|
567
564
|
this.cloudSessionId = cloudSessionId;
|
|
568
565
|
this.cloudProvider = cloudProvider;
|
|
569
566
|
this.prUrl = prUrl;
|
|
@@ -628,6 +625,7 @@ export class AgentProcess {
|
|
|
628
625
|
duration: this.duration(),
|
|
629
626
|
mode: this.mode,
|
|
630
627
|
parent_session_id: this.parentSessionId,
|
|
628
|
+
actor: this.actor,
|
|
631
629
|
workspace_dir: this.workspaceDir,
|
|
632
630
|
cloud_session_id: this.cloudSessionId,
|
|
633
631
|
cloud_provider: this.cloudProvider,
|
|
@@ -884,6 +882,7 @@ export class AgentProcess {
|
|
|
884
882
|
started_at: this.startedAt.toISOString(),
|
|
885
883
|
completed_at: this.completedAt?.toISOString() || null,
|
|
886
884
|
parent_session_id: this.parentSessionId,
|
|
885
|
+
actor: this.actor,
|
|
887
886
|
cloud_session_id: this.cloudSessionId,
|
|
888
887
|
cloud_provider: this.cloudProvider,
|
|
889
888
|
pr_url: this.prUrl,
|
|
@@ -948,6 +947,10 @@ export class AgentProcess {
|
|
|
948
947
|
? meta.task_type
|
|
949
948
|
: null, meta.cloud_repo || null, meta.cloud_branch || null, meta.worktree_name || null, meta.worktree_path || null, meta.profile_name || null);
|
|
950
949
|
agent.startTime = typeof meta.start_time === 'string' ? meta.start_time : null;
|
|
950
|
+
// The persisted actor is the truth for a reload; the constructor set it to
|
|
951
|
+
// THIS process's resolved actor, which is wrong for a teammate someone else
|
|
952
|
+
// ran. Legacy teammates predating the field carry no actor -> null.
|
|
953
|
+
agent.actor = meta.actor ?? null;
|
|
951
954
|
// Distributed-team fields: set post-construction (like startTime) so the
|
|
952
955
|
// constructor signature stays fixed. Null on every pre-existing teammate.
|
|
953
956
|
agent.hostName = meta.host_name || null;
|
|
@@ -1556,9 +1559,7 @@ export class AgentManager {
|
|
|
1556
1559
|
stdio: ['ignore', stdoutFd, stdoutFd],
|
|
1557
1560
|
cwd: agent.cwd || undefined,
|
|
1558
1561
|
detached: true,
|
|
1559
|
-
env: agent.envOverrides
|
|
1560
|
-
? { ...sanitizeProcessEnv(process.env), ...agent.envOverrides }
|
|
1561
|
-
: sanitizeProcessEnv(process.env),
|
|
1562
|
+
env: buildTeammateSpawnEnv(agent.envOverrides),
|
|
1562
1563
|
});
|
|
1563
1564
|
await new Promise((resolve, reject) => {
|
|
1564
1565
|
childProcess.once('spawn', resolve);
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -689,9 +689,40 @@ export interface BrandConfig {
|
|
|
689
689
|
/** False to keep the config but stop minting/using the brand. */
|
|
690
690
|
enabled: boolean;
|
|
691
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* An actor -- a responsible entity behind a run (a human today, a top-level
|
|
694
|
+
* agent later). Keyed in the `actors:` map by a short slug. Every field is
|
|
695
|
+
* optional enrichment over what `tailscale whois` already resolves: pin a
|
|
696
|
+
* preferred git email, add a github handle, or override the display name.
|
|
697
|
+
* `login` is the tailnet login-name to match against (defaults to the map key).
|
|
698
|
+
* See lib/actor.ts.
|
|
699
|
+
*/
|
|
700
|
+
export interface ActorConfig {
|
|
701
|
+
/** 'human' (default) or 'agent'. Only humans get personal git credit. */
|
|
702
|
+
kind?: 'human' | 'agent';
|
|
703
|
+
/** Display + git author name. Overrides the tailnet DisplayName. */
|
|
704
|
+
name?: string;
|
|
705
|
+
/** Git author email. Overrides the tailnet login email. */
|
|
706
|
+
email?: string;
|
|
707
|
+
/** GitHub handle, for PR attribution. */
|
|
708
|
+
github?: string;
|
|
709
|
+
/** Tailnet login-name this entry matches. Defaults to the map key. */
|
|
710
|
+
login?: string;
|
|
711
|
+
}
|
|
692
712
|
/** Top-level structure of ~/.agents/.system/agents.yaml -- the CLI's persistent state. */
|
|
693
713
|
export interface Meta {
|
|
694
714
|
agents?: Partial<Record<AgentId, string>>;
|
|
715
|
+
/**
|
|
716
|
+
* Per-agent preferred ISOLATED version — which copy a bare `agents run <agent>`
|
|
717
|
+
* resolves to when the agent has no global default.
|
|
718
|
+
*
|
|
719
|
+
* Kept separate from `agents` on purpose. An entry there is the global default,
|
|
720
|
+
* which owns the launcher, the bare shim and the real `~/.<agent>` config
|
|
721
|
+
* symlink, and arms the self-heal `shadowing` check. An isolated copy must never
|
|
722
|
+
* acquire any of that, so it cannot be recorded in the same place — the
|
|
723
|
+
* separation is what keeps `getGlobalDefault` incapable of returning one.
|
|
724
|
+
*/
|
|
725
|
+
isolatedAgents?: Partial<Record<AgentId, string>>;
|
|
695
726
|
run?: RunConfig;
|
|
696
727
|
/**
|
|
697
728
|
* `agents run --lease` config. `secretsBundle` names the keychain secrets bundle
|
|
@@ -754,8 +785,23 @@ export interface Meta {
|
|
|
754
785
|
*/
|
|
755
786
|
brands?: Record<string, BrandConfig>;
|
|
756
787
|
/**
|
|
757
|
-
*
|
|
758
|
-
*
|
|
788
|
+
* Actors keyed by slug -- who is behind a run. Enriches or overrides the
|
|
789
|
+
* identity `tailscale whois` resolves (git email, github handle, display
|
|
790
|
+
* name, human vs agent). See lib/actor.ts.
|
|
791
|
+
*/
|
|
792
|
+
actors?: Record<string, ActorConfig>;
|
|
793
|
+
/**
|
|
794
|
+
* Removal tombstones for SEEDED_REGISTRIES presets, keyed like `skill.hermes`.
|
|
795
|
+
*
|
|
796
|
+
* Seeded presets are resolved in memory by `getRegistries` (see
|
|
797
|
+
* `offeredSeeds`) rather than written into agents.yaml — persisting them from
|
|
798
|
+
* the read path dirtied this git-tracked file and deadlocked
|
|
799
|
+
* `agents repo pull` (RUSH-1925). A key listed here means the user ran
|
|
800
|
+
* `registry remove` on that preset, so it is no longer offered.
|
|
801
|
+
*
|
|
802
|
+
* Entries written by the pre-RUSH-1925 seeding also appear here; those files
|
|
803
|
+
* carry the registry in their own `registries:` block too, which takes
|
|
804
|
+
* precedence, so the preset stays exactly as configured.
|
|
759
805
|
*/
|
|
760
806
|
seededPresets?: string[];
|
|
761
807
|
/**
|
package/dist/lib/uninstall.js
CHANGED
|
@@ -20,6 +20,7 @@ import * as os from 'os';
|
|
|
20
20
|
import * as path from 'path';
|
|
21
21
|
import { AGENTS, ALL_AGENT_IDS } from './agents.js';
|
|
22
22
|
import { getAgentConfigPath, getConfigSymlinkVersion, stripShimPathLines, releaseAdoptedLauncher, } from './shims.js';
|
|
23
|
+
import { moveDirCrossDevice, copyDirStrippingAgentsSymlinks } from './config-transfer.js';
|
|
23
24
|
import { getUserAgentsDir, getBackupsDir, getHistoryDir, getShimsDir, getLegacySystemAgentsDir, } from './state.js';
|
|
24
25
|
/** Home dir honoring the AGENTS_REAL_HOME test/override, mirroring shims.ts. */
|
|
25
26
|
function realHome() {
|
|
@@ -60,51 +61,6 @@ function symlinkTarget(p) {
|
|
|
60
61
|
function removeLink(p) {
|
|
61
62
|
fs.unlinkSync(p);
|
|
62
63
|
}
|
|
63
|
-
/**
|
|
64
|
-
* Move `source` onto `dest` across possibly-different volumes. `renameSync` is
|
|
65
|
-
* atomic but throws EXDEV when `~/.agents` lives on a different filesystem than
|
|
66
|
-
* `$HOME`; fall back to copy-then-remove so the restore still completes. The
|
|
67
|
-
* source (a backup inside `~/.agents`) is removed only after the copy succeeds,
|
|
68
|
-
* so a mid-copy failure never destroys the sole surviving copy.
|
|
69
|
-
*/
|
|
70
|
-
function moveDirCrossDevice(source, dest) {
|
|
71
|
-
try {
|
|
72
|
-
fs.renameSync(source, dest);
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
if (err.code !== 'EXDEV')
|
|
76
|
-
throw err;
|
|
77
|
-
fs.cpSync(source, dest, { recursive: true });
|
|
78
|
-
fs.rmSync(source, { recursive: true, force: true });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Copy `source` to `dest`, dropping any symlink whose target resolves back into
|
|
83
|
-
* `~/.agents`. Adoption syncs managed resources (skills/commands) into the
|
|
84
|
-
* version home as symlinks into `~/.agents`; copying them verbatim would leave
|
|
85
|
-
* the restored config full of links that dangle the moment `~/.agents` is
|
|
86
|
-
* disposed. Stripping them yields a clean, self-contained restore.
|
|
87
|
-
*/
|
|
88
|
-
function copyDirStrippingAgentsSymlinks(source, dest, agentsDir) {
|
|
89
|
-
const inside = agentsDir + path.sep;
|
|
90
|
-
fs.cpSync(source, dest, {
|
|
91
|
-
recursive: true,
|
|
92
|
-
filter: (src) => {
|
|
93
|
-
try {
|
|
94
|
-
const st = fs.lstatSync(src);
|
|
95
|
-
if (st.isSymbolicLink()) {
|
|
96
|
-
const tgt = path.resolve(path.dirname(src), fs.readlinkSync(src));
|
|
97
|
-
if (tgt === agentsDir || tgt.startsWith(inside))
|
|
98
|
-
return false;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
/* unreadable entry — let cpSync surface it on the real copy */
|
|
103
|
-
}
|
|
104
|
-
return true;
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
64
|
/** Classify one agent's config dir without mutating anything. */
|
|
109
65
|
function planConfig(agent) {
|
|
110
66
|
const realPath = getAgentConfigPath(agent);
|