@phnx-labs/agents-cli 1.22.42 → 1.22.44

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 (256) hide show
  1. package/CHANGELOG.md +149 -0
  2. package/README.md +15 -13
  3. package/dist/bootstrap.js +33 -13
  4. package/dist/cli/command-registry.d.ts +0 -8
  5. package/dist/cli/command-registry.js +1 -25
  6. package/dist/commands/alias.d.ts +7 -4
  7. package/dist/commands/alias.js +33 -8
  8. package/dist/commands/apply.d.ts +7 -10
  9. package/dist/commands/apply.js +15 -35
  10. package/dist/commands/artifacts.js +4 -5
  11. package/dist/commands/audit.d.ts +6 -6
  12. package/dist/commands/audit.js +12 -12
  13. package/dist/commands/auth.js +14 -6
  14. package/dist/commands/beta.d.ts +7 -1
  15. package/dist/commands/beta.js +16 -9
  16. package/dist/commands/commands.js +1 -1
  17. package/dist/commands/computer.js +20 -6
  18. package/dist/commands/daemon.js +1 -1
  19. package/dist/commands/doctor.d.ts +4 -2
  20. package/dist/commands/doctor.js +21 -9
  21. package/dist/commands/events.d.ts +2 -2
  22. package/dist/commands/events.js +6 -5
  23. package/dist/commands/exec.d.ts +1 -1
  24. package/dist/commands/exec.js +11 -6
  25. package/dist/commands/factory.d.ts +1 -1
  26. package/dist/commands/feed.js +1 -30
  27. package/dist/commands/fleet-capture.d.ts +1 -1
  28. package/dist/commands/fleet-capture.js +4 -5
  29. package/dist/commands/harness.js +4 -52
  30. package/dist/commands/hooks.js +1 -1
  31. package/dist/commands/insights.d.ts +1 -1
  32. package/dist/commands/insights.js +3 -2
  33. package/dist/commands/menubar.js +58 -1
  34. package/dist/commands/monitors.js +1 -1
  35. package/dist/commands/org.d.ts +5 -0
  36. package/dist/commands/org.js +83 -29
  37. package/dist/commands/output.js +2 -2
  38. package/dist/commands/profiles.js +2 -2
  39. package/dist/commands/prune.js +5 -4
  40. package/dist/commands/routines.js +43 -25
  41. package/dist/commands/routines.test-fixture.d.ts +86 -0
  42. package/dist/commands/routines.test-fixture.js +345 -0
  43. package/dist/commands/sessions-picker.js +124 -122
  44. package/dist/commands/sessions.test-fixture.d.ts +24 -0
  45. package/dist/commands/sessions.test-fixture.js +224 -0
  46. package/dist/commands/setup.js +9 -1
  47. package/dist/commands/share.d.ts +9 -10
  48. package/dist/commands/share.js +68 -50
  49. package/dist/commands/skills.js +1 -1
  50. package/dist/commands/snapshot.d.ts +1 -1
  51. package/dist/commands/snapshot.js +4 -4
  52. package/dist/commands/ssh.js +15 -62
  53. package/dist/commands/status.d.ts +4 -2
  54. package/dist/commands/status.js +10 -7
  55. package/dist/commands/subagents.js +1 -1
  56. package/dist/commands/sync.d.ts +1 -0
  57. package/dist/commands/sync.js +29 -2
  58. package/dist/commands/view.js +11 -2
  59. package/dist/commands/webhook.js +1 -1
  60. package/dist/lib/accounting/rotate.d.ts +5 -3
  61. package/dist/lib/accounting/rotate.js +36 -7
  62. package/dist/lib/accounting/usage.d.ts +18 -4
  63. package/dist/lib/accounting/usage.js +138 -27
  64. package/dist/lib/agent-spec/agents.d.ts +7 -7
  65. package/dist/lib/agent-spec/agents.js +15 -15
  66. package/dist/lib/analytics/mix-commands.d.ts +6 -28
  67. package/dist/lib/analytics/mix-commands.js +14 -40
  68. package/dist/lib/audit/log.d.ts +2 -2
  69. package/dist/lib/audit/log.js +2 -2
  70. package/dist/lib/beta.js +1 -1
  71. package/dist/lib/browser/domain-skills.d.ts +26 -6
  72. package/dist/lib/browser/domain-skills.js +81 -43
  73. package/dist/lib/cloud/rush.d.ts +0 -15
  74. package/dist/lib/cloud/rush.js +0 -35
  75. package/dist/lib/crabbox/runtimes.d.ts +6 -2
  76. package/dist/lib/crabbox/runtimes.js +21 -5
  77. package/dist/lib/daemon/daemon.js +97 -58
  78. package/dist/lib/daemon/daemon.test-fixture.d.ts +24 -0
  79. package/dist/lib/daemon/daemon.test-fixture.js +71 -0
  80. package/dist/lib/daemon/runner.d.ts +18 -1
  81. package/dist/lib/daemon/runner.js +105 -11
  82. package/dist/lib/daemon-ticks.d.ts +38 -1
  83. package/dist/lib/daemon-ticks.js +52 -5
  84. package/dist/lib/device-config.js +1 -2
  85. package/dist/lib/devices/discovery-policy.d.ts +3 -3
  86. package/dist/lib/devices/discovery-policy.js +3 -3
  87. package/dist/lib/devices/doctor-findings.js +1 -1
  88. package/dist/lib/devices/fleet.d.ts +4 -8
  89. package/dist/lib/devices/fleet.js +3 -15
  90. package/dist/lib/devices/health-report.js +4 -4
  91. package/dist/lib/devices/pool.d.ts +0 -6
  92. package/dist/lib/devices/pool.js +0 -6
  93. package/dist/lib/devices/registry.d.ts +0 -15
  94. package/dist/lib/devices/registry.js +0 -9
  95. package/dist/lib/devices/stats-cache.d.ts +12 -0
  96. package/dist/lib/devices/stats-cache.js +24 -5
  97. package/dist/lib/drift-sync.d.ts +1 -1
  98. package/dist/lib/drift-sync.js +2 -2
  99. package/dist/lib/drift.d.ts +1 -1
  100. package/dist/lib/exec.js +13 -3
  101. package/dist/lib/fleet/capture.d.ts +1 -1
  102. package/dist/lib/fleet/manifest.js +1 -1
  103. package/dist/lib/fleet/remote-login.d.ts +2 -2
  104. package/dist/lib/fleet/remote-login.js +3 -4
  105. package/dist/lib/format.d.ts +9 -0
  106. package/dist/lib/format.js +16 -0
  107. package/dist/lib/github/pr-mergeable.d.ts +49 -0
  108. package/dist/lib/github/pr-mergeable.js +157 -0
  109. package/dist/lib/github/pr-verdict.d.ts +67 -0
  110. package/dist/lib/github/pr-verdict.js +72 -0
  111. package/dist/lib/harness/adapter.d.ts +6 -5
  112. package/dist/lib/hosts/dispatch.d.ts +2 -0
  113. package/dist/lib/hosts/dispatch.js +8 -1
  114. package/dist/lib/hosts/passthrough.d.ts +10 -0
  115. package/dist/lib/hosts/passthrough.js +28 -7
  116. package/dist/lib/hosts/providers/devices.js +1 -13
  117. package/dist/lib/hosts/ready.d.ts +12 -3
  118. package/dist/lib/hosts/ready.js +27 -12
  119. package/dist/lib/hosts/registry.d.ts +4 -5
  120. package/dist/lib/hosts/registry.js +3 -7
  121. package/dist/lib/hosts/session-index.js +1 -1
  122. package/dist/lib/installations/shims.js +1 -1
  123. package/dist/lib/installations/versions.d.ts +40 -0
  124. package/dist/lib/installations/versions.js +78 -4
  125. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +1 -5
  126. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  127. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -15
  128. package/dist/lib/menubar/install-menubar.d.ts +109 -0
  129. package/dist/lib/menubar/install-menubar.js +218 -12
  130. package/dist/lib/monitors/config.d.ts +2 -2
  131. package/dist/lib/monitors/config.js +3 -2
  132. package/dist/lib/origin-machine.d.ts +18 -0
  133. package/dist/lib/origin-machine.js +34 -0
  134. package/dist/lib/perf/db.js +1 -1
  135. package/dist/lib/perf/spool.js +1 -1
  136. package/dist/lib/prix-account.d.ts +2 -1
  137. package/dist/lib/prix-account.js +2 -1
  138. package/dist/lib/profiles.d.ts +7 -0
  139. package/dist/lib/profiles.js +26 -1
  140. package/dist/lib/remote-agents-json.js +1 -7
  141. package/dist/lib/routines-placement.d.ts +1 -1
  142. package/dist/lib/routines-placement.js +1 -1
  143. package/dist/lib/sandbox.d.ts +24 -0
  144. package/dist/lib/sandbox.js +101 -0
  145. package/dist/lib/scheduling/routines.d.ts +18 -9
  146. package/dist/lib/scheduling/routines.js +16 -8
  147. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  148. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -2
  149. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  150. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -13
  151. package/dist/lib/secrets/agent.js +9 -1
  152. package/dist/lib/secrets/index.js +1 -1
  153. package/dist/lib/secrets/list-filter.js +1 -1
  154. package/dist/lib/service-manifest.d.ts +20 -0
  155. package/dist/lib/service-manifest.js +34 -0
  156. package/dist/lib/session/active.d.ts +4 -16
  157. package/dist/lib/session/active.js +2 -6
  158. package/dist/lib/session/cloud.js +1 -1
  159. package/dist/lib/session/db.d.ts +13 -98
  160. package/dist/lib/session/db.js +5 -12
  161. package/dist/lib/session/discover.d.ts +5 -81
  162. package/dist/lib/session/discover.js +5 -5
  163. package/dist/lib/session/fork.js +1 -1
  164. package/dist/lib/session/live-metadata.js +1 -1
  165. package/dist/lib/session/origin-machine.d.ts +1 -18
  166. package/dist/lib/session/origin-machine.js +4 -34
  167. package/dist/lib/session/relative-time.d.ts +1 -44
  168. package/dist/lib/session/relative-time.js +4 -120
  169. package/dist/lib/session/remote/remote-bundle.d.ts +12 -0
  170. package/dist/lib/session/remote/remote-bundle.js +61 -0
  171. package/dist/lib/session/remote/remote-list.d.ts +148 -0
  172. package/dist/lib/session/remote/remote-list.js +607 -0
  173. package/dist/lib/session/remote/remote.d.ts +132 -0
  174. package/dist/lib/session/remote/remote.js +314 -0
  175. package/dist/lib/session/remote/watch.d.ts +101 -0
  176. package/dist/lib/session/remote/watch.js +241 -0
  177. package/dist/lib/session/remote-bundle.d.ts +1 -12
  178. package/dist/lib/session/remote-bundle.js +3 -61
  179. package/dist/lib/session/remote-list.d.ts +1 -148
  180. package/dist/lib/session/remote-list.js +3 -607
  181. package/dist/lib/session/remote.d.ts +1 -132
  182. package/dist/lib/session/remote.js +3 -314
  183. package/dist/lib/session/short-id.d.ts +1 -17
  184. package/dist/lib/session/short-id.js +4 -20
  185. package/dist/lib/session/watch.d.ts +1 -101
  186. package/dist/lib/session/watch.js +3 -242
  187. package/dist/lib/session/width.d.ts +1 -29
  188. package/dist/lib/session/width.js +4 -101
  189. package/dist/lib/share/config.d.ts +12 -2
  190. package/dist/lib/share/config.js +47 -11
  191. package/dist/lib/share/delete.js +1 -1
  192. package/dist/lib/share/publish.js +1 -1
  193. package/dist/lib/share/worker-template.js +2 -2
  194. package/dist/lib/smart-launch.d.ts +4 -4
  195. package/dist/lib/smart-launch.js +8 -18
  196. package/dist/lib/snapshot.d.ts +2 -2
  197. package/dist/lib/snapshot.js +1 -1
  198. package/dist/lib/staleness/index.d.ts +3 -1
  199. package/dist/lib/staleness/index.js +21 -1
  200. package/dist/lib/staleness/types.d.ts +11 -0
  201. package/dist/lib/staleness/writers/commands.js +13 -4
  202. package/dist/lib/staleness/writers/hooks.js +3 -1
  203. package/dist/lib/staleness/writers/mcp.d.ts +0 -7
  204. package/dist/lib/staleness/writers/mcp.js +16 -1
  205. package/dist/lib/staleness/writers/rules.js +1 -1
  206. package/dist/lib/staleness/writers/skills.js +3 -1
  207. package/dist/lib/staleness/writers/subagents.d.ts +0 -9
  208. package/dist/lib/staleness/writers/subagents.js +18 -1
  209. package/dist/lib/staleness/writers/types.d.ts +10 -0
  210. package/dist/lib/startup/command-registry.d.ts +10 -1
  211. package/dist/lib/startup/command-registry.js +26 -7
  212. package/dist/lib/startup/root-command.d.ts +18 -1
  213. package/dist/lib/startup/root-command.js +18 -1
  214. package/dist/lib/state.js +7 -0
  215. package/dist/lib/teams/placement-probe.js +28 -13
  216. package/dist/lib/teams/scheduler.d.ts +3 -1
  217. package/dist/lib/teams/scheduler.js +1 -1
  218. package/dist/lib/text/relative-time.d.ts +44 -0
  219. package/dist/lib/text/relative-time.js +120 -0
  220. package/dist/lib/text/short-id.d.ts +17 -0
  221. package/dist/lib/text/short-id.js +20 -0
  222. package/dist/lib/text/width.d.ts +29 -0
  223. package/dist/lib/text/width.js +101 -0
  224. package/dist/lib/triggers/handlers.d.ts +7 -0
  225. package/dist/lib/triggers/handlers.js +8 -0
  226. package/dist/lib/triggers/webhook.d.ts +1 -0
  227. package/dist/lib/triggers/webhook.js +2 -1
  228. package/dist/lib/types.d.ts +1 -1
  229. package/dist/lib/view-types.d.ts +7 -0
  230. package/package.json +2 -3
  231. package/dist/bin/agents +0 -0
  232. package/dist/commands/serve.d.ts +0 -10
  233. package/dist/commands/serve.js +0 -68
  234. package/dist/commands/tickets.d.ts +0 -2
  235. package/dist/commands/tickets.js +0 -43
  236. package/dist/commands/trends.d.ts +0 -10
  237. package/dist/commands/trends.js +0 -12
  238. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  239. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  240. package/dist/lib/observe-aliases.d.ts +0 -30
  241. package/dist/lib/observe-aliases.js +0 -38
  242. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  243. package/dist/lib/serve/control.d.ts +0 -95
  244. package/dist/lib/serve/control.js +0 -260
  245. package/dist/lib/serve/data.d.ts +0 -81
  246. package/dist/lib/serve/data.js +0 -91
  247. package/dist/lib/serve/page.d.ts +0 -7
  248. package/dist/lib/serve/page.js +0 -140
  249. package/dist/lib/serve/server.d.ts +0 -80
  250. package/dist/lib/serve/server.js +0 -145
  251. package/dist/lib/serve/stream.d.ts +0 -43
  252. package/dist/lib/serve/stream.js +0 -116
  253. package/dist/lib/serve/token.d.ts +0 -35
  254. package/dist/lib/serve/token.js +0 -85
  255. package/dist/lib/tickets/list.d.ts +0 -53
  256. package/dist/lib/tickets/list.js +0 -153
