@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.
Files changed (231) hide show
  1. package/CHANGELOG.md +1055 -0
  2. package/README.md +36 -10
  3. package/dist/bin/agents +0 -0
  4. package/dist/commands/apply.js +21 -3
  5. package/dist/commands/attach.d.ts +10 -0
  6. package/dist/commands/attach.js +41 -0
  7. package/dist/commands/computer.js +3 -3
  8. package/dist/commands/detach-core.d.ts +46 -0
  9. package/dist/commands/detach-core.js +61 -0
  10. package/dist/commands/detach.d.ts +5 -0
  11. package/dist/commands/detach.js +171 -0
  12. package/dist/commands/doctor.js +18 -0
  13. package/dist/commands/exec.js +83 -13
  14. package/dist/commands/feed.d.ts +7 -1
  15. package/dist/commands/feed.js +47 -4
  16. package/dist/commands/go.d.ts +9 -2
  17. package/dist/commands/go.js +16 -6
  18. package/dist/commands/harness.d.ts +14 -0
  19. package/dist/commands/harness.js +145 -0
  20. package/dist/commands/import.js +38 -8
  21. package/dist/commands/inspect.js +5 -2
  22. package/dist/commands/profiles.d.ts +20 -0
  23. package/dist/commands/profiles.js +68 -21
  24. package/dist/commands/repo.js +14 -0
  25. package/dist/commands/routines.js +286 -15
  26. package/dist/commands/secrets.js +102 -37
  27. package/dist/commands/sessions-browser.js +12 -2
  28. package/dist/commands/sessions-export.js +19 -5
  29. package/dist/commands/sessions-migrate.d.ts +29 -0
  30. package/dist/commands/sessions-migrate.js +596 -0
  31. package/dist/commands/sessions-picker.d.ts +14 -1
  32. package/dist/commands/sessions-picker.js +184 -16
  33. package/dist/commands/sessions.d.ts +56 -14
  34. package/dist/commands/sessions.js +322 -62
  35. package/dist/commands/setup-computer.js +2 -2
  36. package/dist/commands/ssh.d.ts +13 -0
  37. package/dist/commands/ssh.js +110 -37
  38. package/dist/commands/status.js +10 -2
  39. package/dist/commands/versions.js +15 -6
  40. package/dist/commands/view.d.ts +5 -0
  41. package/dist/commands/view.js +24 -4
  42. package/dist/commands/watchdog.d.ts +7 -2
  43. package/dist/commands/watchdog.js +73 -57
  44. package/dist/index.js +59 -7
  45. package/dist/lib/activity.d.ts +17 -6
  46. package/dist/lib/activity.js +466 -40
  47. package/dist/lib/actor.d.ts +50 -0
  48. package/dist/lib/actor.js +166 -0
  49. package/dist/lib/agent-spec/provider.js +2 -1
  50. package/dist/lib/agent-spec/resolve.js +19 -5
  51. package/dist/lib/agent-spec/types.d.ts +9 -1
  52. package/dist/lib/agents.d.ts +21 -0
  53. package/dist/lib/agents.js +70 -6
  54. package/dist/lib/cloud/codex.d.ts +2 -0
  55. package/dist/lib/cloud/codex.js +14 -3
  56. package/dist/lib/cloud/session-index.d.ts +32 -0
  57. package/dist/lib/cloud/session-index.js +58 -0
  58. package/dist/lib/cloud/store.d.ts +7 -0
  59. package/dist/lib/cloud/store.js +25 -0
  60. package/dist/lib/config-transfer.js +4 -0
  61. package/dist/lib/daemon.d.ts +10 -1
  62. package/dist/lib/daemon.js +114 -11
  63. package/dist/lib/devices/connect.d.ts +15 -1
  64. package/dist/lib/devices/connect.js +15 -1
  65. package/dist/lib/devices/fleet.d.ts +37 -1
  66. package/dist/lib/devices/fleet.js +36 -2
  67. package/dist/lib/devices/health-report.d.ts +38 -0
  68. package/dist/lib/devices/health-report.js +214 -0
  69. package/dist/lib/devices/health.js +4 -1
  70. package/dist/lib/devices/reachability.d.ts +31 -0
  71. package/dist/lib/devices/reachability.js +40 -0
  72. package/dist/lib/devices/registry.d.ts +33 -0
  73. package/dist/lib/devices/registry.js +37 -0
  74. package/dist/lib/devices/resolve-target.d.ts +15 -27
  75. package/dist/lib/devices/resolve-target.js +63 -102
  76. package/dist/lib/devices/sync.d.ts +18 -0
  77. package/dist/lib/devices/sync.js +23 -1
  78. package/dist/lib/devices/tailscale.d.ts +3 -0
  79. package/dist/lib/devices/tailscale.js +1 -0
  80. package/dist/lib/events.d.ts +1 -1
  81. package/dist/lib/exec.d.ts +82 -0
  82. package/dist/lib/exec.js +218 -6
  83. package/dist/lib/feed-post.d.ts +63 -0
  84. package/dist/lib/feed-post.js +204 -0
  85. package/dist/lib/feed.d.ts +7 -1
  86. package/dist/lib/feed.js +96 -6
  87. package/dist/lib/fleet/apply.d.ts +32 -2
  88. package/dist/lib/fleet/apply.js +97 -10
  89. package/dist/lib/fleet/types.d.ts +11 -0
  90. package/dist/lib/fs-walk.d.ts +13 -0
  91. package/dist/lib/fs-walk.js +16 -7
  92. package/dist/lib/heal.d.ts +7 -4
  93. package/dist/lib/heal.js +10 -22
  94. package/dist/lib/hooks.d.ts +1 -0
  95. package/dist/lib/hooks.js +156 -0
  96. package/dist/lib/hosts/dispatch.d.ts +16 -0
  97. package/dist/lib/hosts/dispatch.js +26 -4
  98. package/dist/lib/hosts/passthrough.js +9 -2
  99. package/dist/lib/hosts/reconnect.d.ts +78 -0
  100. package/dist/lib/hosts/reconnect.js +127 -0
  101. package/dist/lib/hosts/registry.d.ts +75 -14
  102. package/dist/lib/hosts/registry.js +205 -30
  103. package/dist/lib/hosts/remote-cmd.d.ts +11 -0
  104. package/dist/lib/hosts/remote-cmd.js +32 -8
  105. package/dist/lib/hosts/remote-session-id.d.ts +45 -0
  106. package/dist/lib/hosts/remote-session-id.js +84 -0
  107. package/dist/lib/hosts/run-target.d.ts +17 -5
  108. package/dist/lib/hosts/run-target.js +30 -10
  109. package/dist/lib/hosts/session-index.d.ts +18 -1
  110. package/dist/lib/hosts/session-index.js +40 -5
  111. package/dist/lib/hosts/session-marker.d.ts +33 -0
  112. package/dist/lib/hosts/session-marker.js +51 -0
  113. package/dist/lib/hosts/tasks.d.ts +8 -4
  114. package/dist/lib/import.d.ts +2 -0
  115. package/dist/lib/import.js +35 -2
  116. package/dist/lib/menubar/install-menubar.d.ts +29 -0
  117. package/dist/lib/menubar/install-menubar.js +59 -1
  118. package/dist/lib/menubar/notify-desktop.d.ts +44 -0
  119. package/dist/lib/menubar/notify-desktop.js +78 -0
  120. package/dist/lib/migrate.d.ts +16 -0
  121. package/dist/lib/migrate.js +36 -0
  122. package/dist/lib/models.d.ts +27 -0
  123. package/dist/lib/models.js +54 -1
  124. package/dist/lib/overdue.d.ts +6 -2
  125. package/dist/lib/overdue.js +10 -36
  126. package/dist/lib/picker.js +4 -1
  127. package/dist/lib/platform/process.d.ts +17 -0
  128. package/dist/lib/platform/process.js +70 -0
  129. package/dist/lib/profiles-presets.js +9 -7
  130. package/dist/lib/profiles.d.ts +31 -0
  131. package/dist/lib/profiles.js +70 -0
  132. package/dist/lib/pty-server.d.ts +2 -10
  133. package/dist/lib/pty-server.js +4 -38
  134. package/dist/lib/registry.d.ts +1 -1
  135. package/dist/lib/registry.js +48 -8
  136. package/dist/lib/rotate.d.ts +18 -0
  137. package/dist/lib/rotate.js +28 -0
  138. package/dist/lib/routine-notify.d.ts +76 -0
  139. package/dist/lib/routine-notify.js +190 -0
  140. package/dist/lib/routines-placement.d.ts +38 -0
  141. package/dist/lib/routines-placement.js +79 -0
  142. package/dist/lib/routines-project.d.ts +97 -0
  143. package/dist/lib/routines-project.js +349 -0
  144. package/dist/lib/routines.d.ts +94 -0
  145. package/dist/lib/routines.js +93 -9
  146. package/dist/lib/runner.d.ts +12 -2
  147. package/dist/lib/runner.js +242 -20
  148. package/dist/lib/sandbox.js +10 -0
  149. package/dist/lib/secrets/account-token.d.ts +20 -0
  150. package/dist/lib/secrets/account-token.js +64 -0
  151. package/dist/lib/secrets/agent.d.ts +74 -4
  152. package/dist/lib/secrets/agent.js +181 -107
  153. package/dist/lib/secrets/bundles.d.ts +54 -6
  154. package/dist/lib/secrets/bundles.js +230 -34
  155. package/dist/lib/secrets/index.d.ts +26 -3
  156. package/dist/lib/secrets/index.js +42 -12
  157. package/dist/lib/secrets/rc-hygiene.d.ts +55 -0
  158. package/dist/lib/secrets/rc-hygiene.js +154 -0
  159. package/dist/lib/secrets/remote.d.ts +7 -4
  160. package/dist/lib/secrets/remote.js +7 -4
  161. package/dist/lib/secrets/session-store.d.ts +6 -2
  162. package/dist/lib/secrets/session-store.js +65 -15
  163. package/dist/lib/secrets/sync-commands.d.ts +21 -0
  164. package/dist/lib/secrets/sync-commands.js +21 -0
  165. package/dist/lib/secrets/unlock-hints.d.ts +27 -0
  166. package/dist/lib/secrets/unlock-hints.js +36 -0
  167. package/dist/lib/self-update.d.ts +23 -2
  168. package/dist/lib/self-update.js +86 -5
  169. package/dist/lib/session/active.d.ts +124 -7
  170. package/dist/lib/session/active.js +390 -56
  171. package/dist/lib/session/cloud.js +2 -1
  172. package/dist/lib/session/db.d.ts +54 -0
  173. package/dist/lib/session/db.js +320 -19
  174. package/dist/lib/session/detached.d.ts +30 -0
  175. package/dist/lib/session/detached.js +92 -0
  176. package/dist/lib/session/discover.d.ts +478 -3
  177. package/dist/lib/session/discover.js +1740 -472
  178. package/dist/lib/session/fork.js +2 -1
  179. package/dist/lib/session/hook-sessions.d.ts +43 -0
  180. package/dist/lib/session/hook-sessions.js +135 -0
  181. package/dist/lib/session/linear.d.ts +6 -0
  182. package/dist/lib/session/linear.js +55 -0
  183. package/dist/lib/session/migrate-targets.d.ts +65 -0
  184. package/dist/lib/session/migrate-targets.js +94 -0
  185. package/dist/lib/session/migrations.d.ts +37 -0
  186. package/dist/lib/session/migrations.js +60 -0
  187. package/dist/lib/session/parse.d.ts +18 -0
  188. package/dist/lib/session/parse.js +141 -32
  189. package/dist/lib/session/pid-registry.d.ts +34 -2
  190. package/dist/lib/session/pid-registry.js +49 -2
  191. package/dist/lib/session/prompt.d.ts +7 -0
  192. package/dist/lib/session/prompt.js +37 -0
  193. package/dist/lib/session/provenance.d.ts +7 -0
  194. package/dist/lib/session/render.d.ts +7 -2
  195. package/dist/lib/session/render.js +40 -26
  196. package/dist/lib/session/short-id.d.ts +17 -0
  197. package/dist/lib/session/short-id.js +20 -0
  198. package/dist/lib/session/state.d.ts +4 -0
  199. package/dist/lib/session/state.js +99 -13
  200. package/dist/lib/session/types.d.ts +25 -1
  201. package/dist/lib/session/types.js +8 -0
  202. package/dist/lib/shims.d.ts +1 -1
  203. package/dist/lib/shims.js +20 -6
  204. package/dist/lib/sqlite.d.ts +3 -2
  205. package/dist/lib/sqlite.js +27 -4
  206. package/dist/lib/staleness/detectors/commands.js +1 -1
  207. package/dist/lib/staleness/detectors/workflows.js +13 -2
  208. package/dist/lib/staleness/writers/commands.js +7 -7
  209. package/dist/lib/staleness/writers/workflows.d.ts +4 -2
  210. package/dist/lib/startup/command-registry.d.ts +1 -0
  211. package/dist/lib/startup/command-registry.js +3 -0
  212. package/dist/lib/state.d.ts +8 -4
  213. package/dist/lib/state.js +21 -37
  214. package/dist/lib/teams/agents.d.ts +19 -10
  215. package/dist/lib/teams/agents.js +40 -39
  216. package/dist/lib/types.d.ts +47 -2
  217. package/dist/lib/usage.d.ts +33 -1
  218. package/dist/lib/usage.js +172 -12
  219. package/dist/lib/versions.d.ts +9 -2
  220. package/dist/lib/versions.js +37 -8
  221. package/dist/lib/watchdog/log.d.ts +43 -0
  222. package/dist/lib/watchdog/log.js +69 -0
  223. package/dist/lib/watchdog/routine.d.ts +44 -0
  224. package/dist/lib/watchdog/routine.js +69 -0
  225. package/dist/lib/watchdog/runner.d.ts +51 -7
  226. package/dist/lib/watchdog/runner.js +239 -64
  227. package/dist/lib/watchdog/watchdog.d.ts +1 -1
  228. package/dist/lib/watchdog/watchdog.js +31 -16
  229. package/dist/lib/workflows.d.ts +16 -0
  230. package/dist/lib/workflows.js +110 -1
  231. 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
