@synap-core/cli 1.12.2 → 1.13.0

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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -8
  3. package/dist/build-info.json +2 -2
  4. package/dist/commands/agents.d.ts +0 -1
  5. package/dist/commands/agents.js +1 -1
  6. package/dist/commands/agents.js.map +1 -1
  7. package/dist/commands/app.js +2 -1
  8. package/dist/commands/app.js.map +1 -1
  9. package/dist/commands/automation.js +46 -41
  10. package/dist/commands/automation.js.map +1 -1
  11. package/dist/commands/box.d.ts +42 -0
  12. package/dist/commands/box.js +89 -0
  13. package/dist/commands/box.js.map +1 -0
  14. package/dist/commands/bridge-setup.js +3 -1
  15. package/dist/commands/bridge-setup.js.map +1 -1
  16. package/dist/commands/capability.d.ts +1 -1
  17. package/dist/commands/capability.js +57 -34
  18. package/dist/commands/capability.js.map +1 -1
  19. package/dist/commands/close-questions.d.ts +27 -0
  20. package/dist/commands/close-questions.js +49 -0
  21. package/dist/commands/close-questions.js.map +1 -0
  22. package/dist/commands/close-questions.test.d.ts +1 -0
  23. package/dist/commands/close-questions.test.js +52 -0
  24. package/dist/commands/close-questions.test.js.map +1 -0
  25. package/dist/commands/connect.d.ts +1 -3
  26. package/dist/commands/connect.js +2 -2
  27. package/dist/commands/connect.js.map +1 -1
  28. package/dist/commands/context.js +72 -43
  29. package/dist/commands/context.js.map +1 -1
  30. package/dist/commands/data-extra.js +12 -4
  31. package/dist/commands/data-extra.js.map +1 -1
  32. package/dist/commands/data.js +2 -1
  33. package/dist/commands/data.js.map +1 -1
  34. package/dist/commands/doctor.d.ts +21 -0
  35. package/dist/commands/doctor.js +108 -13
  36. package/dist/commands/doctor.js.map +1 -1
  37. package/dist/commands/hooks.d.ts +19 -0
  38. package/dist/commands/hooks.js +70 -0
  39. package/dist/commands/hooks.js.map +1 -0
  40. package/dist/commands/import.d.ts +25 -0
  41. package/dist/commands/import.js +98 -12
  42. package/dist/commands/import.js.map +1 -1
  43. package/dist/commands/init.d.ts +14 -0
  44. package/dist/commands/init.js +59 -19
  45. package/dist/commands/init.js.map +1 -1
  46. package/dist/commands/knowledge.js +4 -2
  47. package/dist/commands/knowledge.js.map +1 -1
  48. package/dist/commands/lens.js +2 -1
  49. package/dist/commands/lens.js.map +1 -1
  50. package/dist/commands/market-authoring.js +1 -1
  51. package/dist/commands/market-authoring.js.map +1 -1
  52. package/dist/commands/mcp.js +2 -2
  53. package/dist/commands/mcp.js.map +1 -1
  54. package/dist/commands/observe.category.test.d.ts +1 -0
  55. package/dist/commands/observe.category.test.js +59 -0
  56. package/dist/commands/observe.category.test.js.map +1 -0
  57. package/dist/commands/observe.d.ts +3 -0
  58. package/dist/commands/observe.js +7 -5
  59. package/dist/commands/observe.js.map +1 -1
  60. package/dist/commands/observe.title.test.d.ts +1 -0
  61. package/dist/commands/observe.title.test.js +37 -0
  62. package/dist/commands/observe.title.test.js.map +1 -0
  63. package/dist/commands/playbook.js +9 -0
  64. package/dist/commands/playbook.js.map +1 -1
  65. package/dist/commands/pods.d.ts +6 -1
  66. package/dist/commands/pods.js +32 -15
  67. package/dist/commands/pods.js.map +1 -1
  68. package/dist/commands/proton-setup.js +3 -1
  69. package/dist/commands/proton-setup.js.map +1 -1
  70. package/dist/commands/session-feed-wait.d.ts +48 -0
  71. package/dist/commands/session-feed-wait.js +261 -0
  72. package/dist/commands/session-feed-wait.js.map +1 -0
  73. package/dist/commands/session-post.d.ts +40 -0
  74. package/dist/commands/session-post.js +96 -0
  75. package/dist/commands/session-post.js.map +1 -0
  76. package/dist/commands/session-wait.d.ts +9 -4
  77. package/dist/commands/session-wait.js +20 -5
  78. package/dist/commands/session-wait.js.map +1 -1
  79. package/dist/commands/sessions.d.ts +2 -0
  80. package/dist/commands/sessions.js +23 -0
  81. package/dist/commands/sessions.js.map +1 -1
  82. package/dist/commands/skills-commands.d.ts +2 -0
  83. package/dist/commands/skills-commands.js +9 -1
  84. package/dist/commands/skills-commands.js.map +1 -1
  85. package/dist/commands/skills-commands.test.d.ts +1 -0
  86. package/dist/commands/skills-commands.test.js +57 -0
  87. package/dist/commands/skills-commands.test.js.map +1 -0
  88. package/dist/commands/status.js +1 -1
  89. package/dist/commands/status.js.map +1 -1
  90. package/dist/commands/template.d.ts +42 -0
  91. package/dist/commands/template.js +191 -0
  92. package/dist/commands/template.js.map +1 -0
  93. package/dist/commands/tracks.d.ts +67 -6
  94. package/dist/commands/tracks.js +268 -16
  95. package/dist/commands/tracks.js.map +1 -1
  96. package/dist/commands/whoami.d.ts +7 -0
  97. package/dist/commands/whoami.js +17 -0
  98. package/dist/commands/whoami.js.map +1 -1
  99. package/dist/commands/worker-accounts.d.ts +149 -0
  100. package/dist/commands/worker-accounts.js +339 -0
  101. package/dist/commands/worker-accounts.js.map +1 -0
  102. package/dist/commands/worker-accounts.test.d.ts +1 -0
  103. package/dist/commands/worker-accounts.test.js +224 -0
  104. package/dist/commands/worker-accounts.test.js.map +1 -0
  105. package/dist/commands/worker.d.ts +219 -10
  106. package/dist/commands/worker.js +749 -117
  107. package/dist/commands/worker.js.map +1 -1
  108. package/dist/commands/worker.test.js +321 -10
  109. package/dist/commands/worker.test.js.map +1 -1
  110. package/dist/index.js +164 -27
  111. package/dist/index.js.map +1 -1
  112. package/dist/lib/agent-door.d.ts +1 -3
  113. package/dist/lib/agent-door.js +10 -7
  114. package/dist/lib/agent-door.js.map +1 -1
  115. package/dist/lib/auth.d.ts +3 -2
  116. package/dist/lib/auth.js +3 -3
  117. package/dist/lib/auth.js.map +1 -1
  118. package/dist/lib/box/egress.d.ts +82 -0
  119. package/dist/lib/box/egress.js +264 -0
  120. package/dist/lib/box/egress.js.map +1 -0
  121. package/dist/lib/box/evidence.d.ts +86 -0
  122. package/dist/lib/box/evidence.js +121 -0
  123. package/dist/lib/box/evidence.js.map +1 -0
  124. package/dist/lib/box/job-server.d.ts +72 -0
  125. package/dist/lib/box/job-server.js +246 -0
  126. package/dist/lib/box/job-server.js.map +1 -0
  127. package/dist/lib/box/provisioner.d.ts +83 -0
  128. package/dist/lib/box/provisioner.js +312 -0
  129. package/dist/lib/box/provisioner.js.map +1 -0
  130. package/dist/lib/box/proxmox.d.ts +112 -0
  131. package/dist/lib/box/proxmox.js +211 -0
  132. package/dist/lib/box/proxmox.js.map +1 -0
  133. package/dist/lib/box/wire.d.ts +98 -0
  134. package/dist/lib/box/wire.js +70 -0
  135. package/dist/lib/box/wire.js.map +1 -0
  136. package/dist/lib/browser-auth.d.ts +35 -0
  137. package/dist/lib/browser-auth.js +170 -0
  138. package/dist/lib/browser-auth.js.map +1 -0
  139. package/dist/lib/client-header.test.d.ts +1 -0
  140. package/dist/lib/client-header.test.js +85 -0
  141. package/dist/lib/client-header.test.js.map +1 -0
  142. package/dist/lib/conversation-headers.d.ts +24 -9
  143. package/dist/lib/conversation-headers.js +40 -3
  144. package/dist/lib/conversation-headers.js.map +1 -1
  145. package/dist/lib/credential-class.d.ts +28 -1
  146. package/dist/lib/credential-class.js +28 -6
  147. package/dist/lib/credential-class.js.map +1 -1
  148. package/dist/lib/exporter-coverage.d.ts +1 -1
  149. package/dist/lib/exporter-coverage.js +1 -1
  150. package/dist/lib/goal-words.d.ts +38 -0
  151. package/dist/lib/goal-words.js +112 -0
  152. package/dist/lib/goal-words.js.map +1 -0
  153. package/dist/lib/hub-client.d.ts +28 -7
  154. package/dist/lib/hub-client.js +75 -34
  155. package/dist/lib/hub-client.js.map +1 -1
  156. package/dist/lib/init-handoff.d.ts +8 -0
  157. package/dist/lib/init-handoff.js +9 -2
  158. package/dist/lib/init-handoff.js.map +1 -1
  159. package/dist/lib/key-source.d.ts +3 -1
  160. package/dist/lib/key-source.js +7 -4
  161. package/dist/lib/key-source.js.map +1 -1
  162. package/dist/lib/knowledge-title.d.ts +3 -2
  163. package/dist/lib/knowledge-title.js +3 -2
  164. package/dist/lib/knowledge-title.js.map +1 -1
  165. package/dist/lib/mcp-bridge.d.ts +7 -0
  166. package/dist/lib/mcp-bridge.js +34 -1
  167. package/dist/lib/mcp-bridge.js.map +1 -1
  168. package/dist/lib/mcp-bridge.test.js +31 -3
  169. package/dist/lib/mcp-bridge.test.js.map +1 -1
  170. package/dist/lib/openclaw.d.ts +32 -0
  171. package/dist/lib/openclaw.js +165 -0
  172. package/dist/lib/openclaw.js.map +1 -0
  173. package/dist/lib/pod-moved.d.ts +70 -0
  174. package/dist/lib/pod-moved.js +146 -0
  175. package/dist/lib/pod-moved.js.map +1 -0
  176. package/dist/lib/pod-reach.d.ts +39 -0
  177. package/dist/lib/pod-reach.js +117 -0
  178. package/dist/lib/pod-reach.js.map +1 -0
  179. package/dist/lib/pod-reach.test.d.ts +1 -0
  180. package/dist/lib/pod-reach.test.js +67 -0
  181. package/dist/lib/pod-reach.test.js.map +1 -0
  182. package/dist/lib/pod.d.ts +8 -0
  183. package/dist/lib/pod.js +12 -3
  184. package/dist/lib/pod.js.map +1 -1
  185. package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
  186. package/dist/lib/register-claude-code-mcp.test.js +78 -0
  187. package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
  188. package/dist/lib/review-credential.js +3 -1
  189. package/dist/lib/review-credential.js.map +1 -1
  190. package/dist/lib/seed.d.ts +13 -0
  191. package/dist/lib/seed.js +135 -0
  192. package/dist/lib/seed.js.map +1 -0
  193. package/dist/lib/session-feed.d.ts +185 -0
  194. package/dist/lib/session-feed.js +257 -0
  195. package/dist/lib/session-feed.js.map +1 -0
  196. package/dist/lib/targets.d.ts +21 -3
  197. package/dist/lib/targets.js +52 -107
  198. package/dist/lib/targets.js.map +1 -1
  199. package/dist/lib/wake-hook-settings.d.ts +57 -0
  200. package/dist/lib/wake-hook-settings.js +153 -0
  201. package/dist/lib/wake-hook-settings.js.map +1 -0
  202. package/dist/lib/wake-state.d.ts +65 -0
  203. package/dist/lib/wake-state.js +122 -0
  204. package/dist/lib/wake-state.js.map +1 -0
  205. package/package.json +5 -2
  206. package/skills/README.md +1 -1
  207. package/skills/agent-os/SKILL.md +8 -8
  208. package/skills/synap/SKILL.md +141 -84
  209. package/skills/synap/code-skills.md +70 -0
  210. package/skills/synap/concepts.md +28 -20
  211. package/skills/synap/creative-loop.md +1 -1
  212. package/skills/synap/document-embeds.md +3 -1
  213. package/skills/synap/focus-sessions.md +16 -7
  214. package/skills/synap/from-intent.md +32 -16
  215. package/skills/synap/governance-rules.md +1 -1
  216. package/skills/synap/lenses.md +4 -4
  217. package/skills/synap/linking.md +2 -2
  218. package/skills/synap/mental-model.md +1 -1
  219. package/skills/synap/operating-mode-rules.md +1 -1
  220. package/skills/synap/quick-reference.md +2 -1
  221. package/skills/synap/reflexes.md +6 -6
  222. package/skills/synap/viewframe-cells.md +1 -1
  223. package/skills/synap/work-model.md +24 -10
  224. package/skills/synap/workspace-design.md +5 -5
  225. package/skills/synap/writes.md +16 -9
  226. package/skills/synap-app/SKILL.md +148 -66
  227. package/skills/synap-app/creating-the-base-app.md +12 -7
  228. package/skills/synap-app/governance.md +27 -16
  229. package/skills/synap-app/install-commands.md +18 -9
  230. package/skills/synap-app/overview.md +16 -9
  231. package/skills/synap-app/using-the-sdk.md +75 -25
  232. package/skills/synap-schema/SKILL.md +21 -21
  233. package/skills/synap-schema/intent-vocabulary-ssot.md +21 -21
  234. package/templates/box/runner.py +206 -0
