@phnx-labs/agents-cli 1.22.47 → 1.22.49

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 (249) hide show
  1. package/CHANGELOG.md +401 -17
  2. package/README.md +66 -32
  3. package/dist/bootstrap.js +4 -2
  4. package/dist/cli/command-registry.d.ts +1 -0
  5. package/dist/cli/command-registry.js +2 -0
  6. package/dist/commands/accounts.d.ts +58 -0
  7. package/dist/commands/accounts.js +206 -32
  8. package/dist/commands/artifacts.js +7 -6
  9. package/dist/commands/attach.js +1 -1
  10. package/dist/commands/browser.js +501 -103
  11. package/dist/commands/config.d.ts +0 -1
  12. package/dist/commands/config.js +0 -20
  13. package/dist/commands/daemon.d.ts +21 -0
  14. package/dist/commands/daemon.js +147 -12
  15. package/dist/commands/exec.js +52 -15
  16. package/dist/commands/focus.d.ts +14 -0
  17. package/dist/commands/focus.js +48 -5
  18. package/dist/commands/go.d.ts +3 -0
  19. package/dist/commands/go.js +16 -3
  20. package/dist/commands/inspect.js +2 -2
  21. package/dist/commands/lease.d.ts +1 -1
  22. package/dist/commands/lease.js +4 -3
  23. package/dist/commands/mailboxes.js +4 -3
  24. package/dist/commands/menubar.js +11 -4
  25. package/dist/commands/projects.d.ts +16 -1
  26. package/dist/commands/projects.js +58 -64
  27. package/dist/commands/resume.js +1 -1
  28. package/dist/commands/route.js +4 -4
  29. package/dist/commands/routines.js +3 -2
  30. package/dist/commands/run-broadcast.d.ts +1 -1
  31. package/dist/commands/run-broadcast.js +1 -1
  32. package/dist/commands/sessions-picker.d.ts +22 -0
  33. package/dist/commands/sessions-picker.js +48 -9
  34. package/dist/commands/sessions-trace.js +1 -1
  35. package/dist/commands/sessions.js +1 -0
  36. package/dist/commands/setup-secrets.js +23 -0
  37. package/dist/commands/share.d.ts +20 -5
  38. package/dist/commands/share.js +152 -52
  39. package/dist/commands/ssh.js +54 -7
  40. package/dist/commands/traces.d.ts +2 -0
  41. package/dist/commands/traces.js +184 -0
  42. package/dist/commands/view.d.ts +1 -1
  43. package/dist/commands/view.js +17 -34
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.js +5 -0
  46. package/dist/lib/accounting/usage.d.ts +14 -3
  47. package/dist/lib/accounting/usage.js +64 -18
  48. package/dist/lib/agent-spec/agents.js +11 -9
  49. package/dist/lib/browser/drivers/ssh.d.ts +16 -2
  50. package/dist/lib/browser/drivers/ssh.js +36 -9
  51. package/dist/lib/browser/ipc.js +8 -3
  52. package/dist/lib/browser/profiles.d.ts +35 -101
  53. package/dist/lib/browser/profiles.js +130 -301
  54. package/dist/lib/browser/registry.d.ts +39 -0
  55. package/dist/lib/browser/registry.js +149 -0
  56. package/dist/lib/browser/remote-control.d.ts +8 -6
  57. package/dist/lib/browser/remote-control.js +8 -6
  58. package/dist/lib/browser/resolve-target.d.ts +68 -0
  59. package/dist/lib/browser/resolve-target.js +250 -0
  60. package/dist/lib/browser/runtime-state.d.ts +40 -16
  61. package/dist/lib/browser/runtime-state.js +92 -25
  62. package/dist/lib/browser/service.d.ts +28 -9
  63. package/dist/lib/browser/service.js +139 -62
  64. package/dist/lib/browser/task-index.d.ts +70 -0
  65. package/dist/lib/browser/task-index.js +180 -0
  66. package/dist/lib/byok-usage.js +2 -2
  67. package/dist/lib/claude-statusline.d.ts +29 -0
  68. package/dist/lib/claude-statusline.js +139 -0
  69. package/dist/lib/cloud/host.d.ts +1 -1
  70. package/dist/lib/cloud/host.js +1 -1
  71. package/dist/lib/cloud/rush.js +1 -1
  72. package/dist/lib/computer/computer-rpc.js +2 -2
  73. package/dist/lib/computer/download.d.ts +15 -15
  74. package/dist/lib/computer/download.js +35 -98
  75. package/dist/lib/computer/ssh-tunnel.d.ts +0 -3
  76. package/dist/lib/computer/ssh-tunnel.js +12 -22
  77. package/dist/lib/config-keys.d.ts +2 -8
  78. package/dist/lib/config-keys.js +2 -13
  79. package/dist/lib/crabbox/cli.d.ts +1 -1
  80. package/dist/lib/crabbox/cli.js +2 -2
  81. package/dist/lib/crabbox/lease.d.ts +9 -0
  82. package/dist/lib/crabbox/lease.js +70 -15
  83. package/dist/lib/crabbox/runtimes.js +1 -1
  84. package/dist/lib/daemon/account-state-daemon-service.d.ts +16 -0
  85. package/dist/lib/daemon/account-state-daemon-service.js +26 -0
  86. package/dist/lib/daemon/browser-ipc-service.d.ts +20 -0
  87. package/dist/lib/daemon/browser-ipc-service.js +46 -0
  88. package/dist/lib/daemon/daemon.d.ts +3 -0
  89. package/dist/lib/daemon/daemon.js +212 -444
  90. package/dist/lib/daemon/device-probe-service.d.ts +26 -0
  91. package/dist/lib/daemon/device-probe-service.js +47 -0
  92. package/dist/lib/daemon/keychain-reap-service.d.ts +17 -0
  93. package/dist/lib/daemon/keychain-reap-service.js +32 -0
  94. package/dist/lib/daemon/monitor-engine-service.d.ts +22 -0
  95. package/dist/lib/daemon/monitor-engine-service.js +29 -0
  96. package/dist/lib/daemon/secrets-broker-service.d.ts +20 -0
  97. package/dist/lib/daemon/secrets-broker-service.js +66 -0
  98. package/dist/lib/daemon/self-heal-service.d.ts +27 -0
  99. package/dist/lib/daemon/self-heal-service.js +48 -0
  100. package/dist/lib/daemon/service.d.ts +102 -0
  101. package/dist/lib/daemon/service.js +98 -0
  102. package/dist/lib/daemon/session-index-service.d.ts +22 -0
  103. package/dist/lib/daemon/session-index-service.js +40 -0
  104. package/dist/lib/daemon/state-dir-check-service.d.ts +43 -0
  105. package/dist/lib/daemon/state-dir-check-service.js +63 -0
  106. package/dist/lib/daemon/supervisor.d.ts +87 -0
  107. package/dist/lib/daemon/supervisor.js +298 -0
  108. package/dist/lib/daemon/watchdog-service.d.ts +19 -0
  109. package/dist/lib/daemon/watchdog-service.js +40 -0
  110. package/dist/lib/daemon-health.d.ts +15 -0
  111. package/dist/lib/daemon-health.js +29 -5
  112. package/dist/lib/daemon-services.d.ts +8 -1
  113. package/dist/lib/daemon-services.js +55 -0
  114. package/dist/lib/daemon-ticks.d.ts +13 -2
  115. package/dist/lib/daemon-ticks.js +20 -18
  116. package/dist/lib/device-config.d.ts +0 -2
  117. package/dist/lib/device-config.js +1 -23
  118. package/dist/lib/devices/registry.d.ts +1 -1
  119. package/dist/lib/devices/registry.js +1 -1
  120. package/dist/lib/devices/stats-cache.d.ts +20 -0
  121. package/dist/lib/devices/stats-cache.js +49 -5
  122. package/dist/lib/devices/worker-pick.d.ts +48 -0
  123. package/dist/lib/devices/worker-pick.js +113 -0
  124. package/dist/lib/exec.d.ts +67 -13
  125. package/dist/lib/exec.js +85 -29
  126. package/dist/lib/harness/adapters/cursor.js +8 -11
  127. package/dist/lib/helper-download.d.ts +108 -0
  128. package/dist/lib/helper-download.js +194 -0
  129. package/dist/lib/helper-versions.d.ts +52 -0
  130. package/dist/lib/helper-versions.js +58 -0
  131. package/dist/lib/hooks/cache.js +11 -0
  132. package/dist/lib/hooks/install.js +2 -2
  133. package/dist/lib/hosts/credentials.d.ts +1 -1
  134. package/dist/lib/hosts/credentials.js +1 -1
  135. package/dist/lib/hosts/dispatch.d.ts +7 -1
  136. package/dist/lib/hosts/dispatch.js +24 -5
  137. package/dist/lib/hosts/passthrough.d.ts +8 -15
  138. package/dist/lib/hosts/passthrough.js +19 -16
  139. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  140. package/dist/lib/hosts/providers/devices.js +1 -1
  141. package/dist/lib/hosts/reconnect.d.ts +179 -21
  142. package/dist/lib/hosts/reconnect.js +266 -45
  143. package/dist/lib/installations/migrate.d.ts +4 -5
  144. package/dist/lib/installations/migrate.js +6 -7
  145. package/dist/lib/installations/shims.d.ts +1 -1
  146. package/dist/lib/installations/shims.js +23 -13
  147. package/dist/lib/installations/versions.js +25 -2
  148. package/dist/lib/linear-autoclose.d.ts +1 -1
  149. package/dist/lib/linear-autoclose.js +1 -1
  150. package/dist/lib/loop.d.ts +2 -2
  151. package/dist/lib/loop.js +1 -1
  152. package/dist/lib/menubar/download-menubar.d.ts +47 -0
  153. package/dist/lib/menubar/download-menubar.js +60 -0
  154. package/dist/lib/menubar/install-menubar.d.ts +31 -7
  155. package/dist/lib/menubar/install-menubar.js +79 -21
  156. package/dist/lib/menubar/notify-desktop.d.ts +3 -3
  157. package/dist/lib/menubar/notify-desktop.js +6 -6
  158. package/dist/lib/model-tiers.d.ts +1 -1
  159. package/dist/lib/project-probe.d.ts +1 -1
  160. package/dist/lib/project-probe.js +1 -1
  161. package/dist/lib/project-pull.d.ts +1 -1
  162. package/dist/lib/project-pull.js +2 -2
  163. package/dist/lib/projects.d.ts +1 -1
  164. package/dist/lib/projects.js +1 -1
  165. package/dist/lib/sandbox.js +6 -7
  166. package/dist/lib/secrets/download-keychain.d.ts +47 -0
  167. package/dist/lib/secrets/download-keychain.js +70 -0
  168. package/dist/lib/secrets/install-helper.d.ts +20 -1
  169. package/dist/lib/secrets/install-helper.js +44 -3
  170. package/dist/lib/session/active.js +17 -1
  171. package/dist/lib/session/db.d.ts +11 -1
  172. package/dist/lib/session/db.js +138 -6
  173. package/dist/lib/session/discover.d.ts +21 -1
  174. package/dist/lib/session/discover.js +33 -5
  175. package/dist/lib/session/highlights.d.ts +49 -1
  176. package/dist/lib/session/highlights.js +95 -0
  177. package/dist/lib/session/host-link.d.ts +16 -2
  178. package/dist/lib/session/host-link.js +7 -1
  179. package/dist/lib/session/parse.js +33 -1
  180. package/dist/lib/session/remote/remote-list.d.ts +9 -0
  181. package/dist/lib/session/remote/remote-list.js +19 -2
  182. package/dist/lib/session/remote/watch.js +11 -2
  183. package/dist/lib/session/session-cache.d.ts +53 -0
  184. package/dist/lib/session/session-cache.js +88 -0
  185. package/dist/lib/session/state.js +1 -1
  186. package/dist/lib/session/tool-calls.d.ts +2 -0
  187. package/dist/lib/session/tool-calls.js +1 -1
  188. package/dist/lib/session/trajectory-html.d.ts +5 -1
  189. package/dist/lib/session/trajectory-html.js +42 -22
  190. package/dist/lib/session/trajectory-text.js +9 -2
  191. package/dist/lib/session/trajectory.js +53 -4
  192. package/dist/lib/session/types.d.ts +15 -0
  193. package/dist/lib/sha256-asset.d.ts +26 -0
  194. package/dist/lib/sha256-asset.js +41 -0
  195. package/dist/lib/share/backend.d.ts +95 -0
  196. package/dist/lib/share/backend.js +139 -0
  197. package/dist/lib/share/delete.d.ts +6 -2
  198. package/dist/lib/share/delete.js +8 -9
  199. package/dist/lib/share/html.d.ts +22 -0
  200. package/dist/lib/share/html.js +88 -0
  201. package/dist/lib/share/provision.d.ts +18 -4
  202. package/dist/lib/share/provision.js +38 -4
  203. package/dist/lib/share/publish.d.ts +39 -15
  204. package/dist/lib/share/publish.js +55 -26
  205. package/dist/lib/share/worker-template.js +171 -11
  206. package/dist/lib/sqlite.js +16 -3
  207. package/dist/lib/ssh-exec.d.ts +65 -0
  208. package/dist/lib/ssh-exec.js +120 -4
  209. package/dist/lib/startup/command-registry.js +1 -1
  210. package/dist/lib/startup/dev-build.js +3 -3
  211. package/dist/lib/state.d.ts +1 -1
  212. package/dist/lib/state.js +7 -3
  213. package/dist/lib/subagents-registry.js +1 -1
  214. package/dist/lib/terminal/index.d.ts +1 -1
  215. package/dist/lib/terminal/types.d.ts +1 -1
  216. package/dist/lib/terminal/types.js +1 -1
  217. package/dist/lib/tmux/orphan-reap.js +1 -1
  218. package/dist/lib/tmux/session.js +31 -0
  219. package/dist/lib/traces/backend.d.ts +29 -0
  220. package/dist/lib/traces/backend.js +46 -0
  221. package/dist/lib/traces/classify.d.ts +52 -0
  222. package/dist/lib/traces/classify.js +72 -0
  223. package/dist/lib/traces/config.d.ts +10 -0
  224. package/dist/lib/traces/config.js +2 -0
  225. package/dist/lib/traces/provision.d.ts +19 -0
  226. package/dist/lib/traces/provision.js +30 -0
  227. package/dist/lib/traces/sync.d.ts +150 -0
  228. package/dist/lib/traces/sync.js +447 -0
  229. package/dist/lib/traces/worker-template.d.ts +4 -0
  230. package/dist/lib/traces/worker-template.js +159 -0
  231. package/dist/lib/types.d.ts +18 -19
  232. package/dist/lib/types.js +14 -0
  233. package/dist/lib/usage-refresh.d.ts +1 -1
  234. package/dist/lib/usage-refresh.js +11 -8
  235. package/dist/lib/workflows.d.ts +1 -1
  236. package/package.json +4 -6
  237. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  238. package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +0 -24
  239. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  240. package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
  241. package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +0 -128
  242. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  243. package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -26
  244. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  245. package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
  246. package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +0 -135
  247. package/dist/lib/secrets/Agents CLI.app/Contents/embedded.provisionprofile +0 -0
  248. package/dist/lib/usage-fleet.d.ts +0 -32
  249. package/dist/lib/usage-fleet.js +0 -125
