@phnx-labs/agents-cli 1.20.74 → 1.20.77
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 +1055 -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 +18 -0
- package/dist/commands/exec.js +83 -13
- 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 +38 -8
- 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 +286 -15
- package/dist/commands/secrets.js +102 -37
- package/dist/commands/sessions-browser.js +12 -2
- 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.d.ts +14 -1
- package/dist/commands/sessions-picker.js +184 -16
- package/dist/commands/sessions.d.ts +56 -14
- package/dist/commands/sessions.js +322 -62
- package/dist/commands/setup-computer.js +2 -2
- package/dist/commands/ssh.d.ts +13 -0
- package/dist/commands/ssh.js +110 -37
- package/dist/commands/status.js +10 -2
- package/dist/commands/versions.js +15 -6
- package/dist/commands/view.d.ts +5 -0
- package/dist/commands/view.js +24 -4
- 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 +17 -6
- package/dist/lib/activity.js +466 -40
- 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 +21 -0
- package/dist/lib/agents.js +70 -6
- 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.js +4 -0
- package/dist/lib/daemon.d.ts +10 -1
- package/dist/lib/daemon.js +114 -11
- package/dist/lib/devices/connect.d.ts +15 -1
- package/dist/lib/devices/connect.js +15 -1
- package/dist/lib/devices/fleet.d.ts +37 -1
- package/dist/lib/devices/fleet.js +36 -2
- 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 +82 -0
- package/dist/lib/exec.js +218 -6
- package/dist/lib/feed-post.d.ts +63 -0
- package/dist/lib/feed-post.js +204 -0
- package/dist/lib/feed.d.ts +7 -1
- package/dist/lib/feed.js +96 -6
- 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/heal.d.ts +7 -4
- package/dist/lib/heal.js +10 -22
- package/dist/lib/hooks.d.ts +1 -0
- package/dist/lib/hooks.js +156 -0
- package/dist/lib/hosts/dispatch.d.ts +16 -0
- package/dist/lib/hosts/dispatch.js +26 -4
- package/dist/lib/hosts/passthrough.js +9 -2
- 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.d.ts +11 -0
- package/dist/lib/hosts/remote-cmd.js +32 -8
- package/dist/lib/hosts/remote-session-id.d.ts +45 -0
- package/dist/lib/hosts/remote-session-id.js +84 -0
- package/dist/lib/hosts/run-target.d.ts +17 -5
- package/dist/lib/hosts/run-target.js +30 -10
- package/dist/lib/hosts/session-index.d.ts +18 -1
- package/dist/lib/hosts/session-index.js +40 -5
- 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 +2 -0
- package/dist/lib/import.js +35 -2
- package/dist/lib/menubar/install-menubar.d.ts +29 -0
- package/dist/lib/menubar/install-menubar.js +59 -1
- package/dist/lib/menubar/notify-desktop.d.ts +44 -0
- package/dist/lib/menubar/notify-desktop.js +78 -0
- 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 +6 -2
- package/dist/lib/overdue.js +10 -36
- 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/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/routine-notify.d.ts +76 -0
- package/dist/lib/routine-notify.js +190 -0
- package/dist/lib/routines-placement.d.ts +38 -0
- package/dist/lib/routines-placement.js +79 -0
- package/dist/lib/routines-project.d.ts +97 -0
- package/dist/lib/routines-project.js +349 -0
- package/dist/lib/routines.d.ts +94 -0
- package/dist/lib/routines.js +93 -9
- package/dist/lib/runner.d.ts +12 -2
- package/dist/lib/runner.js +242 -20
- package/dist/lib/sandbox.js +10 -0
- package/dist/lib/secrets/account-token.d.ts +20 -0
- package/dist/lib/secrets/account-token.js +64 -0
- package/dist/lib/secrets/agent.d.ts +74 -4
- package/dist/lib/secrets/agent.js +181 -107
- package/dist/lib/secrets/bundles.d.ts +54 -6
- package/dist/lib/secrets/bundles.js +230 -34
- package/dist/lib/secrets/index.d.ts +26 -3
- package/dist/lib/secrets/index.js +42 -12
- 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/session-store.d.ts +6 -2
- package/dist/lib/secrets/session-store.js +65 -15
- package/dist/lib/secrets/sync-commands.d.ts +21 -0
- package/dist/lib/secrets/sync-commands.js +21 -0
- package/dist/lib/secrets/unlock-hints.d.ts +27 -0
- package/dist/lib/secrets/unlock-hints.js +36 -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 +124 -7
- package/dist/lib/session/active.js +390 -56
- package/dist/lib/session/cloud.js +2 -1
- package/dist/lib/session/db.d.ts +54 -0
- package/dist/lib/session/db.js +320 -19
- package/dist/lib/session/detached.d.ts +30 -0
- package/dist/lib/session/detached.js +92 -0
- package/dist/lib/session/discover.d.ts +478 -3
- package/dist/lib/session/discover.js +1740 -472
- 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 +141 -32
- package/dist/lib/session/pid-registry.d.ts +34 -2
- package/dist/lib/session/pid-registry.js +49 -2
- package/dist/lib/session/prompt.d.ts +7 -0
- package/dist/lib/session/prompt.js +37 -0
- package/dist/lib/session/provenance.d.ts +7 -0
- package/dist/lib/session/render.d.ts +7 -2
- package/dist/lib/session/render.js +40 -26
- package/dist/lib/session/short-id.d.ts +17 -0
- package/dist/lib/session/short-id.js +20 -0
- package/dist/lib/session/state.d.ts +4 -0
- package/dist/lib/session/state.js +99 -13
- package/dist/lib/session/types.d.ts +25 -1
- package/dist/lib/session/types.js +8 -0
- package/dist/lib/shims.d.ts +1 -1
- package/dist/lib/shims.js +20 -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 +1 -0
- package/dist/lib/startup/command-registry.js +3 -0
- package/dist/lib/state.d.ts +8 -4
- package/dist/lib/state.js +21 -37
- package/dist/lib/teams/agents.d.ts +19 -10
- package/dist/lib/teams/agents.js +40 -39
- package/dist/lib/types.d.ts +47 -2
- package/dist/lib/usage.d.ts +33 -1
- package/dist/lib/usage.js +172 -12
- package/dist/lib/versions.d.ts +9 -2
- package/dist/lib/versions.js +37 -8
- 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
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* markers. Codex has no such tools, so it falls back to last-role + question
|
|
15
15
|
* shape + mtime — same function, driven off the normalized events.
|
|
16
16
|
*/
|
|
17
|
+
import * as path from 'path';
|
|
17
18
|
import { summarizeToolUse } from './parse.js';
|
|
18
19
|
/**
|
|
19
20
|
* Detect per-session rate-limit / usage-limit signals in assistant or error
|
|
@@ -47,9 +48,9 @@ const PROSE_QUESTION_FRESH_MS = 30 * 60_000;
|
|
|
47
48
|
/** Claude tool names that structurally mean "the agent handed control back to you". */
|
|
48
49
|
const PLAN_TOOL = 'ExitPlanMode';
|
|
49
50
|
const ASK_TOOL = 'AskUserQuestion';
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const
|
|
51
|
+
const SNAPSHOT_TODO_TOOLS = new Set(['TodoWrite', 'todo_write', 'update_plan']);
|
|
52
|
+
const TASK_CREATE_TOOL = 'TaskCreate';
|
|
53
|
+
const TASK_UPDATE_TOOL = 'TaskUpdate';
|
|
53
54
|
/**
|
|
54
55
|
* Derive live plan progress from a checklist tool call's args. Accepts both
|
|
55
56
|
* Claude's `TodoWrite` (`todos: [{content,status,activeForm}]`) and Codex's
|
|
@@ -58,10 +59,11 @@ const CODEX_PLAN_TOOL = 'update_plan';
|
|
|
58
59
|
* list, so a session with no plan carries no `todos` field.
|
|
59
60
|
*/
|
|
60
61
|
export function extractTodoProgress(args) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const input = args?.input && typeof args.input === 'object' ? args.input : args;
|
|
63
|
+
const raw = Array.isArray(input?.todos)
|
|
64
|
+
? input.todos
|
|
65
|
+
: Array.isArray(input?.plan)
|
|
66
|
+
? input.plan
|
|
65
67
|
: undefined;
|
|
66
68
|
if (!Array.isArray(raw) || raw.length === 0)
|
|
67
69
|
return undefined;
|
|
@@ -78,7 +80,8 @@ export function extractTodoProgress(args) {
|
|
|
78
80
|
if (!content)
|
|
79
81
|
continue;
|
|
80
82
|
const status = t?.status === 'completed' || t?.status === 'in_progress' ? t.status : 'pending';
|
|
81
|
-
|
|
83
|
+
const description = typeof t?.description === 'string' && t.description ? t.description : undefined;
|
|
84
|
+
items.push({ content, status, ...(description ? { description } : {}), ...(activeForm ? { activeForm } : {}) });
|
|
82
85
|
}
|
|
83
86
|
if (items.length === 0)
|
|
84
87
|
return undefined;
|
|
@@ -91,6 +94,86 @@ export function extractTodoProgress(args) {
|
|
|
91
94
|
activeForm: inProgress ? inProgress.activeForm ?? inProgress.content : undefined,
|
|
92
95
|
};
|
|
93
96
|
}
|
|
97
|
+
/** Fold snapshot checklist tools and Claude TaskCreate/TaskUpdate event logs. */
|
|
98
|
+
export function extractTodoProgressFromEvents(events) {
|
|
99
|
+
let items = [];
|
|
100
|
+
let nextTaskId = 1;
|
|
101
|
+
let sawChecklist = false;
|
|
102
|
+
for (const event of events) {
|
|
103
|
+
if (event.type !== 'tool_use')
|
|
104
|
+
continue;
|
|
105
|
+
const args = event.args ?? {};
|
|
106
|
+
if (SNAPSHOT_TODO_TOOLS.has(event.tool ?? '')) {
|
|
107
|
+
const input = args.input && typeof args.input === 'object' ? args.input : args;
|
|
108
|
+
const raw = Array.isArray(input.todos) ? input.todos : Array.isArray(input.plan) ? input.plan : undefined;
|
|
109
|
+
if (raw) {
|
|
110
|
+
items = raw.map((item) => ({ ...item }));
|
|
111
|
+
sawChecklist = true;
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (event.tool === TASK_CREATE_TOOL) {
|
|
116
|
+
const content = args.subject || args.description;
|
|
117
|
+
if (typeof content !== 'string' || !content.trim())
|
|
118
|
+
continue;
|
|
119
|
+
items.push({
|
|
120
|
+
taskId: String(nextTaskId++),
|
|
121
|
+
content: content.trim(),
|
|
122
|
+
description: typeof args.description === 'string' ? args.description : undefined,
|
|
123
|
+
activeForm: typeof args.activeForm === 'string' ? args.activeForm : undefined,
|
|
124
|
+
status: 'pending',
|
|
125
|
+
});
|
|
126
|
+
sawChecklist = true;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (event.tool === TASK_UPDATE_TOOL) {
|
|
130
|
+
const taskId = String(args.taskId ?? args.task_id ?? '');
|
|
131
|
+
const index = items.findIndex(item => String(item.taskId ?? '') === taskId);
|
|
132
|
+
if (index < 0)
|
|
133
|
+
continue;
|
|
134
|
+
if (args.status === 'deleted') {
|
|
135
|
+
items.splice(index, 1);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const prior = items[index];
|
|
139
|
+
items[index] = {
|
|
140
|
+
...prior,
|
|
141
|
+
...(typeof args.subject === 'string' ? { content: args.subject } : {}),
|
|
142
|
+
...(typeof args.description === 'string' ? { description: args.description } : {}),
|
|
143
|
+
...(typeof args.activeForm === 'string' ? { activeForm: args.activeForm } : {}),
|
|
144
|
+
...(typeof args.status === 'string' ? { status: args.status } : {}),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return sawChecklist ? extractTodoProgress({ todos: items }) : undefined;
|
|
149
|
+
}
|
|
150
|
+
/** Derive a recency-ordered, de-duplicated list of directories touched by tools. */
|
|
151
|
+
export function extractRecentDirectoriesTouched(events, cwd) {
|
|
152
|
+
const dirs = [];
|
|
153
|
+
const add = (value, file = false) => {
|
|
154
|
+
if (typeof value !== 'string' || !value.trim())
|
|
155
|
+
return;
|
|
156
|
+
const resolved = path.isAbsolute(value) ? value : path.resolve(cwd || process.cwd(), value);
|
|
157
|
+
const dir = file ? path.dirname(resolved) : resolved;
|
|
158
|
+
const old = dirs.indexOf(dir);
|
|
159
|
+
if (old >= 0)
|
|
160
|
+
dirs.splice(old, 1);
|
|
161
|
+
dirs.push(dir);
|
|
162
|
+
};
|
|
163
|
+
for (const event of events) {
|
|
164
|
+
if (event.type !== 'tool_use')
|
|
165
|
+
continue;
|
|
166
|
+
const tool = event.tool ?? '';
|
|
167
|
+
const args = event.args ?? {};
|
|
168
|
+
if (['Edit', 'Write', 'edit_file', 'write_file', 'create_file', 'edit', 'write'].includes(tool)) {
|
|
169
|
+
add(args.file_path ?? args.filePath ?? args.path ?? event.path, true);
|
|
170
|
+
}
|
|
171
|
+
else if (['Bash', 'exec_command', 'run_shell_command', 'shell', 'Execute'].includes(tool)) {
|
|
172
|
+
add(args.cwd ?? args.Cwd ?? args.workdir ?? args.working_directory ?? cwd);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return dirs.length ? dirs.slice(-10) : undefined;
|
|
176
|
+
}
|
|
94
177
|
/** Trailing '?' or a leading interrogative — a question aimed at the user. */
|
|
95
178
|
const QUESTION_TRAILING = /\?["'”)\]]?\s*$/;
|
|
96
179
|
const QUESTION_PHRASE = /\b(shall i|should i|do you want|would you like|which (?:one|option|approach|of)|can you (?:confirm|clarify)|please (?:confirm|clarify|advise)|let me know|are you (?:ok|okay|sure)|proceed\?)\b/i;
|
|
@@ -325,11 +408,10 @@ export function inferActivity(events, ctx = {}) {
|
|
|
325
408
|
.slice(-3)
|
|
326
409
|
.map(e => oneLine(e.content ?? ''))
|
|
327
410
|
.filter(Boolean);
|
|
328
|
-
// Live plan progress: the
|
|
411
|
+
// Live plan progress: snapshot checklist tools or the folded Task* event log. Attached
|
|
329
412
|
// to `base` so every return path below carries it — a working, waiting, or idle
|
|
330
413
|
// session all keep showing how far the plan got.
|
|
331
|
-
const
|
|
332
|
-
const todos = lastTodo ? extractTodoProgress(lastTodo.args) : undefined;
|
|
414
|
+
const todos = extractTodoProgressFromEvents(meaningful);
|
|
333
415
|
const base = {
|
|
334
416
|
activity: 'idle',
|
|
335
417
|
lastRole: lastMsg?.role,
|
|
@@ -378,8 +460,12 @@ export function inferActivity(events, ctx = {}) {
|
|
|
378
460
|
// A prose question takes a free-text reply (no select-list), so no options/keys.
|
|
379
461
|
// Unlike the structural plan/ask signals above, the prose heuristic DECAYS: a
|
|
380
462
|
// question nobody answered within PROSE_QUESTION_FRESH_MS is a session that
|
|
381
|
-
// ended, not one that needs you (RUSH-1522).
|
|
382
|
-
|
|
463
|
+
// ended, not one that needs you (RUSH-1522). A prose "?" is only "waiting on
|
|
464
|
+
// you" while the file is DEMONSTRABLY fresh — with no mtime signal at all we
|
|
465
|
+
// cannot assert freshness, so the heuristic must not fire (an unknown-age
|
|
466
|
+
// prose question is a session that ended, closing RUSH-1522's null-mtime hole
|
|
467
|
+
// where a null mtime kept the question forever).
|
|
468
|
+
const questionFresh = ctx.mtimeMs != null && Date.now() - ctx.mtimeMs < PROSE_QUESTION_FRESH_MS;
|
|
383
469
|
if (questionFresh && looksLikeQuestion(last.content ?? '')) {
|
|
384
470
|
const text = oneLine(last.content ?? '');
|
|
385
471
|
return { ...base, activity: 'waiting_input', awaitingReason: 'question', question: { text, reason: 'question' } };
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
export type SessionAgentId = 'claude' | 'codex' | 'gemini' | 'antigravity' | 'opencode' | 'openclaw' | 'rush' | 'hermes' | 'grok' | 'kimi' | 'droid';
|
|
11
11
|
/** All agents with session discovery support, in display order. */
|
|
12
12
|
export declare const SESSION_AGENTS: SessionAgentId[];
|
|
13
|
+
/**
|
|
14
|
+
* True when `agent` stores session data `agents sessions` can discover (a member
|
|
15
|
+
* of {@link SESSION_AGENTS}). The single predicate every session-index writer
|
|
16
|
+
* gates on, so "is this a trackable agent?" is decided in exactly one place.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isSessionTrackedAgent(agent: string): agent is SessionAgentId;
|
|
13
19
|
/** A single normalized event within a session (message, tool call, thinking, etc.). */
|
|
14
20
|
export interface SessionEvent {
|
|
15
21
|
type: 'message' | 'tool_use' | 'tool_result' | 'thinking' | 'error' | 'init' | 'result' | 'usage' | 'attachment';
|
|
@@ -25,6 +31,16 @@ export interface SessionEvent {
|
|
|
25
31
|
output?: string;
|
|
26
32
|
/** Internal: marks tool_use events from local commands */
|
|
27
33
|
_local?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Internal: marks a `role=user` message that is harness-injected scaffolding
|
|
36
|
+
* (Claude `<bash-input>`/`<bash-stdout>` from `!`-prefix runs, `<system-reminder>`,
|
|
37
|
+
* `<task-notification>`, `<command-*>` wrappers, `[Request interrupted]`, skill
|
|
38
|
+
* bodies, hook feedback) rather than a genuine user turn. Set centrally in
|
|
39
|
+
* `parseSession` via `isSyntheticUserMessage`. Such events are excluded from
|
|
40
|
+
* `--include user` and are not counted as turn starts by `--first`/`--last`,
|
|
41
|
+
* but stay in the default full stream so `--markdown` keeps full fidelity.
|
|
42
|
+
*/
|
|
43
|
+
_synthetic?: boolean;
|
|
28
44
|
model?: string;
|
|
29
45
|
inputTokens?: number;
|
|
30
46
|
outputTokens?: number;
|
|
@@ -41,10 +57,12 @@ export interface SessionAttachment {
|
|
|
41
57
|
mediaType: string;
|
|
42
58
|
sizeBytes?: number;
|
|
43
59
|
}
|
|
44
|
-
/** One checklist item
|
|
60
|
+
/** One normalized checklist/task item emitted by any transcript harness. */
|
|
45
61
|
export interface TodoItem {
|
|
46
62
|
content: string;
|
|
47
63
|
status: 'pending' | 'in_progress' | 'completed';
|
|
64
|
+
/** Optional longer explanation supplied by task-based harnesses. */
|
|
65
|
+
description?: string;
|
|
48
66
|
/** Present-continuous label shown while this item is the active step. */
|
|
49
67
|
activeForm?: string;
|
|
50
68
|
}
|
|
@@ -152,6 +170,12 @@ export interface SessionMeta {
|
|
|
152
170
|
* instead of re-parsing the transcript. Absent when the session wrote no list.
|
|
153
171
|
*/
|
|
154
172
|
todos?: TodoProgress;
|
|
173
|
+
/** Most-recent unique directories changed or used as a shell working directory. */
|
|
174
|
+
recentDirectoriesTouched?: string[];
|
|
175
|
+
/** Linear project containing ticketId, resolved lazily and cached in SQLite. */
|
|
176
|
+
linearProject?: string;
|
|
177
|
+
/** Browser URL for linearProject. */
|
|
178
|
+
linearProjectUrl?: string;
|
|
155
179
|
/**
|
|
156
180
|
* True when the session was spawned programmatically (SDK entrypoint) rather
|
|
157
181
|
* than by a human at the Claude CLI. Captured at scan time from the JSONL
|
|
@@ -8,3 +8,11 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/** All agents with session discovery support, in display order. */
|
|
10
10
|
export const SESSION_AGENTS = ['claude', 'codex', 'gemini', 'antigravity', 'opencode', 'openclaw', 'rush', 'hermes', 'grok', 'kimi', 'droid'];
|
|
11
|
+
/**
|
|
12
|
+
* True when `agent` stores session data `agents sessions` can discover (a member
|
|
13
|
+
* of {@link SESSION_AGENTS}). The single predicate every session-index writer
|
|
14
|
+
* gates on, so "is this a trackable agent?" is decided in exactly one place.
|
|
15
|
+
*/
|
|
16
|
+
export function isSessionTrackedAgent(agent) {
|
|
17
|
+
return SESSION_AGENTS.includes(agent);
|
|
18
|
+
}
|
package/dist/lib/shims.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export interface ConflictInfo {
|
|
|
77
77
|
* top-level entry add/remove — deep edits to plugin contents won't
|
|
78
78
|
* trigger auto-resync, run `agents sync` for that.
|
|
79
79
|
*/
|
|
80
|
-
export declare const SHIM_SCHEMA_VERSION =
|
|
80
|
+
export declare const SHIM_SCHEMA_VERSION = 27;
|
|
81
81
|
/**
|
|
82
82
|
* Generate the full bash shim script for the given agent. The returned string
|
|
83
83
|
* is written to ~/.agents/shims/{cliCommand} and made executable.
|
package/dist/lib/shims.js
CHANGED
|
@@ -222,7 +222,7 @@ async function promptConflictStrategy(conflictInfos) {
|
|
|
222
222
|
// The old dispatcher checked only the global dir, so a pinned grok that
|
|
223
223
|
// installed into the versioned home fell through to the "not installed"
|
|
224
224
|
// error.
|
|
225
|
-
export const SHIM_SCHEMA_VERSION =
|
|
225
|
+
export const SHIM_SCHEMA_VERSION = 27;
|
|
226
226
|
/** Internal marker string used to embed the schema version in shim scripts. */
|
|
227
227
|
const SHIM_VERSION_MARKER = 'agents-shim-version:';
|
|
228
228
|
function shellQuote(value) {
|
|
@@ -278,13 +278,20 @@ export COPILOT_HOME="$VERSION_DIR/home/${configDirName}"
|
|
|
278
278
|
# This gives agents-cli full versioned isolation + resource sync for grok.
|
|
279
279
|
export GROK_HOME="$VERSION_DIR/home/.grok"
|
|
280
280
|
`
|
|
281
|
-
: agent === '
|
|
281
|
+
: agent === 'opencode'
|
|
282
282
|
? `
|
|
283
|
+
# OpenCode reads plugins, agents, commands, and other config-directory
|
|
284
|
+
# resources from OPENCODE_CONFIG_DIR. Point it at the versioned global config
|
|
285
|
+
# tree where agents-cli syncs OpenCode resources.
|
|
286
|
+
export OPENCODE_CONFIG_DIR="$VERSION_DIR/home/.config/opencode"
|
|
287
|
+
`
|
|
288
|
+
: agent === 'kimi'
|
|
289
|
+
? `
|
|
283
290
|
# Kimi Code CLI honors KIMI_CODE_HOME to relocate ~/.kimi-code (config.toml,
|
|
284
291
|
# mcp.json, sessions, skills, hooks). Point it at the versioned home.
|
|
285
292
|
export KIMI_CODE_HOME="$VERSION_DIR/home/${configDirName}"
|
|
286
293
|
`
|
|
287
|
-
|
|
294
|
+
: '';
|
|
288
295
|
const launchArgs = agent === 'codex' ? ' -c check_for_update_on_startup=false' : '';
|
|
289
296
|
return `#!/bin/bash
|
|
290
297
|
# Auto-generated by agents-cli - do not edit
|
|
@@ -867,7 +874,7 @@ function assertSafeVersion(version) {
|
|
|
867
874
|
* KEEP IN SYNC with the `managedEnv` switch in `generateVersionedAliasScript`.
|
|
868
875
|
* The colocated test `shims.isolation-capability.test.ts` enforces this.
|
|
869
876
|
*/
|
|
870
|
-
export const CONFIG_ENV_ISOLATED_AGENTS = ['claude', 'codex', 'copilot', 'grok', 'kimi'];
|
|
877
|
+
export const CONFIG_ENV_ISOLATED_AGENTS = ['claude', 'codex', 'copilot', 'grok', 'kimi', 'opencode'];
|
|
871
878
|
/**
|
|
872
879
|
* Whether an agent supports a clean `--isolated` install — i.e. its config
|
|
873
880
|
* location can be redirected by an env var so the isolated copy stays fully
|
|
@@ -912,13 +919,20 @@ export COPILOT_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${
|
|
|
912
919
|
# aliases at the versioned home for isolation parity with the main shim.
|
|
913
920
|
export GROK_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${configDirName}"
|
|
914
921
|
`
|
|
915
|
-
: agent === '
|
|
922
|
+
: agent === 'opencode'
|
|
916
923
|
? `
|
|
924
|
+
# OpenCode reads plugins, agents, commands, and other config-directory
|
|
925
|
+
# resources from OPENCODE_CONFIG_DIR. Point direct aliases at the versioned
|
|
926
|
+
# global config tree where agents-cli syncs OpenCode resources.
|
|
927
|
+
export OPENCODE_CONFIG_DIR="$HOME/.agents/.history/versions/${agent}/${version}/home/.config/opencode"
|
|
928
|
+
`
|
|
929
|
+
: agent === 'kimi'
|
|
930
|
+
? `
|
|
917
931
|
# Kimi Code CLI honors KIMI_CODE_HOME to relocate ~/.kimi-code (config.toml,
|
|
918
932
|
# mcp.json, sessions, skills, hooks). Point direct aliases at the versioned home.
|
|
919
933
|
export KIMI_CODE_HOME="$HOME/.agents/.history/versions/${agent}/${version}/home/${configDirName}"
|
|
920
934
|
`
|
|
921
|
-
|
|
935
|
+
: '';
|
|
922
936
|
const launchArgs = agent === 'codex' ? ' -c check_for_update_on_startup=false' : '';
|
|
923
937
|
// Resolve the binary the same way the main shim does (see generateShimScript).
|
|
924
938
|
// Grok and Droid do NOT ship into node_modules/.bin — Grok downloads a native
|
package/dist/lib/sqlite.d.ts
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,
|
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';
|
|
@@ -57,6 +57,7 @@ export declare const loadApply: ModuleLoader;
|
|
|
57
57
|
export declare const loadCheck: ModuleLoader;
|
|
58
58
|
export declare const loadStatus: ModuleLoader;
|
|
59
59
|
export declare const loadProfiles: ModuleLoader;
|
|
60
|
+
export declare const loadHarness: ModuleLoader;
|
|
60
61
|
export declare const loadSecrets: ModuleLoader;
|
|
61
62
|
export declare const loadLogin: ModuleLoader;
|
|
62
63
|
export declare const loadWallet: ModuleLoader;
|
|
@@ -35,6 +35,7 @@ export const loadApply = async () => (await import('../../commands/apply.js')).r
|
|
|
35
35
|
export const loadCheck = async () => (await import('../../commands/check.js')).registerCheckCommand;
|
|
36
36
|
export const loadStatus = async () => (await import('../../commands/status.js')).registerStatusCommand;
|
|
37
37
|
export const loadProfiles = async () => (await import('../../commands/profiles.js')).registerProfilesCommands;
|
|
38
|
+
export const loadHarness = async () => (await import('../../commands/harness.js')).registerHarnessCommands;
|
|
38
39
|
export const loadSecrets = async () => (await import('../../commands/secrets.js')).registerSecretsCommands;
|
|
39
40
|
export const loadLogin = async () => (await import('../../commands/login.js')).registerLoginCommands;
|
|
40
41
|
export const loadWallet = async () => (await import('../../commands/wallet.js')).registerWalletCommands;
|
|
@@ -146,6 +147,8 @@ export const COMMAND_LOADERS = {
|
|
|
146
147
|
status: [loadStatus],
|
|
147
148
|
profile: [loadProfiles],
|
|
148
149
|
profiles: [loadProfiles],
|
|
150
|
+
harness: [loadHarness],
|
|
151
|
+
harnesses: [loadHarness],
|
|
149
152
|
secrets: [loadSecrets],
|
|
150
153
|
login: [loadLogin],
|
|
151
154
|
logout: [loadLogin],
|
package/dist/lib/state.d.ts
CHANGED
|
@@ -121,9 +121,13 @@ export declare function getSystemRoutinesDir(): string;
|
|
|
121
121
|
* Path to a project-scoped routines directory (`<project>/.agents/routines/`),
|
|
122
122
|
* or null when no project `.agents/` is found by walking up from cwd.
|
|
123
123
|
*
|
|
124
|
-
* Project routines participate in `list`/`view
|
|
125
|
-
*
|
|
126
|
-
* routines)
|
|
124
|
+
* Project routines participate in `list`/`view` for inspection always. Daemon
|
|
125
|
+
* firing requires an explicit opt-in via `agents routines enable-project`
|
|
126
|
+
* (writes `meta.routines.projects`); after opt-in, `agents routines sync`
|
|
127
|
+
* materialises them into the user layer with `source:` provenance so the
|
|
128
|
+
* daemon (which loads user + system only) can fire them safely. A project's
|
|
129
|
+
* own `agents.yaml` `routines.enable: true` is a documentation signal only —
|
|
130
|
+
* it does not auto-enable firing. See `lib/routines-project.ts`.
|
|
127
131
|
*/
|
|
128
132
|
export declare function getProjectRoutinesDir(cwd?: string): string | null;
|
|
129
133
|
/** Path to routine execution logs (~/.agents/.history/runs/). */
|
|
@@ -165,7 +169,7 @@ export declare function getDriveDir(): string;
|
|
|
165
169
|
export declare function getTrashDir(): string;
|
|
166
170
|
/** Path to local session indexer storage (~/.agents/.history/sessions/). */
|
|
167
171
|
export declare function getSessionsDir(): string;
|
|
168
|
-
/** Path to the session index database (~/.agents/.history/sessions.db). */
|
|
172
|
+
/** Path to the session index database (~/.agents/.history/sessions/sessions.db). */
|
|
169
173
|
export declare function getSessionsDbPath(): string;
|
|
170
174
|
/** Path to teams config + registry (~/.agents/teams/). */
|
|
171
175
|
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
|
/**
|
|
@@ -320,9 +319,13 @@ export function getSystemRoutinesDir() { return SYSTEM_ROUTINES_DIR; }
|
|
|
320
319
|
* Path to a project-scoped routines directory (`<project>/.agents/routines/`),
|
|
321
320
|
* or null when no project `.agents/` is found by walking up from cwd.
|
|
322
321
|
*
|
|
323
|
-
* Project routines participate in `list`/`view
|
|
324
|
-
*
|
|
325
|
-
* routines)
|
|
322
|
+
* Project routines participate in `list`/`view` for inspection always. Daemon
|
|
323
|
+
* firing requires an explicit opt-in via `agents routines enable-project`
|
|
324
|
+
* (writes `meta.routines.projects`); after opt-in, `agents routines sync`
|
|
325
|
+
* materialises them into the user layer with `source:` provenance so the
|
|
326
|
+
* daemon (which loads user + system only) can fire them safely. A project's
|
|
327
|
+
* own `agents.yaml` `routines.enable: true` is a documentation signal only —
|
|
328
|
+
* it does not auto-enable firing. See `lib/routines-project.ts`.
|
|
326
329
|
*/
|
|
327
330
|
export function getProjectRoutinesDir(cwd = process.cwd()) {
|
|
328
331
|
const projectAgentsDir = getProjectAgentsDir(cwd);
|
|
@@ -376,7 +379,7 @@ export function getDriveDir() { return DRIVE_DIR; }
|
|
|
376
379
|
export function getTrashDir() { return TRASH_DIR; }
|
|
377
380
|
/** Path to local session indexer storage (~/.agents/.history/sessions/). */
|
|
378
381
|
export function getSessionsDir() { return SESSIONS_DIR; }
|
|
379
|
-
/** Path to the session index database (~/.agents/.history/sessions.db). */
|
|
382
|
+
/** Path to the session index database (~/.agents/.history/sessions/sessions.db). */
|
|
380
383
|
export function getSessionsDbPath() { return SESSIONS_DB_PATH; }
|
|
381
384
|
/** Path to teams config + registry (~/.agents/teams/). */
|
|
382
385
|
export function getTeamsDir() { return TEAMS_DIR; }
|
|
@@ -384,10 +387,21 @@ export function getTeamsDir() { return TEAMS_DIR; }
|
|
|
384
387
|
export function getTeamsAgentsDir() { return TEAMS_AGENTS_DIR; }
|
|
385
388
|
/** Path to the team registry — list of named teams with timestamps. Durable runtime, per-machine. */
|
|
386
389
|
export function getTeamsRegistryPath() { return path.join(HISTORY_DIR, 'teams', 'registry.json'); }
|
|
390
|
+
/**
|
|
391
|
+
* The devices dir (registry + ignore-list live here). Read at CALL time so a
|
|
392
|
+
* test can redirect it to a temp dir via AGENTS_DEVICES_DIR without racing the
|
|
393
|
+
* module-load capture of HISTORY_DIR — mirrors the AGENTS_EVENTS_PATH /
|
|
394
|
+
* AGENTS_SECRETS_AGENT_DIR test-isolation escape hatches. Never set in
|
|
395
|
+
* production code; it exists so the vitest fork's device-registry writes can
|
|
396
|
+
* never reach the user's real ~/.agents/.history/devices (RUSH-2042).
|
|
397
|
+
*/
|
|
398
|
+
function getDevicesDir() {
|
|
399
|
+
return process.env.AGENTS_DEVICES_DIR ?? path.join(HISTORY_DIR, 'devices');
|
|
400
|
+
}
|
|
387
401
|
/** Path to the device registry — SSH device profiles with platform/auth metadata. Durable runtime, per-machine (host list + addresses are NOT pulled by `agents repo push`). */
|
|
388
|
-
export function getDevicesRegistryPath() { return path.join(
|
|
402
|
+
export function getDevicesRegistryPath() { return path.join(getDevicesDir(), 'registry.json'); }
|
|
389
403
|
/** Path to the device ignore-list — tailscale node names the user dismissed, so auto-discovery never re-suggests them. Per-machine, same dir as the registry. */
|
|
390
|
-
export function getDevicesIgnoredPath() { return path.join(
|
|
404
|
+
export function getDevicesIgnoredPath() { return path.join(getDevicesDir(), 'ignored.json'); }
|
|
391
405
|
/** Dir of "pending device" sentinels (~/.agents/.cache/state/devices-pending/) — one empty-ish file per newly-discovered, not-yet-approved tailnet node. Written by the daemon probe, read by the menu-bar helper (mirrors the attention sentinel dir). */
|
|
392
406
|
export function getDevicesPendingDir() { return path.join(RUNTIME_STATE_DIR, 'devices-pending'); }
|
|
393
407
|
/** Path to cloud dispatch cache (~/.agents/.cache/cloud/). */
|
|
@@ -680,29 +694,6 @@ function overlayMachineLocal(meta) {
|
|
|
680
694
|
}
|
|
681
695
|
return meta;
|
|
682
696
|
}
|
|
683
|
-
function applyRegistrySeeds(meta) {
|
|
684
|
-
const seeded = new Set(meta.seededPresets || []);
|
|
685
|
-
let changed = false;
|
|
686
|
-
for (const [type, presets] of Object.entries(SEEDED_REGISTRIES)) {
|
|
687
|
-
for (const [name, config] of Object.entries(presets)) {
|
|
688
|
-
const key = `${type}.${name}`;
|
|
689
|
-
if (seeded.has(key))
|
|
690
|
-
continue;
|
|
691
|
-
if (!meta.registries)
|
|
692
|
-
meta.registries = { mcp: {}, skill: {} };
|
|
693
|
-
if (!meta.registries[type])
|
|
694
|
-
meta.registries[type] = {};
|
|
695
|
-
if (!meta.registries[type][name]) {
|
|
696
|
-
meta.registries[type][name] = { ...config };
|
|
697
|
-
}
|
|
698
|
-
seeded.add(key);
|
|
699
|
-
changed = true;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
if (changed)
|
|
703
|
-
meta.seededPresets = [...seeded];
|
|
704
|
-
return changed;
|
|
705
|
-
}
|
|
706
697
|
/**
|
|
707
698
|
* One-shot migration: move agents.yaml from system repo to user repo.
|
|
708
699
|
* Idempotent — no-ops if user file already exists or system file absent.
|
|
@@ -813,17 +804,10 @@ export function readMeta() {
|
|
|
813
804
|
};
|
|
814
805
|
}
|
|
815
806
|
overlayMachineLocal(meta);
|
|
816
|
-
if (applyRegistrySeeds(meta)) {
|
|
817
|
-
writeMeta(meta);
|
|
818
|
-
return rememberMeta(meta);
|
|
819
|
-
}
|
|
820
807
|
return rememberMeta(meta);
|
|
821
808
|
}
|
|
822
809
|
const meta = createDefaultMeta();
|
|
823
810
|
overlayMachineLocal(meta);
|
|
824
|
-
if (applyRegistrySeeds(meta)) {
|
|
825
|
-
writeMeta(meta);
|
|
826
|
-
}
|
|
827
811
|
return rememberMeta(meta);
|
|
828
812
|
}
|
|
829
813
|
/** Serialize and write agents.yaml to the user repo, invalidating the in-memory cache. */
|