@@ -0,0 +1,224 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { describe, expect, it } from "vitest";
5
+ import { AccountPool, loadAccountsFile, probeAccount, reserveIds, selectAccount, standingOf, } from "./worker-accounts.js";
6
+ const T = Date.parse("2026-10-24T06:00:00Z");
7
+ const H = 3_600_000;
8
+ const meter = (m) => ({ rejected: false, checkedAt: T, ...m });
9
+ const room = (m) => ({ kind: "room", meter: meter(m) });
10
+ const file = (over = {}) => ({
11
+ version: 1,
12
+ reserve: 0,
13
+ accounts: [
14
+ { id: "dev", label: "Dev", token: "tok-dev", design: true },
15
+ { id: "a", label: "A", token: "tok-a" },
16
+ { id: "b", label: "B", token: "tok-b" },
17
+ { id: "c", label: "C", token: "tok-c" },
18
+ ],
19
+ ...over,
20
+ });
21
+ describe("selectAccount", () => {
22
+ it("picks the account whose 5-hour window resets soonest (use it or lose it)", () => {
23
+ const s = new Map([
24
+ ["dev", room({ fiveHour: 10, fiveHourReset: T + 4 * H, week: 10 })],
25
+ ["a", room({ fiveHour: 10, fiveHourReset: T + 3 * H, week: 10 })],
26
+ ["b", room({ fiveHour: 50, fiveHourReset: T + 1 * H, week: 10 })],
27
+ ["c", room({ fiveHour: 10, fiveHourReset: T + 2 * H, week: 10 })],
28
+ ]);
29
+ expect(selectAccount(file(), s, { design: false }).account?.id).toBe("b");
30
+ });
31
+ it("ties on the reset go to file order", () => {
32
+ const s = new Map([
33
+ ["a", room({ fiveHourReset: T + H })],
34
+ ["b", room({ fiveHourReset: T + H })],
35
+ ]);
36
+ expect(selectAccount(file(), s, { design: false }).account?.id).toBe("a");
37
+ });
38
+ it("leaves out the reserve: the non-design accounts with the most WEEKLY room left", () => {
39
+ // b resets soonest, but b and c have the most weekly room: they stay for the person.
40
+ const s = new Map([
41
+ ["dev", room({ fiveHourReset: T + 5 * H, week: 90 })],
42
+ ["a", room({ fiveHourReset: T + 3 * H, week: 80 })],
43
+ ["b", room({ fiveHourReset: T + 1 * H, week: 5 })],
44
+ ["c", room({ fiveHourReset: T + 2 * H, week: 20 })],
45
+ ]);
46
+ expect([...reserveIds(file().accounts, s, 2)].sort()).toEqual(["b", "c"]);
47
+ expect(selectAccount(file({ reserve: 2 }), s, { design: false }).account?.id).toBe("a");
48
+ });
49
+ it("the design account is never counted in the reserve", () => {
50
+ const s = new Map([
51
+ ["dev", room({ week: 0 })],
52
+ ["a", room({ week: 50 })],
53
+ ["b", room({ week: 60 })],
54
+ ]);
55
+ expect([...reserveIds(file().accounts, s, 1)]).toEqual(["a"]);
56
+ });
57
+ it("an UNMEASURED account is never picked — a failed probe is not room", () => {
58
+ const s = new Map([
59
+ ["a", { kind: "unmeasured", reason: "probe failed: TypeError" }],
60
+ ["b", { kind: "refused", reason: "HTTP 401" }],
61
+ ["c", { kind: "full", until: T + H }],
62
+ ]);
63
+ const sel = selectAccount(file(), s, { design: false });
64
+ expect(sel.account).toBeUndefined();
65
+ expect(sel.reason).toMatch(/a: unmeasured/);
66
+ });
67
+ it("an unmeasured account is never READ as full either: it is not reserved in place of a measured one", () => {
68
+ const s = new Map([
69
+ ["a", { kind: "unmeasured", reason: "x" }],
70
+ ["b", room({ week: 10 })],
71
+ ["c", room({ week: 30 })],
72
+ ]);
73
+ // b has the most weekly room among the MEASURED (90% left); a is not ranked at all.
74
+ expect([...reserveIds(file().accounts, s, 1)]).toEqual(["b"]);
75
+ expect(selectAccount(file({ reserve: 1 }), s, { design: false }).account?.id).toBe("c");
76
+ });
77
+ it("a design run takes ONLY the design account, and waits when it has no room", () => {
78
+ const s = new Map([
79
+ ["dev", { kind: "full", until: T + H }],
80
+ ["a", room({ fiveHourReset: T + H })],
81
+ ]);
82
+ const sel = selectAccount(file(), s, { design: true });
83
+ expect(sel.account).toBeUndefined();
84
+ expect(sel.reason).toMatch(/no design account with room/);
85
+ s.set("dev", room({ fiveHourReset: T + 9 * H }));
86
+ expect(selectAccount(file(), s, { design: true }).account?.id).toBe("dev");
87
+ });
88
+ it("another run spends the design account only when no other account has room", () => {
89
+ // dev resets soonest, yet a takes the run: dev's quota stays for the designs.
90
+ const s = new Map([
91
+ ["dev", room({ fiveHourReset: T + 1 * H })],
92
+ ["a", room({ fiveHourReset: T + 4 * H })],
93
+ ["b", { kind: "full", until: T + H }],
94
+ ["c", { kind: "full", until: T + H }],
95
+ ]);
96
+ expect(selectAccount(file(), s, { design: false }).account?.id).toBe("a");
97
+ s.set("a", { kind: "full", until: T + H });
98
+ expect(selectAccount(file(), s, { design: false }).account?.id).toBe("dev");
99
+ });
100
+ it("a design run with no design account flagged is refused in words", () => {
101
+ const f = file({ accounts: [{ id: "a", label: "A", token: "t" }] });
102
+ expect(selectAccount(f, new Map([["a", room({})]]), { design: true }).reason).toMatch(/flagged design/);
103
+ });
104
+ });
105
+ describe("standingOf", () => {
106
+ it("over the threshold is full until the binding window resets", () => {
107
+ const s = standingOf({ kind: "measured", meter: meter({ fiveHour: 96, fiveHourReset: T + H, week: 10 }) }, undefined, T);
108
+ expect(s).toMatchObject({ kind: "full", until: T + H });
109
+ });
110
+ it("a full window whose reset passed is unmeasured until measured again — not room", () => {
111
+ const s = standingOf({ kind: "measured", meter: meter({ fiveHour: 100, fiveHourReset: T - 1 }) }, undefined, T);
112
+ expect(s.kind).toBe("unmeasured");
113
+ });
114
+ it("a run's limit mark wins over an older probe", () => {
115
+ const s = standingOf({ kind: "measured", meter: meter({ fiveHour: 1 }) }, T + H, T);
116
+ expect(s).toMatchObject({ kind: "full", until: T + H });
117
+ });
118
+ });
119
+ const headers = (h) => Object.fromEntries(Object.entries(h).map(([k, v]) => [`anthropic-ratelimit-unified-${k}`, v]));
120
+ const respond = (status, h = {}, body = {}) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json", ...headers(h) } });
121
+ describe("probeAccount (ported from ClaudeSwitch probeOnce)", () => {
122
+ it("200 → measured, utilization as percent, resets in ms", async () => {
123
+ let sent;
124
+ const r = await probeAccount("sk-ant-oat-x", {
125
+ now: () => T,
126
+ fetchImpl: (async (_u, init) => {
127
+ sent = init;
128
+ return respond(200, { status: "allowed", "5h-utilization": "0.25", "5h-reset": "1792725000", "7d-utilization": "0.5", "7d-reset": "1793000000" });
129
+ }),
130
+ });
131
+ expect(r).toEqual({
132
+ kind: "measured",
133
+ meter: expect.objectContaining({ fiveHour: 25, fiveHourReset: 1792725000_000, week: 50, weekReset: 1793000000_000, rejected: false }),
134
+ });
135
+ const h = sent?.headers;
136
+ expect(h.Authorization).toBe("Bearer sk-ant-oat-x");
137
+ expect(h["anthropic-beta"]).toBe("oauth-2025-04-20");
138
+ expect(JSON.parse(String(sent?.body)).max_tokens).toBe(1);
139
+ });
140
+ it("429 rejected → measured full; 429 without rejected → a burst, unmeasured", async () => {
141
+ const full = await probeAccount("t", { fetchImpl: (async () => respond(429, { status: "rejected", reset: "1792725000" })) });
142
+ expect(full).toMatchObject({ kind: "measured", meter: { rejected: true } });
143
+ const burst = await probeAccount("t", { fetchImpl: (async () => respond(429, {})) });
144
+ expect(burst).toEqual({ kind: "unmeasured", reason: "briefly rate limited" });
145
+ });
146
+ it("401/403 → refused", async () => {
147
+ const r = await probeAccount("t", { fetchImpl: (async () => respond(401, {}, { error: { message: "invalid token" } })) });
148
+ expect(r).toEqual({ kind: "refused", reason: "invalid token" });
149
+ });
150
+ it("a missing model tries the next one", async () => {
151
+ const models = [];
152
+ const r = await probeAccount("t", {
153
+ models: ["gone-model", "live-model"],
154
+ fetchImpl: (async (_u, init) => {
155
+ const m = JSON.parse(String(init?.body)).model;
156
+ models.push(m);
157
+ return m === "gone-model" ? respond(404, {}, { error: { type: "not_found_error", message: "model: gone" } }) : respond(200, { "5h-utilization": "0" });
158
+ }),
159
+ });
160
+ expect(models).toEqual(["gone-model", "live-model"]);
161
+ expect(r.kind).toBe("measured");
162
+ });
163
+ it("a network failure is UNMEASURED, never room and never full", async () => {
164
+ const r = await probeAccount("t", { fetchImpl: (async () => { throw new TypeError("fetch failed"); }) });
165
+ expect(r.kind).toBe("unmeasured");
166
+ expect(standingOf(r, undefined, T).kind).toBe("unmeasured");
167
+ });
168
+ });
169
+ describe("AccountPool", () => {
170
+ it("reuses a fresh measurement, and a limit mark keeps the account out without probing it", async () => {
171
+ let t = T;
172
+ const probed = [];
173
+ const probe = async (token) => {
174
+ probed.push(token);
175
+ return { kind: "measured", meter: meter({ fiveHour: 10, fiveHourReset: T + H, checkedAt: t }) };
176
+ };
177
+ const pool = new AccountPool(file({ accounts: file().accounts.slice(1, 3) }), probe, () => t);
178
+ await pool.measure();
179
+ await pool.measure();
180
+ expect(probed).toEqual(["tok-a", "tok-b"]);
181
+ pool.markFull("a", T + H);
182
+ t += 4 * 60_000;
183
+ await pool.measure();
184
+ expect(probed).toEqual(["tok-a", "tok-b", "tok-b"]);
185
+ expect(pool.select({ design: false }).account?.id).toBe("b");
186
+ });
187
+ });
188
+ describe("loadAccountsFile", () => {
189
+ const dir = () => fs.mkdtempSync(path.join(os.tmpdir(), "worker-accounts-"));
190
+ it("no default file → null (the environment's login, as before)", () => {
191
+ expect(loadAccountsFile(undefined)).toBeNull();
192
+ });
193
+ it("a named file that is missing throws", () => {
194
+ expect(() => loadAccountsFile(path.join(dir(), "nope.json"))).toThrow(/does not exist/);
195
+ });
196
+ it("a broken file throws — never 'no accounts' — and never quotes a token", () => {
197
+ const f = path.join(dir(), "accounts.json");
198
+ fs.writeFileSync(f, '{"version":1,"accounts":[{"id":"a","token":"sk-ant-oat-SECRET"}');
199
+ expect(() => loadAccountsFile(f)).toThrow(/not valid JSON/);
200
+ fs.writeFileSync(f, JSON.stringify({ version: 1, accounts: [{ id: "a b", token: "sk-ant-oat-SECRET" }] }));
201
+ let msg = "";
202
+ try {
203
+ loadAccountsFile(f);
204
+ }
205
+ catch (err) {
206
+ msg = err.message;
207
+ }
208
+ expect(msg).toMatch(/id must match/);
209
+ expect(msg).not.toContain("SECRET");
210
+ });
211
+ it("reads the documented shape", () => {
212
+ const f = path.join(dir(), "accounts.json");
213
+ fs.writeFileSync(f, JSON.stringify({ version: 1, reserve: 2, accounts: [{ id: "dev", label: "Dev", token: " t1 ", design: true }, { id: "a", token: "t2" }] }));
214
+ expect(loadAccountsFile(f)).toEqual({
215
+ version: 1,
216
+ reserve: 2,
217
+ accounts: [
218
+ { id: "dev", label: "Dev", token: "t1", design: true },
219
+ { id: "a", label: "a", token: "t2" },
220
+ ],
221
+ });
222
+ });
223
+ });
224
+ //# sourceMappingURL=worker-accounts.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-accounts.test.js","sourceRoot":"","sources":["../../src/commands/worker-accounts.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,aAAa,EACb,UAAU,GAKX,MAAM,sBAAsB,CAAC;AAE9B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;AAC7C,MAAM,CAAC,GAAG,SAAS,CAAC;AACpB,MAAM,KAAK,GAAG,CAAC,CAAiB,EAAS,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;AACtF,MAAM,IAAI,GAAG,CAAC,CAAiB,EAAY,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAElF,MAAM,IAAI,GAAG,CAAC,OAA8B,EAAE,EAAgB,EAAE,CAAC,CAAC;IAChE,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,QAAQ,EAAE;QACR,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE;QAC3D,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;QACvC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;QACvC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE;KACxC;IACD,GAAG,IAAI;CACR,CAAC,CAAC;AAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACnE,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACjE,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACjE,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;SAClE,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SACtC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,qFAAqF;QACrF,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACrD,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACnD,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAClD,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;SACpD,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1E,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACzB,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;SAC1B,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC;YAChE,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;YAC9C,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;SACtC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mGAAmG,EAAE,GAAG,EAAE;QAC3G,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;YAC1C,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACzB,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;SAC1B,CAAC,CAAC;QACH,oFAAoF;QACpF,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACvC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;SACtC,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;QAC1D,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2EAA2E,EAAE,GAAG,EAAE;QACnF,8EAA8E;QAC9E,MAAM,CAAC,GAAG,IAAI,GAAG,CAAmB;YAClC,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3C,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACzC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;SACtC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1E,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3C,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,GAAG,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACpE,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1G,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QACzH,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gFAAgF,EAAE,GAAG,EAAE;QACxF,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QAChH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,CAAC,CAAyB,EAAE,EAAE,CAC5C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,+BAA+B,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACjG,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,IAA4B,EAAE,EAAE,OAAgB,EAAE,EAAE,EAAE,CACrF,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAEjH,QAAQ,CAAC,mDAAmD,EAAE,GAAG,EAAE;IACjE,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,IAAI,IAA6B,CAAC;QAClC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,cAAc,EAAE;YAC3C,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;YACZ,SAAS,EAAE,CAAC,KAAK,EAAE,EAAW,EAAE,IAAkB,EAAE,EAAE;gBACpD,IAAI,GAAG,IAAI,CAAC;gBACZ,OAAO,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;YACpJ,CAAC,CAAiB;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAChB,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,MAAM,CAAC,gBAAgB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;SACtI,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,EAAE,OAAiC,CAAC;QAClD,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;QACpD,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,KAAK,IAAI,EAAE;QACxF,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAiB,EAAE,CAAC,CAAC;QAC7I,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC5E,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAiB,EAAE,CAAC,CAAC;QACrG,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,CAAC,CAAiB,EAAE,CAAC,CAAC;QAC1I,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;YACpC,SAAS,EAAE,CAAC,KAAK,EAAE,EAAW,EAAE,IAAkB,EAAE,EAAE;gBACpD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,KAAe,CAAC;gBACzD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACf,OAAO,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,CAAC;YACzJ,CAAC,CAAiB;SACnB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;QACrD,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAiB,EAAE,CAAC,CAAC;QACzH,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAClC,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,uFAAuF,EAAE,KAAK,IAAI,EAAE;QACrG,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,EAAE,KAAa,EAAwB,EAAE;YAC1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAClG,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9F,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3C,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC1B,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QAChB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC7E,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC1F,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,iEAAiE,CAAC,CAAC;QACvF,MAAM,CAAC,GAAG,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC5D,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3G,IAAI,GAAG,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YACH,gBAAgB,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,GAAI,GAAa,CAAC,OAAO,CAAC;QAC/B,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;QAC5C,EAAE,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAChK,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAClC,OAAO,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE;gBACR,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;gBACtD,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE;aACrC;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -21,10 +21,28 @@
21
21
  * variables are removed from the launched environment so a stray key can never