@@ -34,6 +34,22 @@ export const AGENTS_TMUX_HISTORY_LIMIT = 20_000;
34
34
  export const AGENTS_TMUX_CONFIG_SCHEMA = 1;
35
35
  /** Server-scoped user-option recording which AGENTS_TMUX_CONFIG_SCHEMA is applied. */
36
36
  const CONFIG_SCHEMA_OPTION = '@ag_tmux_config_schema';
37
+ /**
38
+ * Session-scoped user options naming WHICH agent session a wrapper session runs,
39
+ * so a status bar (or any tmux format) can show it without shelling out:
40
+ * `#{@ag_session_id}` / `#{@ag_agent}`.
41
+ *
42
+ * The session NAME cannot serve this purpose. runInTmux builds it from
43
+ * `(options.sessionId ?? randomUUID()).slice(0, 8)` (exec.ts), so a run with no
44
+ * pre-assigned id still gets 8 hex characters — indistinguishable from a real
45
+ * short session id but resolving to nothing. Only claude currently takes a
46
+ * forced `--session-id`, so on a box running both, `ag-claude-<real>` and
47
+ * `ag-codex-<fabricated>` look identical. These options are stamped ONLY from
48
+ * `labels.sessionId`, which is set only when the id is genuine — absent rather
49
+ * than wrong, so a consumer can fall back instead of displaying a fake handle.
50
+ */
51
+ const SESSION_ID_OPTION = '@ag_session_id';
52
+ const AGENT_NAME_OPTION = '@ag_agent';
37
53
  let startupConfigSequence = 0;