@@ -7,9 +7,8 @@
7
7
  * usage.db) still exists — it is now `agents insights mix` and the recipe
8
8
  * subcommands below. Latency stays on `agents perf`; quota on `agents usage`.
9
9
  *
10
- * `agents trends` remains a thin deprecated alias registered from
11
- * `commands/trends.ts` that shares this same registration no second copy of
12
- * the recipe tree.
10
+ * Former top-level `agents trends` is gone. The nested spelling
11
+ * `agents insights trends` is an alias of `agents insights mix`.
13
12
  */
14
13
  import type { Command } from 'commander';
15
14
  export declare function parseMixDays(raw: string | undefined): number;
@@ -19,35 +18,14 @@ export declare function printMixSection(section: {
19
18
  rows: Array<Record<string, string | number | null>>;
20
19
  }): void;
21
20
  export declare function renderMixDashboard(days: number, asJson: boolean, bannerLabel?: string): void;
22
- /** One-line deprecation for the retired top-level `agents trends` spelling. */
23
- export declare function printTrendsDeprecation(): void;
24
- export interface RegisterMixCommandsOptions {
25
- /**
26
- * When true, every action prints the trends deprecation line first. Used only
27
- * by the thin top-level `agents trends` alias — the real tree under insights
28
- * never sets this.
29
- */
30
- deprecated?: boolean;
31
- /**
32
- * Banner label for the multi-recipe dashboard (default: agents insights mix).
33
- * The deprecated alias passes `agents insights mix` still, so callers learn
34
- * the new name even when they typed trends.
35
- */
36
- dashboardBanner?: string;
37
- }
38
21
  /**
39
- * Attach counter-mix subcommands to a parent (typically `insights` or the
40
- * deprecated `trends` alias).
22
+ * Attach counter-mix subcommands to a parent (typically `insights`).
41
23
  *
42
24
  * Layout:
43
- * <parent> mix multi-recipe board (default for trends alias)
25
+ * <parent> mix multi-recipe board
26
+ * <parent> trends alias of mix (former top-level `agents trends`)
44
27
  * <parent> recipes list recipe ids
45
28
  * <parent> query raw usage.db rows
46
29
  * <parent> harness-mix|… one baked recipe
47
30
  */