22
22
  * silently switch billing away from the subscription.
23
23
  *
24
+ * Several Claude accounts (`--accounts <file>`, default
25
+ * ~/.config/synap-worker/accounts.json when it exists): before each launch the
26
+ * accounts are measured and one is picked (worker-accounts.ts); its token goes
27
+ * into the run's environment only. A run cut off by a usage limit marks that
28
+ * account full and is RESUMED (same Claude conversation) on the next account.
29
+ *
30
+ * A DESIGN run (the session declares an outcome of kind "design") launches as
31
+ * `claude --bg` — the only mode that has the Artifact tool — on the account
32
+ * flagged `design`, and is watched through `claude agents --json` and its
33
+ * transcript.
34
+ *
35
+ * Two PROTOCOLS (`sessionProtocol`): a CODE session is worked in a git
36
+ * worktree on a `devbox/<id>` branch and ends in a draft PR; a WORK-FOLDER
37
+ * session (a playbook run over pod data — a video edit, an interview) is
38
+ * worked in `<work root>/<sessionId>/` with no git, files its outputs back to
39
+ * the pod, and asks the person through the session's human-owned slots.
40
+ *
24
41
  * State (which sessions were launched, their Claude session ids and outcome)
25
42
  * lives in ~/.synap/worker/<agent>/state.json; each run's stream-json goes to