38
54
  function tmuxConfigArgument(value) {
39
55
  return `"${value.replace(/([\\"$])/g, '\\$1')}"`;
@@ -232,6 +248,21 @@ export async function createSession(opts) {
232
248
  if (pane) {
233
249
  await runTmux({ socket, args: ['set-option', '-pt', pane, 'remain-on-exit', 'on', ';', 'set-option', '-g', 'remain-on-exit', 'off'], throwOnError: false }).catch(() => { });
234
250
  }
251
+ // Stamp the agent identity onto the session so tmux formats can read it.
252
+ // Best-effort: a failure here must not fail a launch that otherwise worked,
253
+ // and an unset option simply renders empty in a format.
254
+ const identityArgs = [];
255
+ if (opts.labels?.sessionId) {
256
+ identityArgs.push('set-option', '-t', opts.name, SESSION_ID_OPTION, opts.labels.sessionId);
257
+ }
258
+ if (opts.labels?.agent) {
259
+ if (identityArgs.length)
260
+ identityArgs.push(';');
261
+ identityArgs.push('set-option', '-t', opts.name, AGENT_NAME_OPTION, opts.labels.agent);
262
+ }
263
+ if (identityArgs.length) {
264
+ await runTmux({ socket, args: identityArgs, throwOnError: false }).catch(() => { });
265
+ }
235
266
  const meta = {
236
267
  name: opts.name,
237
268
  socket,
@@ -0,0 +1,29 @@
1
+ /**
2
+ * TracesBackend — token-source seam for `agents traces sync`.
3
+ *
4
+ * Managed path: signed in to Phoenix (`readSession() != null`), no BYO
5
+ * override. Token is the Phoenix access_token; endpoint is the live
6
+ * `traces.agents-cli.sh` Worker. Zero Cloudflare setup.
7
+ *
8
+ * BYO path (future): TRACES_BASE_URL + TRACES_WRITE_TOKEN env vars. Not
9
+ * exposed in the CLI for M1 — follow-on milestone, same pattern as
10
+ * `agents artifacts setup`.
11
+ */
12
+ export declare const DEFAULT_TRACES_DOMAIN = "traces.agents-cli.sh";
13
+ export interface TracesBackend {
14
+ /** Public base URL of the traces Worker, no trailing slash. */
15
+ baseUrl: string;
16
+ /** Bearer sent as `Authorization`. Phoenix access_token. */
17
+ token: string;
18
+ /** Phoenix userId — the R2 namespace prefix. */
19
+ userId: string;
20
+ }
21
+ /**
22
+ * Resolve the backend for the current machine. Throws when not signed in.
23
+ *
24
+ * BYO override env vars (for testing / self-hosted):
25
+ * AGENTS_TRACES_BASE_URL — Worker URL, no trailing slash
26
+ * AGENTS_TRACES_WRITE_TOKEN — static write token (bypasses Phoenix auth)
27
+ */
28
+ export declare function resolveTracesBackend(): TracesBackend;
29
+ export declare function managedTracesBaseUrl(): string;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * TracesBackend — token-source seam for `agents traces sync`.
3
+ *
4
+ * Managed path: signed in to Phoenix (`readSession() != null`), no BYO
5
+ * override. Token is the Phoenix access_token; endpoint is the live
6
+ * `traces.agents-cli.sh` Worker. Zero Cloudflare setup.
7
+ *
8
+ * BYO path (future): TRACES_BASE_URL + TRACES_WRITE_TOKEN env vars. Not
9
+ * exposed in the CLI for M1 — follow-on milestone, same pattern as
10
+ * `agents artifacts setup`.
11
+ */
12
+ import { readSession } from '../identity/client.js';
13
+ export const DEFAULT_TRACES_DOMAIN = 'traces.agents-cli.sh';
14
+ /**
15
+ * Resolve the backend for the current machine. Throws when not signed in.
16
+ *
17
+ * BYO override env vars (for testing / self-hosted):
18
+ * AGENTS_TRACES_BASE_URL — Worker URL, no trailing slash
19
+ * AGENTS_TRACES_WRITE_TOKEN — static write token (bypasses Phoenix auth)
20
+ */
21
+ export function resolveTracesBackend() {
22
+ const envBase = (process.env['AGENTS_TRACES_BASE_URL'] ?? '').replace(/\/+$/, '').trim();
23
+ const envToken = (process.env['AGENTS_TRACES_WRITE_TOKEN'] ?? '').trim();
24
+ if (envBase && envToken) {
25
+ return { baseUrl: envBase, token: envToken, userId: 'byo' };
26
+ }
27
+ const session = readSession();
28
+ if (!session) {
29
+ throw new Error("Not signed in. Run 'agents auth login' to sync traces to your Phoenix account.");
30
+ }
31
+ if (!session.access_token) {
32
+ throw new Error("Session has no access token. Run 'agents auth login' again.");
33
+ }
34
+ const userId = (session.userId ?? '').trim();
35
+ if (!userId) {
36
+ throw new Error("Signed in but the session has no user id. Run 'agents auth login' again.");
37
+ }
38
+ return {
39
+ baseUrl: managedTracesBaseUrl(),
40
+ token: session.access_token,
41
+ userId,
42
+ };
43
+ }
44
+ export function managedTracesBaseUrl() {
45
+ return `https://${DEFAULT_TRACES_DOMAIN}`;
46
+ }
@@ -0,0 +1,52 @@
1
+ export type TraceTopicGroup = 'code' | 'research' | 'review' | 'content' | 'ops';
2
+ export type TraceFailureCause = 'real' | 'guard' | 'hook';
3
+ /** Per-bucket aggregate stats for one day, stored in the rolling bucketHistory. */
4
+ export interface BucketStats {
5
+ key: string;
6
+ date: string;
7
+ count: number;
8
+ /** Tool-error count / total tool calls in this session set (0–1). */
9
+ errorRate: number;
10
+ /** Sessions with ≥1 stall friction signal / total sessions in bucket (0–1). */
11
+ stallRate: number;
12
+ }
13
+ /** Movement signal for one topic bucket compared to its 7-day rolling average. */
14
+ export interface DriftSignal {
15
+ bucket: string;
16
+ /** current errorRate − 7d average (positive = degrading). */
17
+ errorDelta: number;
18
+ /** current stallRate − 7d average (positive = degrading). */
19
+ stallDelta: number;
20
+ severity: 'degrading' | 'stable' | 'improving';
21
+ }
22
+ export interface TopicEvidence {
23
+ cwd?: string | null;
24
+ gitBranch?: string | null;
25
+ topic?: string | null;
26
+ label?: string | null;
27
+ toolMix?: Record<string, number>;
28
+ }
29
+ export interface ClassifiedTopic {
30
+ group: TraceTopicGroup;
31
+ key: string;
32
+ label: string;
33
+ }
34
+ export interface ToolCallFailure {
35
+ tool: string;
36
+ exit_code?: number | null;
37
+ status_code?: number | null;
38
+ error_code?: string | null;
39
+ error?: string | null;
40
+ parse_error?: string | null;
41
+ outcome?: string | null;
42
+ }
43
+ /** Classify a session from metadata and aggregate tool names; never reads transcript text. */
44
+ export declare function classifyTopic(input: TopicEvidence): ClassifiedTopic;
45
+ /** Bucket a failed tool call without inspecting raw tool input or transcript text. */
46
+ export declare function classifyCause(call: ToolCallFailure): TraceFailureCause;
47
+ /**
48
+ * Compare today's per-bucket stats to the last 7 days of history and return
49
+ * movement signals. Buckets with fewer than 3 historical days are skipped —
50
+ * not enough signal to distinguish noise from drift.
51
+ */
52
+ export declare function computeDriftSignal(history: BucketStats[][], today: BucketStats[]): DriftSignal[];
@@ -0,0 +1,72 @@
1
+ function normalizedEvidence(input) {
2
+ return [input.cwd, input.gitBranch, input.topic, input.label]
3
+ .filter((value) => typeof value === 'string')
4
+ .join(' ')
5
+ .toLowerCase();
6
+ }
7
+ /** Classify a session from metadata and aggregate tool names; never reads transcript text. */
8
+ export function classifyTopic(input) {
9
+ const text = normalizedEvidence(input);
10
+ const tools = Object.keys(input.toolMix ?? {}).map((tool) => tool.toLowerCase());
11
+ const hasTool = (pattern) => tools.some((tool) => pattern.test(tool));
12
+ if (/\b(review|audit|pr[-_/ ]?review|code[-_/ ]?review)\b/.test(text)
13
+ || hasTool(/review|comment/)) {
14
+ return { group: 'review', key: 'code-review', label: 'Code review' };
15
+ }
16
+ if (/\b(research|investigat|analysis|benchmark|paper|docs?)\b/.test(text)
17
+ || hasTool(/web_search|search_query|webfetch|browser/)) {
18
+ return { group: 'research', key: 'research', label: 'Research' };
19
+ }
20
+ if (/\b(blog|copy|content|post|article|script|caption)\b/.test(text)) {
21
+ return { group: 'content', key: 'content', label: 'Content' };
22
+ }
23
+ if (/\b(deploy|release|infra|ci|ops|fleet|daemon|provision)\b/.test(text)
24
+ || hasTool(/ssh|deploy|computer/)) {
25
+ return { group: 'ops', key: 'operations', label: 'Operations' };
26
+ }
27
+ if (/\b(test|fix|bug|feat|refactor|implement|code)\b/.test(text)
28
+ || hasTool(/edit|write|apply_patch|exec|bash|shell/)) {
29
+ return { group: 'code', key: 'engineering', label: 'Engineering' };
30
+ }
31
+ return { group: 'research', key: 'general', label: 'General' };
32
+ }
33
+ /** Bucket a failed tool call without inspecting raw tool input or transcript text. */
34
+ export function classifyCause(call) {
35
+ const evidence = [call.error_code, call.error, call.parse_error]
36
+ .filter((value) => typeof value === 'string')
37
+ .join(' ')
38
+ .toLowerCase();
39
+ if (/\b(?:git-guard|main-branch-guard)\b/.test(evidence))
40
+ return 'guard';
41
+ if (/permission\b.*\bdenied\b.*\b(?:auto[- ]mode|classifier)\b/.test(evidence)) {
42
+ return 'hook';
43
+ }
44
+ return 'real';
45
+ }
46
+ const DRIFT_THRESHOLD = 0.20;
47
+ /**
48
+ * Compare today's per-bucket stats to the last 7 days of history and return
49
+ * movement signals. Buckets with fewer than 3 historical days are skipped —
50
+ * not enough signal to distinguish noise from drift.
51
+ */
52
+ export function computeDriftSignal(history, today) {
53
+ const signals = [];
54
+ for (const stat of today) {
55
+ const pastStats = history
56
+ .flatMap((day) => day.filter((b) => b.key === stat.key))
57
+ .slice(-7);
58
+ if (pastStats.length < 3)
59
+ continue;
60
+ const avgError = pastStats.reduce((sum, b) => sum + b.errorRate, 0) / pastStats.length;
61
+ const avgStall = pastStats.reduce((sum, b) => sum + b.stallRate, 0) / pastStats.length;
62
+ const errorDelta = stat.errorRate - avgError;
63
+ const stallDelta = stat.stallRate - avgStall;
64
+ const severity = errorDelta > DRIFT_THRESHOLD || stallDelta > DRIFT_THRESHOLD
65
+ ? 'degrading'
66
+ : errorDelta < -DRIFT_THRESHOLD || stallDelta < -DRIFT_THRESHOLD
67
+ ? 'improving'
68
+ : 'stable';
69
+ signals.push({ bucket: stat.key, errorDelta, stallDelta, severity });
70
+ }
71
+ return signals.sort((a, b) => b.errorDelta - a.errorDelta);
72
+ }
@@ -0,0 +1,10 @@
1
+ /** Isolated Cloudflare resources for the private Phoenix trace store. */
2
+ export interface TracesConfig {
3
+ baseUrl: string;
4
+ accountId: string;
5
+ workerName: string;
6
+ bucketName: string;
7
+ domain?: string;
8
+ }
9
+ export declare const DEFAULT_WORKER_NAME = "agents-traces";
10
+ export declare const DEFAULT_BUCKET_NAME = "agents-traces";
@@ -0,0 +1,2 @@
1
+ export const DEFAULT_WORKER_NAME = 'agents-traces';
2
+ export const DEFAULT_BUCKET_NAME = 'agents-traces';
@@ -0,0 +1,19 @@
1
+ import { type CloudflareRequester } from '../share/provision.js';
2
+ interface ProvisionOptions {
3
+ request?: CloudflareRequester;
4
+ }
5
+ /** Bind the Phoenix identity base URL used to verify every trace read and write. */
6
+ export declare function setPhoenixIdBaseSecret(apiToken: string, accountId: string, workerName: string, phoenixIdBase: string, opts?: ProvisionOptions): Promise<void>;
7
+ export interface ProvisionTracesOptions extends ProvisionOptions {
8
+ apiToken: string;
9
+ accountId: string;
10
+ workerName: string;
11
+ bucketName: string;
12
+ phoenixIdBase: string;
13
+ domain?: string;
14
+ }
15
+ /** Provision the complete isolated traces deployment using the canonical Worker template. */
16
+ export declare function provisionTraces(opts: ProvisionTracesOptions): Promise<{
17
+ baseUrl: string;
18
+ }>;
19
+ export {};
@@ -0,0 +1,30 @@
1
+ // Cloudflare orchestration for the private agents-traces store. The generic
2
+ // request primitives live in share/provision; only the isolated traces resource
3
+ // choices and Worker template belong here.
4
+ import { randomBytes } from 'node:crypto';
5
+ import { addCustomDomain, createBucket, deployWorker, enableWorkersDev, findZoneId, putWorkerSecret, } from '../share/provision.js';
6
+ import { DEFAULT_TRACES_DOMAIN } from './backend.js';
7
+ import { renderTracesWorkerScript } from './worker-template.js';
8
+ /** Bind the Phoenix identity base URL used to verify every trace read and write. */
9
+ export async function setPhoenixIdBaseSecret(apiToken, accountId, workerName, phoenixIdBase, opts = {}) {
10
+ const normalized = phoenixIdBase.replace(/\/+$/, '').trim();
11
+ if (!normalized)
12
+ throw new Error('PHOENIX_ID_BASE is required to verify trace requests.');
13
+ await putWorkerSecret(apiToken, accountId, workerName, 'PHOENIX_ID_BASE', normalized, opts);
14
+ }
15
+ /** Provision the complete isolated traces deployment using the canonical Worker template. */
16
+ export async function provisionTraces(opts) {
17
+ const domain = opts.domain ?? DEFAULT_TRACES_DOMAIN;
18
+ const requestOpts = opts.request ? { request: opts.request } : {};
19
+ await createBucket(opts.apiToken, opts.accountId, opts.bucketName, requestOpts);
20
+ await deployWorker(opts.apiToken, opts.accountId, opts.workerName, renderTracesWorkerScript(), opts.bucketName, requestOpts);
21
+ await putWorkerSecret(opts.apiToken, opts.accountId, opts.workerName, 'WRITE_TOKEN', randomBytes(32).toString('hex'), requestOpts);
22
+ await setPhoenixIdBaseSecret(opts.apiToken, opts.accountId, opts.workerName, opts.phoenixIdBase, requestOpts);
23
+ const workersDevSubdomain = await enableWorkersDev(opts.apiToken, opts.accountId, opts.workerName, requestOpts);
24
+ const zoneId = await findZoneId(opts.apiToken, domain, requestOpts);
25
+ if (!zoneId) {
26
+ return { baseUrl: `https://${opts.workerName}.${workersDevSubdomain}.workers.dev` };
27
+ }
28
+ await addCustomDomain(opts.apiToken, opts.accountId, opts.workerName, zoneId, domain, requestOpts);
29
+ return { baseUrl: `https://${domain}` };
30
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Incremental sync of derived, redacted SessionTrajectory blobs to the
3
+ * agents-traces R2 store.
4
+ *
5
+ * Security invariant: only the derived signal (steps + gaps + stats +
6
+ * errorCount + programTimeShare) is uploaded — no raw transcript text.
7
+ * redactSecrets() is called inside buildTrajectory() before we PUT.
8
+ *
9
+ * Sync gate: `sessions.db` `file_mtime_ms` is the source of truth. A ledger
10
+ * at `getRuntimeStateDir()/traces-sync.json` records the last sync timestamp
11
+ * per device so re-runs skip unchanged sessions.
12
+ */
13
+ import { type SessionTrajectory } from '../session/trajectory.js';
14
+ import { type BucketStats, type DriftSignal, type TraceFailureCause, type TraceTopicGroup } from './classify.js';
15
+ export interface SyncOpts {
16
+ /** Limit to N sessions (for testing / --dry-run); no limit when undefined. */
17
+ limit?: number;
18
+ /** When true, skip uploading the per-device index shard. */
19
+ skipIndex?: boolean;
20
+ /**
21
+ * Compute the derived shards from this device's real sessions.db and WRITE
22
+ * them to `outDir` instead of uploading. No Phoenix auth, no worker, no
23
+ * network — a local export for verifying the real signal. Ignores the
24
+ * incremental watermark so the export reflects every session.
25
+ */
26
+ dryRun?: boolean;
27
+ /** Directory to write `index.json` + `sessions/<id>.json` when `dryRun` is set. */
28
+ outDir?: string;
29
+ }
30
+ export interface SyncResult {
31
+ uploaded: number;
32
+ skipped: number;
33
+ errors: number;
34
+ }
35
+ /** Push derived, redacted trajectories for this device to the traces store. */
36
+ export declare function syncTraces(opts?: SyncOpts): Promise<SyncResult>;
37
+ export interface TracesIndexShard {
38
+ schema: 1;
39
+ device: string;
40
+ syncedAt: number;
41
+ owner: string;
42
+ stats: {
43
+ sessionsImported: number;
44
+ medianMs: number;
45
+ p90Ms: number;
46
+ needAttention: number;
47
+ toolErrorRate: number;
48
+ };
49
+ needsAttention: IndexedSession[];
50
+ topics: Array<{
51
+ key: string;
52
+ label: string;
53
+ count: number;
54
+ group: TraceTopicGroup;
55
+ }>;
56
+ failures: {
57
+ byToolError: Array<{
58
+ tool: string;
59
+ desc: string;
60
+ cause: TraceFailureCause;
61
+ count: number;
62
+ }>;
63
+ byCause: Record<TraceFailureCause, number>;
64
+ };
65
+ /** Rolling 14-day window of per-bucket daily stats. Each inner array is one day. */
66
+ bucketHistory: BucketStats[][];
67
+ /** Movement signals for buckets with ≥3 days of history. */
68
+ driftSignals: DriftSignal[];
69
+ }
70
+ export interface IndexedSession {
71
+ id: string;
72
+ title: string;
73
+ repo: string;
74
+ device: string;
75
+ agent: string;
76
+ model: string;
77
+ severity: number;
78
+ flags: string[];
79
+ }
80
+ /** Build the redacted rich console shard from indexed metadata and derived caches. */
81
+ export declare function buildIndexShard(rows: SyncRow[], device: string, owner: string, prevShard?: TracesIndexShard | null): TracesIndexShard;
82
+ /** Per-session drill-down detail the console consumes (sessions/<id>.json). */
83
+ export interface SessionDetail {
84
+ schema: 1;
85
+ id: string;
86
+ meta: {
87
+ spanMs: number;
88
+ turns: number;
89
+ tools: number;
90
+ errorCount: number;
91
+ tokens: number;
92
+ costUsd: number;
93
+ outcome: string;
94
+ repo: string;
95
+ agent: string;
96
+ model: string;
97
+ };
98
+ steps: SessionTrajectory['steps'];
99
+ gaps: SessionTrajectory['gaps'];
100
+ /** Steps dropped from `steps` when a run was too long — surfaced so truncation is never silent. */
101
+ truncatedSteps: number;
102
+ whereItWentWrong: string | null;
103
+ }
104
+ /**
105
+ * Map the derived trajectory to the console's SessionDetail shape, stripping
106
+ * local-machine PII (full cwd, account) that would expose filesystem paths if
107
+ * written to R2. `repo` is the cwd basename only.
108
+ */
109
+ export declare function buildSessionDetail(traj: SessionTrajectory): SessionDetail;
110
+ interface SyncLedger {
111
+ lastSyncMtime?: number;
112
+ }
113
+ export declare function readSyncLedger(): SyncLedger;
114
+ export declare function writeSyncLedger(ledger: SyncLedger): void;
115
+ export interface SyncRow {
116
+ id: string;
117
+ short_id: string;
118
+ agent: string;
119
+ origin: string | null;
120
+ routine_name: string | null;
121
+ routine_run_id: string | null;
122
+ version: string | null;
123
+ account: string | null;
124
+ account_key: string | null;
125
+ account_org: string | null;
126
+ mode: string | null;
127
+ timestamp: string;
128
+ last_activity: string | null;
129
+ project: string | null;
130
+ cwd: string | null;
131
+ git_branch: string | null;
132
+ topic: string | null;
133
+ label: string | null;
134
+ message_count: number | null;
135
+ token_count: number | null;
136
+ output_tokens: number | null;
137
+ input_tokens: number | null;
138
+ cache_read_tokens: number | null;
139
+ cache_write_tokens: number | null;
140
+ cost_usd: number | null;
141
+ cost_usd_nocache: number | null;
142
+ duration_ms: number | null;
143
+ model: string | null;
144
+ tool_call_count: number | null;
145
+ file_path: string;
146
+ file_mtime_ms: number | null;
147
+ file_size: number | null;
148
+ machine: string | null;
149
+ }
150
+ export {};