- /** The live plan/checklist tools: Claude's `TodoWrite` and Codex's `update_plan`. */
51
- const TODO_TOOL = 'TodoWrite';
52
- const CODEX_PLAN_TOOL = 'update_plan';
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 raw = Array.isArray(args?.todos)
62
- ? args.todos
63
- : Array.isArray(args?.plan)
64
- ? args.plan
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
- items.push(activeForm ? { content, status, activeForm } : { content, status });
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 most recent TodoWrite's checklist (RUSH-1380). Attached
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 lastTodo = lastOf(meaningful, e => e.type === 'tool_use' && (e.tool === TODO_TOOL || e.tool === CODEX_PLAN_TOOL));
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). Unknown mtime keeps the question.
382
- const questionFresh = ctx.mtimeMs == null || Date.now() - ctx.mtimeMs < PROSE_QUESTION_FRESH_MS;
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, as Claude's `TodoWrite` (`content`) or Codex's `update_plan` (`step`) emits it. */
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
+ }
@@ -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 = 26;
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 = 26;
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 === 'kimi'
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 === 'kimi'
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
@@ -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 when the same source runs in tests (Bun) and
7
- * production (Node).
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,
@@ -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 when the same source runs in tests (Bun) and
7
- * production (Node).
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. Pass an object through unchanged so callers using named binds work.
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 (grok, kimi, Codex >= 0.117.0, …); falls back to scanning
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 `{versionHome}/workflows/` for subdirectories
3
- * containing WORKFLOW.md. Mirrors versions.ts:551-558.
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 grok (no native commands, but skills/) and Codex
8
- * >= 0.117.0 (commands capability ends, skills capability remains).
9
- * Writes `{agentDir}/skills/<name>/SKILL.md` with the `agents_command`
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 (grok, codex >= 0.117.0)
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 (grok, kimi, …). Opt out only agents with their own
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 directory into
3
- * `<versionHome>/workflows/<name>/` via `syncWorkflowToVersion`.
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],
@@ -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`/`run` for inspection but are
125
- * NOT fired by the daemon (which runs from $HOME and loads only user + system
126
- * routines). Opt-in firing for project routines is tracked as a follow-up.
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`/`run` for inspection but are
324
- * NOT fired by the daemon (which runs from $HOME and loads only user + system
325
- * routines). Opt-in firing for project routines is tracked as a follow-up.
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(HISTORY_DIR, 'devices', 'registry.json'); }
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(HISTORY_DIR, 'devices', 'ignored.json'); }
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. */