26
- * ~/.synap/worker/<agent>/runs/<sessionId>.jsonl.
43
+ * ~/.synap/worker/<agent>/runs/<sessionId>.jsonl. Neither ever holds a token.
27
44
  */
45
+ import { type McpCallClient } from "../lib/mcp-call.js";
28
46
  export interface WorkerOptions {
29
47
  agent: string;
30
48
  interval?: string;
@@ -33,16 +51,20 @@ export interface WorkerOptions {
33
51
  maxParallel?: string;
34
52
  claudeBin?: string;
35
53
  claudeConfigDir?: string;
36
- mcpServer?: string;
37
54
  allowedTools?: string;
38
55
  skipPermissions?: boolean;
39
56
  dryRun?: boolean;
57
+ /** The Claude accounts file (default ~/.config/synap-worker/accounts.json, used when it exists). */
58
+ accounts?: string;
59
+ /** Where work-folder runs get their folder, one per session (default ~/synap-work). */
60
+ workRoot?: string;
40
61
  }
41
62
  export interface HandedItem {
42
63
  id: string;
43
64
  goal: string | null;
44
65
  }
45
- export type RunStatus = "running" | "done" | "failed";
66
+ /** `limited`: cut off by a usage limit, waiting to be resumed on another account. */
67
+ export type RunStatus = "running" | "done" | "failed" | "limited";
46
68
  export interface RunRecord {
47
69
  sessionId: string;
48
70
  status: RunStatus;
@@ -54,6 +76,24 @@ export interface RunRecord {
54
76
  result?: string;
55
77
  /** How many times a room follow-up resumed this Claude conversation. */
56
78
  resumes?: number;
79
+ /** How many times a run that failed before Claude started was relaunched. */
80
+ launchRetries?: number;
81
+ /** The accounts-file id the latest launch ran on — an id, never a token. */
82
+ accountId?: string;
83
+ /** `print` = `claude -p` (default); `bg` = `claude --bg`, a design run. */
84
+ mode?: "print" | "bg";
85
+ /** The short id `claude --bg` printed (what `claude agents|stop` take). */
86
+ bgId?: string;
87
+ /** When the latest launch (first or resumed) started. */
88
+ launchedAt?: string;
89
+ /** How many times a run cut off by a usage limit was resumed on another account. */
90
+ limitResumes?: number;
91
+ /** A background run first seen blocked (needs input) at this time. */
92
+ blockedSince?: string;
93
+ /** Which protocol the run was launched with (absent: a run from before protocols = code). */
94
+ protocol?: WorkerProtocol;
95
+ /** A work-folder run's folder: its cwd, which every resume reuses (Claude finds a conversation by its cwd). */
96
+ workDir?: string;
57
97
  }
58
98
  interface WorkerState {
59
99
  runs: Record<string, RunRecord>;
@@ -81,14 +121,38 @@ export declare class AgentPausedError extends Error {
81
121
  * block throws `AgentBoundForDispatchError`.
82
122
  */
83
123
  export declare function parseHandedToYou(orientText: string): HandedItem[];
84
- /** Sessions handed to the agent that this worker has not launched yet. */
85
- export declare function pickNew(items: HandedItem[], state: WorkerState, slots: number): HandedItem[];
86
124
  /**
87
- * The MCP server name the local Claude Code uses for THIS pod: the entry in
88
- * ~/.claude.json whose URL is `<podUrl>/mcp` (user or project scope).
125
+ * A run that failed BEFORE Claude started (no Claude session: an expired login,
126
+ * exhausted credits) is relaunched after 30 min, then 1 h, 2 h and 4 h, enough
127
+ * to outlast a credit reset. A run Claude did start is resumed only by a room
128
+ * follow-up, never relaunched from scratch.
129
+ */
130
+ export declare const LAUNCH_RETRY_BASE_MS: number;
131
+ export declare const MAX_LAUNCH_RETRIES = 4;
132
+ /** Sessions to launch now: never launched, or due a relaunch (see above). */
133
+ export declare function pickNew(items: HandedItem[], state: WorkerState, slots: number, now?: number): HandedItem[];
134
+ /**
135
+ * The pod MCP server every run gets, under this name, carrying the WORKER
136
+ * AGENT's own key. Runs never inherit the server in ~/.claude.json: whatever
137
+ * key that file holds (a `synap login --reconnect` on the box rewrites it with
138
+ * another agent's) would decide who the run posts as, and the worker would
139
+ * then read its own posts as follow-ups (2026-10-20).
89
140
  */
90
- export declare function findMcpServerName(claudeJson: unknown, podUrl: string): string | null;
141
+ export declare const RUN_MCP_SERVER = "synap-worker";
142
+ export declare function runMcpConfig(podUrl: string, apiKey: string,
143
+ /** The run's Claude session id: names the conversation to the pod, one id across resumes. */
144
+ claudeSessionId?: string): {
145
+ mcpServers: Record<string, unknown>;
146
+ };
147
+ /** Writes the run config owner-only (it holds the key) and returns its path. */
148
+ export declare function writeRunMcpConfig(dir: string, config: {
149
+ mcpServers: Record<string, unknown>;
150
+ }, name?: string): string;
91
151
  export declare const DEFAULT_ALLOWED_TOOLS: string[];
152
+ /** The tools a design run adds: the claude.ai Artifact tool (and the search that loads deferred tools). */
153
+ export declare const DESIGN_EXTRA_TOOLS: string[];
154
+ /** The tools a work-folder run adds: skills (the HyperFrames workflow is one). */
155
+ export declare const WORK_FOLDER_EXTRA_TOOLS: string[];
92
156
  /** The protocol the launched Claude Code follows for one handed session. */
93
157
  export declare function buildWorkerPrompt(p: {
94
158
  sessionId: string;
@@ -96,9 +160,119 @@ export declare function buildWorkerPrompt(p: {
96
160
  agentName: string;
97
161
  cwd: string;
98
162
  mcpServer: string;
163
+ /** A design run: the deliverable is a claude.ai Design artifact. */
164
+ design?: boolean;
165
+ }): string;
166
+ /** How long a work-folder run waits for an answer to its ask before it ends `blocked`. */
167
+ export declare const ASK_WAIT_MINUTES = 30;
168
+ /**
169
+ * The protocol for a WORK-FOLDER session (`sessionProtocol`): no git; files in
170
+ * the session's folder; outputs filed to the pod; questions asked through a
171
+ * human-owned slot with an ask (what Content Studio, Relay and the Needs-you
172
+ * list show), never a room `QUESTION:` line.
173
+ */
174
+ export declare function buildWorkFolderPrompt(p: {
175
+ sessionId: string;
176
+ goal: string | null;
177
+ agentName: string;
178
+ workDir: string;
179
+ mcpServer: string;
99
180
  }): string;
100
- /** The launched environment: the subscription, never a stray API key. */
101
- export declare function workerEnv(base: NodeJS.ProcessEnv, claudeConfigDir?: string): NodeJS.ProcessEnv;
181
+ /**
182
+ * The launched environment: the subscription, never a stray API key. With an
183
+ * account picked, its token REPLACES any token the worker inherited.
184
+ */
185
+ export declare function workerEnv(base: NodeJS.ProcessEnv, claudeConfigDir?: string, oauthToken?: string): NodeJS.ProcessEnv;
186
+ export interface LimitHit {
187
+ error: string;
188
+ /** When the limit lifts (ms), when Claude Code said. */
189
+ resetsAt?: number;
190
+ }
191
+ /** What one run's events say about how it ended. */
192
+ export interface RunEnd {
193
+ claudeSessionId?: string;
194
+ /** The `result` text (stream) or the last main assistant text (transcript). */
195
+ text?: string;
196
+ /** Set when the run's LAST main-thread turn was refused by a usage limit. */
197
+ limit?: LimitHit;
198
+ isError?: boolean;
199
+ }
200
+ /**
201
+ * Fold one event (a stream-json line of `claude -p`, or a transcript line of
202
+ * a background session — the two spell the fields differently) into the run's
203
+ * ending. A later healthy assistant message clears an earlier limit: only a
204
+ * run whose last turn hit the limit "ended on a limit".
205
+ */
206
+ export declare function foldRunEvent(end: RunEnd, ev: Record<string, unknown>, rejectedResetsAt?: {
207
+ at?: number;
208
+ }): RunEnd;
209
+ /** A run that printed its WORKER-RESULT verdict finished its protocol: never a limit. */
210
+ export declare function endedOnLimit(end: RunEnd): LimitHit | undefined;
211
+ /** How long an account stays out after a limit with no reset time given. */
212
+ export declare function limitUntil(hit: LimitHit, now: number): number;
213
+ /** At most this many usage-limit resumes per session. */
214
+ export declare const MAX_LIMIT_RESUMES = 6;
215
+ /** The prompt that resumes a run a usage limit cut off, on another account. */
216
+ export declare const LIMIT_RESUME_PROMPT = "Continue where you stopped. Your previous turn was cut off by a Claude usage limit and this session moved to another account. Same protocol; end with one line: WORKER-RESULT: done | blocked | failed \u2014 <one sentence>.";
217
+ /**
218
+ * The structured signal for a DESIGN run: the session declares an outcome of
219
+ * kind "design" (`synap_get_session` → `outcomes.outcomes[].kind`, the
220
+ * playbook's `expectedOutputs: [{kind: "design", label: "Design"}]`). The goal
221
+ * text is never read for it. A session whose outcomes could not be read
222
+ * THROWS: an unreadable session is not "not a design run".
223
+ */
224
+ export declare const DESIGN_OUTCOME_KIND = "design";
225
+ export declare function isDesignSession(getSessionText: string): boolean;
226
+ /**
227
+ * `code`: a git worktree, a `devbox/<id>` branch, a draft PR, room `QUESTION:`s.
228
+ * `work-folder`: a folder per session, no git, outputs filed to the pod, asks
229
+ * through the session's human-owned slots.
230
+ */
231
+ export type WorkerProtocol = "code" | "work-folder";
232
+ /** The run params that name a repository — the ones the pod's dispatch path mounts (`repoInputs`, external-agent-executor.ts). */
233
+ export declare const REPO_PARAM_KEYS: readonly ["repo", "repos", "branch"];
234
+ /** Deliverable kinds that only code work yields: the dispatch path's code outputs (`ExternalAgentOutputKey`) and `code`. */
235
+ export declare const CODE_OUTPUT_KINDS: readonly ["pull_request", "branch", "code"];
236
+ /**
237
+ * Which protocol a handed session gets, from the `synap_get_session` read.
238
+ *
239
+ * A session that runs NO playbook is an ad-hoc hand-off ("start this on my
240
+ * devbox"): the code protocol, exactly as before protocols existed. A PLAYBOOK
241
+ * RUN (`session.playbookId`) is a process over pod data — Produce Content's
242
+ * video edit, a CRM list, an interview — and gets the work-folder protocol,
243
+ * unless it carries code context: a repo or branch in its run params
244
+ * (`session.metadata.params`, read the same way the dispatch path reads them)
245
+ * or a code deliverable declared on the session or on any of its stages
246
+ * (`expectedOutputs`, `stages[].expectedOutputs`), so a code playbook stays
247
+ * code from its first stage on. The goal text is never read. An unreadable
248
+ * session THROWS: it is not "a code session".
249
+ */
250
+ export declare function sessionProtocol(getSessionText: string): WorkerProtocol;
251
+ /** A work-folder run's folder: `<root>/<sessionId>`. */
252
+ export declare function workFolderFor(root: string, sessionId: string): string;
253
+ /** The short id `claude --bg` prints ("backgrounded · fd009109"). */
254
+ export declare function parseBgId(output: string): string | undefined;
255
+ export interface BgEntry {
256
+ id: string;
257
+ sessionId?: string;
258
+ /** Background sessions: working | blocked | done | failed (Claude Code 2.1.296+). */
259
+ state?: string;
260
+ status?: string;
261
+ }
262
+ /** `claude agents --json --all` → entries. Anything but a JSON list THROWS (a failed read is not "gone"). */
263
+ export declare function parseAgentsList(text: string): BgEntry[];
264
+ export type BgPhase = "running" | "finished" | "blocked" | "gone";
265
+ export declare function bgPhase(entry: BgEntry | undefined): BgPhase;
266
+ /** The transcript of a Claude session: `<config>/projects/<any>/<sessionId>.jsonl`. */
267
+ export declare function findTranscript(claudeConfigDir: string | undefined, sessionId: string): string | undefined;
268
+ /** How a background run's transcript ends, reading only entries written since `sinceMs`. */
269
+ export declare function readTranscriptEnd(text: string, sinceMs: number): RunEnd & {
270
+ seen: number;
271
+ };
272
+ /** A background run blocked (it needs input nobody will give) this long is ended. */
273
+ export declare const BG_BLOCKED_MAX_MS: number;
274
+ /** A background run not yet listed, or listed with nothing new, is waited for this long after launch. */
275
+ export declare const BG_SETTLE_MS: number;
102
276
  /** The final `WORKER-RESULT:` line of a run's result text, if present. */
103
277
  export declare function workerVerdict(resultText: string | undefined): string | undefined;
104
278
  export interface RoomMessage {
@@ -118,5 +292,40 @@ export declare const MAX_RESUMES = 20;
118
292
  export declare function followUpsSince(messages: RoomMessage[], since: string, selfAgentId: string): RoomMessage[];
119
293
  /** The prompt that resumes a finished run with the room's new messages. */
120
294
  export declare function buildFollowUpPrompt(messages: RoomMessage[]): string;
295
+ export interface ExecResult {
296
+ code: number | null;
297
+ stdout: string;
298
+ stderr: string;
299
+ }
300
+ /** Runs a short-lived command (`claude --bg`, `claude agents`, `claude stop`). */
301
+ export type ExecFn = (bin: string, args: string[], o: {
302
+ cwd: string;
303
+ env: NodeJS.ProcessEnv;
304
+ }) => Promise<ExecResult>;
305
+ export interface WorkerDeps {
306
+ mcp: McpCallClient;
307
+ podUrl: string;
308
+ apiKey: string;
309
+ /** The worker agent's own user id: its posts never resume it. */
310
+ selfAgentId: string;
311
+ exec?: ExecFn;
312
+ /** The account probe's fetch (tests stub it). */
313
+ fetchImpl?: typeof fetch;
314
+ now?: () => number;
315
+ say?: (line: string) => void;
316
+ }
317
+ export interface Worker {
318
+ tick(): Promise<{
319
+ handed: number;
320
+ launched: number;
321
+ }>;
322
+ /** Re-read the background runs' state (design runs). */
323
+ watch(): Promise<void>;
324
+ waitForChildren(): Promise<void>;
325
+ backgroundRunning(): number;
326
+ stop(): void;
327
+ readonly state: WorkerState;
328
+ }
329
+ export declare function createWorker(opts: WorkerOptions, deps: WorkerDeps): Worker;
121
330
  export declare function workerCommand(opts: WorkerOptions): Promise<void>;
122
331
  export {};