48
- export declare function registerMixCommands(parent: Command, opts?: RegisterMixCommandsOptions): void;
49
- /**
50
- * Thin top-level `agents trends` alias: same mix tree, deprecation on every path,
51
- * default action = mix board (old `agents trends` with no subcommand).
52
- */
53
- export declare function registerDeprecatedTrendsAlias(program: Command): void;
31
+ export declare function registerMixCommands(parent: Command): void;
@@ -7,9 +7,8 @@
7
7
  * usage.db) still exists — it is now `agents insights mix` and the recipe
8
8
  * subcommands below. Latency stays on `agents perf`; quota on `agents usage`.
9
9
  *
10
- * `agents trends` remains a thin deprecated alias registered from
11
- * `commands/trends.ts` that shares this same registration no second copy of
12
- * the recipe tree.
10
+ * Former top-level `agents trends` is gone. The nested spelling
11
+ * `agents insights trends` is an alias of `agents insights mix`.
13
12
  */
14
13
  import chalk from 'chalk';
15
14
  import { setHelpSections } from '../help.js';
@@ -56,33 +55,24 @@ export function renderMixDashboard(days, asJson, bannerLabel = 'agents insights
56
55
  for (const section of dash.sections)
57
56
  printMixSection(section);
58
57
  }
59
- /** One-line deprecation for the retired top-level `agents trends` spelling. */
60
- export function printTrendsDeprecation() {
61
- console.error(chalk.yellow('agents trends is deprecated — use `agents insights mix` (or `agents insights <recipe>`).'));
62
- }
63
58
  /**
64
- * Attach counter-mix subcommands to a parent (typically `insights` or the
65
- * deprecated `trends` alias).
59
+ * Attach counter-mix subcommands to a parent (typically `insights`).
66
60
  *
67
61
  * Layout:
68
- * <parent> mix multi-recipe board (default for trends alias)
62
+ * <parent> mix multi-recipe board
63
+ * <parent> trends alias of mix (former top-level `agents trends`)
69
64
  * <parent> recipes list recipe ids
70
65
  * <parent> query raw usage.db rows
71
66
  * <parent> harness-mix|… one baked recipe
72
67
  */
73
- export function registerMixCommands(parent, opts = {}) {
74
- const before = () => {
75
- if (opts.deprecated)
76
- printTrendsDeprecation();
77
- };
78
- const banner = opts.dashboardBanner ?? 'agents insights mix';
68
+ export function registerMixCommands(parent) {
69
+ const banner = 'agents insights mix';
79
70
  const mix = parent
80
71
  .command('mix')
81
72
  .description('Counter recipes — harness/model mix, token ratios, resource frequency (sessions index + usage.db)')
82
73
  .option('--days <n>', 'Days of history to include', '7')
83
74
  .option('--json', 'Emit JSON instead of tables')
84
75
  .action(function summary() {
85
- before();
86
76
  const o = this.opts();
87
77
  renderMixDashboard(parseMixDays(o.days), Boolean(o.json), banner);
88
78
  });
@@ -115,7 +105,6 @@ export function registerMixCommands(parent, opts = {}) {
115
105
  .description('List baked mix-recipe ids')
116
106
  .option('--json', 'Emit JSON')
117
107
  .action((o) => {
118
- before();
119
108
  const list = listRecipes();
120
109
  if (o.json) {
121
110
  console.log(JSON.stringify(list, null, 2));
@@ -134,7 +123,6 @@ export function registerMixCommands(parent, opts = {}) {
134
123
  .option('--limit <n>', 'Max rows', '40')
135
124
  .option('--json', 'Emit JSON')
136
125
  .action((o) => {
137
- before();
138
126
  const win = analyticsWindow(parseMixDays(o.days));
139
127
  const kind = o.kind && USAGE_KINDS.includes(o.kind)
140
128
  ? o.kind
@@ -177,7 +165,6 @@ export function registerMixCommands(parent, opts = {}) {
177
165
  .option('--days <n>', 'Days of history', '7')
178
166
  .option('--json', 'Emit JSON')
179
167
  .action(function recipeAction() {
180
- before();
181
168
  const parentOpts = this.parent?.opts?.();
182
169
  const o = { ...parentOpts, ...this.opts() };
183
170
  const win = analyticsWindow(parseMixDays(o.days));
@@ -193,37 +180,24 @@ export function registerMixCommands(parent, opts = {}) {
193
180
  printMixSection(section);
194
181
  });
195
182
  }
196
- }
197
- /**
198
- * Thin top-level `agents trends` alias: same mix tree, deprecation on every path,
199
- * default action = mix board (old `agents trends` with no subcommand).
200
- */
201
- export function registerDeprecatedTrendsAlias(program) {
202
- const trends = program
183
+ // Nested home for the former top-level `agents trends` spelling.
184
+ const trends = parent
203
185
  .command('trends')
204
- .description('Deprecated alias of `agents insights mix` — counter recipes over sessions + usage.db')
186
+ .description('Alias of `mix` — former top-level `agents trends`')
205
187
  .option('--days <n>', 'Days of history to include', '7')
206
188
  .option('--json', 'Emit JSON instead of tables')
207
189
  .action(function summary() {
208
- printTrendsDeprecation();
209
190
  const o = this.opts();
210
- renderMixDashboard(parseMixDays(o.days), Boolean(o.json), 'agents insights mix');
191
+ renderMixDashboard(parseMixDays(o.days), Boolean(o.json), banner);
211
192
  });
212
193
  setHelpSections(trends, {
213
194
  examples: `
214
- # Prefer the canonical spelling
195
+ agents insights trends
215
196
  agents insights mix
216
-
217
- # Still works (prints a deprecation line)
218
- agents trends
219
- agents trends harness-mix --json
220
197
  `,
221
198
  notes: `
222
- \`agents trends\` is a compatibility alias. New code and agent briefs should use
223
- \`agents insights mix\` / \`agents insights <recipe>\`. Behavioural report remains
224
- bare \`agents insights\`. Latency remains \`agents perf\`.
199
+ \`agents insights trends\` is the nested spelling of the former top-level
200
+ \`agents trends\`. Prefer \`agents insights mix\`.
225
201
  `,
226
202
  });
227
- // Same subcommands as insights, with deprecation on every fire.
228
- registerMixCommands(trends, { deprecated: true, dashboardBanner: 'agents insights mix' });
229
203
  }
@@ -6,7 +6,7 @@
6
6
  * NOT append there. Operators list run outcomes with:
7
7
  *
8
8
  * agents events --include runs
9
- * agents audit # alias of the above
9
+ * agents events audit # nested alias of the above
10
10
  */
11
11
  /** First record's `prevHash` — a fixed anchor so the chain has a root. */
12
12
  export declare const GENESIS_HASH = "GENESIS";
@@ -59,7 +59,7 @@ export declare function verifyAuditChain(logPath?: string): {
59
59
  ok: boolean;
60
60
  brokenAt?: number;
61
61
  };
62
- /** Read the whole chain, oldest-first. Exposed for `agents audit list`. */
62
+ /** Read the whole chain, oldest-first. Exposed for `agents events audit verify`. */
63
63
  export declare function readAuditLog(logPath?: string): AuditRecord[];
64
64
  /**
65
65
  * Record ONE dispatched run at the single exec chokepoint into the unified
@@ -6,7 +6,7 @@
6
6
  * NOT append there. Operators list run outcomes with:
7
7
  *
8
8
  * agents events --include runs
9
- * agents audit # alias of the above
9
+ * agents events audit # nested alias of the above
10
10
  */
11
11
  import * as fs from 'fs';
12
12
  import * as path from 'path';
@@ -116,7 +116,7 @@ export function verifyAuditChain(logPath = getAuditLogPath()) {
116
116
  }
117
117
  return { ok: true };
118
118
  }
119
- /** Read the whole chain, oldest-first. Exposed for `agents audit list`. */
119
+ /** Read the whole chain, oldest-first. Exposed for `agents events audit verify`. */
120
120
  export function readAuditLog(logPath = getAuditLogPath()) {
121
121
  return readRecords(logPath);
122
122
  }
package/dist/lib/beta.js CHANGED
@@ -86,5 +86,5 @@ export function setBetaEnabled(features, enabled) {
86
86
  return { ...location, enabledFeatures };
87
87
  }
88
88
  export function betaEnableHint(feature) {
89
- return `Enable it with: agents beta enable ${feature}`;
89
+ return `Enable it with: agents setup beta enable ${feature}`;
90
90
  }
@@ -2,7 +2,9 @@
2
2
  * Domain-skill discovery for `agents browser start`.
3
3
  *
4
4
  * When a browser task opens a URL, look up a site-specific SKILL.md from
5
- * `~/.agents/skills/browser/domain-skills/<dir>/SKILL.md` and surface its
5
+ * `skills/browser/domain-skills/<dir>/SKILL.md` in the layered DotAgents
6
+ * repos — project > user > system, first layer with a match wins, the same
7
+ * precedence `resolveResource` in `../resources.ts` applies — and surface its
6
8
  * contents so the calling agent gets per-site operating instructions
7
9
  * (selectors, gotchas, sign-in quirks) before it starts driving the page.
8
10
  *
@@ -24,8 +26,21 @@ export interface ResolvedDomainSkill {
24
26
  /** Hostname the match was made against (post-www strip). */
25
27
  hostname: string;
26
28
  }
27
- /** Where domain-skills live. Override via $AGENTS_BROWSER_DOMAIN_SKILLS_DIR for tests. */
28
- export declare function domainSkillsRoot(): string;
29
+ /**
30
+ * Where domain-skills live, in precedence order: project > user > system >
31
+ * extra repos — the same layering `resolveResource` applies. A layer whose
32
+ * root does not exist is simply skipped at resolve time.
33
+ *
34
+ * The project layer resolves from `cwd` (default `process.cwd()`). The
35
+ * browser daemon is shared and long-lived, and its IPC request does not yet
36
+ * carry the calling CLI's cwd, so at that call site the project layer follows
37
+ * the daemon's own cwd until the caller's cwd is threaded through
38
+ * (RUSH-2996); user/system/extra-repo layers are cwd-independent.
39
+ *
40
+ * $AGENTS_BROWSER_DOMAIN_SKILLS_DIR overrides the whole list with a single
41
+ * root, for tests.
42
+ */
43
+ export declare function domainSkillsRoots(cwd?: string): string[];
29
44
  /**
30
45
  * Derive match candidates from a hostname. Order matters — earlier candidates
31
46
  * are tried first.
@@ -40,12 +55,17 @@ export declare function hostnameMatchCandidates(hostname: string): string[];
40
55
  /**
41
56
  * Resolve a URL to its matching domain-skill, or null if none.
42
57
  *
43
- * Two-pass strategy:
58
+ * Roots are searched in `domainSkillsRoots` order (project > user > system);
59
+ * the first layer with a match wins outright — an earlier layer's
60
+ * directory-name match beats a later layer's `domains:` pin, mirroring
61
+ * `resolveResource`'s layer precedence. Within one layer, two passes:
44
62
  * 1. Index every SKILL.md in the root and read its `domains:` frontmatter.
45
63
  * If any pinned domain matches a candidate, return that skill.
46
64
  * 2. Fall back to directory-name match against the candidate list.
47
65
  *
48
66
  * Errors (missing root, unreadable file, invalid URL) are swallowed and
49
- * yield null — domain-skill discovery must never break browser start.
67
+ * yield null — domain-skill discovery must never break browser start. A miss
68
+ * logs the roots searched at debug level (AGENTS_DEBUG/DEBUG) so a skill
69
+ * sitting in an unsearched layer is diagnosable rather than silent.
50
70
  */
51
- export declare function resolveDomainSkill(url: string): ResolvedDomainSkill | null;
71
+ export declare function resolveDomainSkill(url: string, cwd?: string): ResolvedDomainSkill | null;
@@ -2,7 +2,9 @@
2
2
  * Domain-skill discovery for `agents browser start`.
3
3
  *
4
4
  * When a browser task opens a URL, look up a site-specific SKILL.md from
5
- * `~/.agents/skills/browser/domain-skills/<dir>/SKILL.md` and surface its
5
+ * `skills/browser/domain-skills/<dir>/SKILL.md` in the layered DotAgents
6
+ * repos — project > user > system, first layer with a match wins, the same
7
+ * precedence `resolveResource` in `../resources.ts` applies — and surface its
6
8
  * contents so the calling agent gets per-site operating instructions
7
9
  * (selectors, gotchas, sign-in quirks) before it starts driving the page.
8
10
  *
@@ -14,14 +16,37 @@
14
16
  * the directory-name match.
15
17
  */
16
18
  import * as fs from 'fs';
17
- import * as os from 'os';
18
19
  import * as path from 'path';
19
- /** Where domain-skills live. Override via $AGENTS_BROWSER_DOMAIN_SKILLS_DIR for tests. */
20
- export function domainSkillsRoot() {
20
+ import { getEnabledExtraRepos, getProjectAgentsDir, getSystemAgentsDir, getUserAgentsDir, } from '../state.js';
21
+ /**
22
+ * Where domain-skills live, in precedence order: project > user > system >
23
+ * extra repos — the same layering `resolveResource` applies. A layer whose
24
+ * root does not exist is simply skipped at resolve time.
25
+ *
26
+ * The project layer resolves from `cwd` (default `process.cwd()`). The
27
+ * browser daemon is shared and long-lived, and its IPC request does not yet
28
+ * carry the calling CLI's cwd, so at that call site the project layer follows
29
+ * the daemon's own cwd until the caller's cwd is threaded through
30
+ * (RUSH-2996); user/system/extra-repo layers are cwd-independent.
31
+ *
32
+ * $AGENTS_BROWSER_DOMAIN_SKILLS_DIR overrides the whole list with a single
33
+ * root, for tests.
34
+ */
35
+ export function domainSkillsRoots(cwd) {
21
36
  const override = process.env.AGENTS_BROWSER_DOMAIN_SKILLS_DIR;
22
37
  if (override)
23
- return override;
24
- return path.join(os.homedir(), '.agents', 'skills', 'browser', 'domain-skills');
38
+ return [override];
39
+ const sub = ['skills', 'browser', 'domain-skills'];
40
+ const roots = [];
41
+ const projectDir = getProjectAgentsDir(cwd);
42
+ if (projectDir)
43
+ roots.push(path.join(projectDir, ...sub));
44
+ roots.push(path.join(getUserAgentsDir(), ...sub));
45
+ roots.push(path.join(getSystemAgentsDir(), ...sub));
46
+ for (const extra of getEnabledExtraRepos()) {
47
+ roots.push(path.join(extra.dir, ...sub));
48
+ }
49
+ return roots;
25
50
  }
26
51
  /**
27
52
  * Derive match candidates from a hostname. Order matters — earlier candidates
@@ -85,18 +110,28 @@ function parseDomainsFrontmatter(content) {
85
110
  }
86
111
  return [];
87
112
  }
113
+ /** Stderr debug line, gated on AGENTS_DEBUG/DEBUG — same convention as `../teams/debug.ts`. */
114
+ function debug(message) {
115
+ if (process.env.AGENTS_DEBUG || process.env.DEBUG)
116
+ console.error(message);
117
+ }
88
118
  /**
89
119
  * Resolve a URL to its matching domain-skill, or null if none.
90
120
  *
91
- * Two-pass strategy:
121
+ * Roots are searched in `domainSkillsRoots` order (project > user > system);
122
+ * the first layer with a match wins outright — an earlier layer's
123
+ * directory-name match beats a later layer's `domains:` pin, mirroring
124
+ * `resolveResource`'s layer precedence. Within one layer, two passes:
92
125
  * 1. Index every SKILL.md in the root and read its `domains:` frontmatter.
93
126
  * If any pinned domain matches a candidate, return that skill.
94
127
  * 2. Fall back to directory-name match against the candidate list.
95
128
  *
96
129
  * Errors (missing root, unreadable file, invalid URL) are swallowed and
97
- * yield null — domain-skill discovery must never break browser start.
130
+ * yield null — domain-skill discovery must never break browser start. A miss
131
+ * logs the roots searched at debug level (AGENTS_DEBUG/DEBUG) so a skill
132
+ * sitting in an unsearched layer is diagnosable rather than silent.
98
133
  */
99
- export function resolveDomainSkill(url) {
134
+ export function resolveDomainSkill(url, cwd) {
100
135
  let hostname;
101
136
  try {
102
137
  hostname = new URL(url).hostname;
@@ -106,52 +141,55 @@ export function resolveDomainSkill(url) {
106
141
  }
107
142
  if (!hostname)
108
143
  return null;
109
- const root = domainSkillsRoot();
110
- let entries;
111
- try {
112
- entries = fs.readdirSync(root, { withFileTypes: true });
113
- }
114
- catch {
115
- return null;
116
- }
117
144
  const candidates = hostnameMatchCandidates(hostname);
118
145
  if (candidates.length === 0)
119
146
  return null;
120
147
  const candidateSet = new Set(candidates);
121
- const indexed = [];
122
- for (const e of entries) {
123
- if (!e.isDirectory())
124
- continue;
125
- const skillPath = path.join(root, e.name, 'SKILL.md');
126
- let content;
148
+ const roots = domainSkillsRoots(cwd);
149
+ for (const root of roots) {
150
+ let entries;
127
151
  try {
128
- content = fs.readFileSync(skillPath, 'utf-8');
152
+ entries = fs.readdirSync(root, { withFileTypes: true });
129
153
  }
130
154
  catch {
131
155
  continue;
132
156
  }
133
- indexed.push({
134
- name: e.name,
135
- skillPath,
136
- content,
137
- pinned: parseDomainsFrontmatter(content),
138
- });
139
- }
140
- // Pass 1: explicit `domains:` overrides.
141
- for (const s of indexed) {
142
- for (const d of s.pinned) {
143
- if (candidateSet.has(d)) {
144
- return { name: s.name, path: s.skillPath, content: s.content, hostname };
157
+ const indexed = [];
158
+ for (const e of entries) {
159
+ if (!e.isDirectory())
160
+ continue;
161
+ const skillPath = path.join(root, e.name, 'SKILL.md');
162
+ let content;
163
+ try {
164
+ content = fs.readFileSync(skillPath, 'utf-8');
165
+ }
166
+ catch {
167
+ continue;
145
168
  }
169
+ indexed.push({
170
+ name: e.name,
171
+ skillPath,
172
+ content,
173
+ pinned: parseDomainsFrontmatter(content),
174
+ });
146
175
  }
147
- }
148
- // Pass 2: directory-name match, walking candidates in priority order.
149
- const byName = new Map(indexed.map((s) => [s.name.toLowerCase(), s]));
150
- for (const c of candidates) {
151
- const hit = byName.get(c);
152
- if (hit) {
153
- return { name: hit.name, path: hit.skillPath, content: hit.content, hostname };
176
+ // Pass 1: explicit `domains:` overrides.
177
+ for (const s of indexed) {
178
+ for (const d of s.pinned) {
179
+ if (candidateSet.has(d)) {
180
+ return { name: s.name, path: s.skillPath, content: s.content, hostname };
181
+ }
182
+ }
183
+ }
184
+ // Pass 2: directory-name match, walking candidates in priority order.
185
+ const byName = new Map(indexed.map((s) => [s.name.toLowerCase(), s]));
186
+ for (const c of candidates) {
187
+ const hit = byName.get(c);
188
+ if (hit) {
189
+ return { name: hit.name, path: hit.skillPath, content: hit.content, hostname };
190
+ }
154
191
  }
155
192
  }
193
+ debug(`[browser] no domain-skill for ${hostname}; searched: ${roots.join(', ')}`);
156
194
  return null;
157
195
  }
@@ -25,21 +25,6 @@ export interface AccountManifest {
25
25
  fp: string;
26
26
  versions: AccountManifestEntry[];
27
27
  }
28
- /**
29
- * Read the raw OAuth credentials for one Claude version. On Mac, prefer the
30
- * Keychain blob (canonical). On Linux/CI, fall back to `.claude/.credentials.json`
31
- * inside the version home (where the Linux Claude CLI stores its OAuth).
32
- *
33
- * Returns null when no credentials are findable — caller treats as "version
34
- * is installed but not signed in" and skips it from the manifest.
35
- *
36
- * NOTE: the darwin branch returns the UNWRAPPED oauth sub-object (what the Rush
37
- * server re-wraps). It is NOT the shape Claude Code reads back from
38
- * `.credentials.json`. The lease exporter (crabbox/runtimes.ts) therefore only
39
- * reuses the Linux `.credentials.json` branch here and reads the wrapped raw
40
- * Keychain payload itself on darwin.
41
- */
42
- export declare function readClaudeCredentialsBlob(home: string): Promise<string | null>;
43
28
  /**
44
29
  * Build a manifest of the user's local Claude installations to send on every
45
30
  * cloud dispatch. The manifest is the contract the server uses to detect when
@@ -13,7 +13,6 @@ import { resolveDispatchRepos, normalizeProviderStatus, MAX_IMAGES_PER_DISPATCH
13
13
  import { parseSSE } from './stream.js';
14
14
  import { listInstalledVersions, getVersionHomePath } from '../installations/versions.js';
15
15
  import { getAccountInfo } from '../agents.js';
16
- import { loadClaudeOauth } from '../accounting/usage.js';
17
16
  import { selectBalancedVersion } from '../accounting/rotate.js';
18
17
  const PROXY_BASE = process.env.RUSH_PROXY_BASE ?? 'https://api.prix.dev';
19
18
  const USER_YAML = path.join(os.homedir(), '.rush', 'user.yaml');
@@ -112,40 +111,6 @@ function parsePromptCode(body) {
112
111
  return null;
113
112
  }
114
113
  }
115
- /**
116
- * Read the raw OAuth credentials for one Claude version. On Mac, prefer the
117
- * Keychain blob (canonical). On Linux/CI, fall back to `.claude/.credentials.json`
118
- * inside the version home (where the Linux Claude CLI stores its OAuth).
119
- *
120
- * Returns null when no credentials are findable — caller treats as "version
121
- * is installed but not signed in" and skips it from the manifest.
122
- *
123
- * NOTE: the darwin branch returns the UNWRAPPED oauth sub-object (what the Rush
124
- * server re-wraps). It is NOT the shape Claude Code reads back from
125
- * `.credentials.json`. The lease exporter (crabbox/runtimes.ts) therefore only
126
- * reuses the Linux `.credentials.json` branch here and reads the wrapped raw
127
- * Keychain payload itself on darwin.
128
- */
129
- export async function readClaudeCredentialsBlob(home) {
130
- if (process.platform === 'darwin') {
131
- const oauth = await loadClaudeOauth(home);
132
- if (oauth && oauth.accessToken) {
133
- return JSON.stringify(oauth);
134
- }
135
- }
136
- const credsPath = path.join(home, '.claude', '.credentials.json');
137
- try {
138
- if (fs.existsSync(credsPath)) {
139
- const raw = fs.readFileSync(credsPath, 'utf-8').trim();
140
- if (raw)
141
- return raw;
142
- }
143
- }
144
- catch {
145
- // fall through to null
146
- }
147
- return null;
148
- }
149
114
  /**
150
115
  * Build a manifest of the user's local Claude installations to send on every
151
116
  * cloud dispatch. The manifest is the contract the server uses to detect when
@@ -85,8 +85,12 @@ export declare const CLAUDE_TOKEN_REMOTE = ".claude/.credentials.json";
85
85
  * versioned home) uses a hash-suffixed service, so we try the bare service first,
86
86
  * then enumerate installed version homes (preferring the account whose email
87
87
  * matches `preferEmail`, so the token matches the `.claude.json` config we copy).
88
- * Off macOS the local Claude CLI stores the token in `.credentials.json` already —
89
- * reuse the rush.ts Linux branch verbatim.
88
+ * Off macOS the local Claude CLI stores the wrapped rotating blob in
89
+ * `.credentials.json` already. Read that file here with a shape check
90
+ * (`claudeAiOauth.accessToken`). Do not reintroduce a shared helper that
91
+ * also serves Rush Cloud dispatch — dispatch is email-only (SING-1b) and
92
+ * the old `readClaudeCredentialsBlob` path was the #1767 TTY-banner leak
93
+ * (RUSH-2359).
90
94
  *
91
95
  * The reader/service/version helpers are injected so unit tests never touch the
92
96
  * real Keychain.
@@ -19,7 +19,6 @@ import { getAccountInfo } from '../agents.js';
19
19
  import { getKeychainToken } from '../secrets/index.js';
20
20
  import { getClaudeKeychainService } from '../accounting/usage.js';
21
21
  import { listInstalledVersions, getVersionHomePath } from '../installations/versions.js';
22
- import { readClaudeCredentialsBlob } from '../cloud/rush.js';
23
22
  export const LEASE_RUNTIMES = [
24
23
  { id: 'claude', label: 'Claude Code', localCandidates: ['.claude/.claude.json', '.claude.json'], remote: '.claude.json' },
25
24
  { id: 'codex', label: 'Codex CLI', localCandidates: ['.codex/auth.json'], remote: '.codex/auth.json' },
@@ -193,8 +192,12 @@ function isClaudeCredentialsBlob(s) {
193
192
  * versioned home) uses a hash-suffixed service, so we try the bare service first,
194
193
  * then enumerate installed version homes (preferring the account whose email
195
194
  * matches `preferEmail`, so the token matches the `.claude.json` config we copy).
196
- * Off macOS the local Claude CLI stores the token in `.credentials.json` already —
197
- * reuse the rush.ts Linux branch verbatim.
195
+ * Off macOS the local Claude CLI stores the wrapped rotating blob in
196
+ * `.credentials.json` already. Read that file here with a shape check
197
+ * (`claudeAiOauth.accessToken`). Do not reintroduce a shared helper that
198
+ * also serves Rush Cloud dispatch — dispatch is email-only (SING-1b) and
199
+ * the old `readClaudeCredentialsBlob` path was the #1767 TTY-banner leak
200
+ * (RUSH-2359).
198
201
  *
199
202
  * The reader/service/version helpers are injected so unit tests never touch the
200
203
  * real Keychain.
@@ -248,9 +251,22 @@ export async function resolveClaudeCredentialsBlob(opts) {
248
251
  }
249
252
  return null;
250
253
  }
251
- // Off darwin: the local Claude CLI already stores the wrapped blob on disk.
254
+ // Off darwin: the local Claude CLI stores the wrapped rotating blob on disk.
255
+ // Read it directly so a file-based setup-token (Rush Cloud dispatch) is not
256
+ // mistaken for a native OAuth login that SING-1b must refuse to copy.
252
257
  const home = process.env.AGENTS_REAL_HOME || os.homedir();
253
- return readClaudeCredentialsBlob(home);
258
+ const credsPath = path.join(home, '.claude', '.credentials.json');
259
+ try {
260
+ if (fs.existsSync(credsPath)) {
261
+ const raw = fs.readFileSync(credsPath, 'utf-8').trim();
262
+ if (raw && isClaudeCredentialsBlob(raw))
263
+ return raw;
264
+ }
265
+ }
266
+ catch {
267
+ /* no readable credentials file */
268
+ }
269
+ return null;
254
270
  }
255
271
  /**
256
272
  * The credential-provisioning snippet for a `--lease` box.