@synap-core/cli 1.12.2 → 1.13.1-next.20261102.246dc73

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 (358) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -11
  3. package/dist/build-info.json +2 -3
  4. package/dist/commands/agents.d.ts +0 -1
  5. package/dist/commands/agents.js +13 -3
  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 +87 -1
  17. package/dist/commands/capability.js +174 -64
  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 +74 -44
  29. package/dist/commands/context.js.map +1 -1
  30. package/dist/commands/data-extra.d.ts +13 -0
  31. package/dist/commands/data-extra.js +35 -6
  32. package/dist/commands/data-extra.js.map +1 -1
  33. package/dist/commands/data.js +2 -1
  34. package/dist/commands/data.js.map +1 -1
  35. package/dist/commands/doctor.d.ts +39 -0
  36. package/dist/commands/doctor.js +136 -14
  37. package/dist/commands/doctor.js.map +1 -1
  38. package/dist/commands/hooks.d.ts +19 -0
  39. package/dist/commands/hooks.js +70 -0
  40. package/dist/commands/hooks.js.map +1 -0
  41. package/dist/commands/import.d.ts +25 -0
  42. package/dist/commands/import.js +98 -12
  43. package/dist/commands/import.js.map +1 -1
  44. package/dist/commands/init.d.ts +14 -0
  45. package/dist/commands/init.js +63 -21
  46. package/dist/commands/init.js.map +1 -1
  47. package/dist/commands/keys-request.d.ts +48 -0
  48. package/dist/commands/keys-request.js +236 -0
  49. package/dist/commands/keys-request.js.map +1 -0
  50. package/dist/commands/keys-request.test.d.ts +1 -0
  51. package/dist/commands/keys-request.test.js +176 -0
  52. package/dist/commands/keys-request.test.js.map +1 -0
  53. package/dist/commands/knowledge.d.ts +42 -5
  54. package/dist/commands/knowledge.js +94 -29
  55. package/dist/commands/knowledge.js.map +1 -1
  56. package/dist/commands/lens.js +2 -1
  57. package/dist/commands/lens.js.map +1 -1
  58. package/dist/commands/market-authoring.js +1 -1
  59. package/dist/commands/market-authoring.js.map +1 -1
  60. package/dist/commands/market.d.ts +89 -31
  61. package/dist/commands/market.js +215 -222
  62. package/dist/commands/market.js.map +1 -1
  63. package/dist/commands/mcp.d.ts +1 -1
  64. package/dist/commands/mcp.js +14 -9
  65. package/dist/commands/mcp.js.map +1 -1
  66. package/dist/commands/observe.category.test.d.ts +1 -0
  67. package/dist/commands/observe.category.test.js +59 -0
  68. package/dist/commands/observe.category.test.js.map +1 -0
  69. package/dist/commands/observe.d.ts +3 -0
  70. package/dist/commands/observe.js +7 -5
  71. package/dist/commands/observe.js.map +1 -1
  72. package/dist/commands/observe.title.test.d.ts +1 -0
  73. package/dist/commands/observe.title.test.js +37 -0
  74. package/dist/commands/observe.title.test.js.map +1 -0
  75. package/dist/commands/playbook.js +9 -0
  76. package/dist/commands/playbook.js.map +1 -1
  77. package/dist/commands/pods.d.ts +6 -1
  78. package/dist/commands/pods.js +38 -17
  79. package/dist/commands/pods.js.map +1 -1
  80. package/dist/commands/proposals-actions.js +7 -1
  81. package/dist/commands/proposals-actions.js.map +1 -1
  82. package/dist/commands/proton-setup.js +3 -1
  83. package/dist/commands/proton-setup.js.map +1 -1
  84. package/dist/commands/providers.d.ts +22 -6
  85. package/dist/commands/providers.js +39 -32
  86. package/dist/commands/providers.js.map +1 -1
  87. package/dist/commands/raycast.d.ts +15 -0
  88. package/dist/commands/raycast.js +36 -10
  89. package/dist/commands/raycast.js.map +1 -1
  90. package/dist/commands/session-feed-wait.d.ts +48 -0
  91. package/dist/commands/session-feed-wait.js +261 -0
  92. package/dist/commands/session-feed-wait.js.map +1 -0
  93. package/dist/commands/session-post.d.ts +40 -0
  94. package/dist/commands/session-post.js +96 -0
  95. package/dist/commands/session-post.js.map +1 -0
  96. package/dist/commands/session-wait.d.ts +9 -4
  97. package/dist/commands/session-wait.js +20 -5
  98. package/dist/commands/session-wait.js.map +1 -1
  99. package/dist/commands/sessions.d.ts +2 -0
  100. package/dist/commands/sessions.js +23 -0
  101. package/dist/commands/sessions.js.map +1 -1
  102. package/dist/commands/skills-commands.d.ts +2 -0
  103. package/dist/commands/skills-commands.js +9 -1
  104. package/dist/commands/skills-commands.js.map +1 -1
  105. package/dist/commands/skills-commands.test.d.ts +1 -0
  106. package/dist/commands/skills-commands.test.js +57 -0
  107. package/dist/commands/skills-commands.test.js.map +1 -0
  108. package/dist/commands/status.js +13 -7
  109. package/dist/commands/status.js.map +1 -1
  110. package/dist/commands/statusline.backoff.test.js +13 -3
  111. package/dist/commands/statusline.backoff.test.js.map +1 -1
  112. package/dist/commands/statusline.d.ts +104 -9
  113. package/dist/commands/statusline.js +392 -148
  114. package/dist/commands/statusline.js.map +1 -1
  115. package/dist/commands/statusline.line2.test.d.ts +15 -0
  116. package/dist/commands/statusline.line2.test.js +226 -0
  117. package/dist/commands/statusline.line2.test.js.map +1 -0
  118. package/dist/commands/statusline.needs-you.test.d.ts +1 -0
  119. package/dist/commands/statusline.needs-you.test.js +17 -0
  120. package/dist/commands/statusline.needs-you.test.js.map +1 -0
  121. package/dist/commands/statusline.now.test.d.ts +10 -0
  122. package/dist/commands/statusline.now.test.js +250 -0
  123. package/dist/commands/statusline.now.test.js.map +1 -0
  124. package/dist/commands/tracks.d.ts +68 -6
  125. package/dist/commands/tracks.js +272 -16
  126. package/dist/commands/tracks.js.map +1 -1
  127. package/dist/commands/upload.js +12 -0
  128. package/dist/commands/upload.js.map +1 -1
  129. package/dist/commands/wait.d.ts +124 -0
  130. package/dist/commands/wait.js +384 -0
  131. package/dist/commands/wait.js.map +1 -0
  132. package/dist/commands/wait.test.d.ts +8 -0
  133. package/dist/commands/wait.test.js +308 -0
  134. package/dist/commands/wait.test.js.map +1 -0
  135. package/dist/commands/whoami.d.ts +7 -0
  136. package/dist/commands/whoami.js +17 -0
  137. package/dist/commands/whoami.js.map +1 -1
  138. package/dist/commands/worker-accounts.d.ts +149 -0
  139. package/dist/commands/worker-accounts.js +339 -0
  140. package/dist/commands/worker-accounts.js.map +1 -0
  141. package/dist/commands/worker-accounts.test.d.ts +1 -0
  142. package/dist/commands/worker-accounts.test.js +224 -0
  143. package/dist/commands/worker-accounts.test.js.map +1 -0
  144. package/dist/commands/worker-github-app.d.ts +63 -0
  145. package/dist/commands/worker-github-app.js +161 -0
  146. package/dist/commands/worker-github-app.js.map +1 -0
  147. package/dist/commands/worker-github-app.test.d.ts +1 -0
  148. package/dist/commands/worker-github-app.test.js +102 -0
  149. package/dist/commands/worker-github-app.test.js.map +1 -0
  150. package/dist/commands/worker-github-broker.d.ts +39 -0
  151. package/dist/commands/worker-github-broker.js +106 -0
  152. package/dist/commands/worker-github-broker.js.map +1 -0
  153. package/dist/commands/worker-github-broker.test.d.ts +1 -0
  154. package/dist/commands/worker-github-broker.test.js +90 -0
  155. package/dist/commands/worker-github-broker.test.js.map +1 -0
  156. package/dist/commands/worker-runs.test.d.ts +1 -0
  157. package/dist/commands/worker-runs.test.js +150 -0
  158. package/dist/commands/worker-runs.test.js.map +1 -0
  159. package/dist/commands/worker-worktrees.d.ts +34 -0
  160. package/dist/commands/worker-worktrees.js +87 -0
  161. package/dist/commands/worker-worktrees.js.map +1 -0
  162. package/dist/commands/worker.d.ts +406 -10
  163. package/dist/commands/worker.js +1180 -126
  164. package/dist/commands/worker.js.map +1 -1
  165. package/dist/commands/worker.test.js +588 -11
  166. package/dist/commands/worker.test.js.map +1 -1
  167. package/dist/index.js +220 -28
  168. package/dist/index.js.map +1 -1
  169. package/dist/lib/agent-door.d.ts +1 -3
  170. package/dist/lib/agent-door.js +10 -7
  171. package/dist/lib/agent-door.js.map +1 -1
  172. package/dist/lib/agents-config.d.ts +9 -0
  173. package/dist/lib/agents-config.js +20 -0
  174. package/dist/lib/agents-config.js.map +1 -1
  175. package/dist/lib/atomic-file.d.ts +20 -1
  176. package/dist/lib/atomic-file.js +100 -2
  177. package/dist/lib/atomic-file.js.map +1 -1
  178. package/dist/lib/auth.d.ts +28 -2
  179. package/dist/lib/auth.js +52 -12
  180. package/dist/lib/auth.js.map +1 -1
  181. package/dist/lib/box/egress.d.ts +82 -0
  182. package/dist/lib/box/egress.js +264 -0
  183. package/dist/lib/box/egress.js.map +1 -0
  184. package/dist/lib/box/evidence.d.ts +86 -0
  185. package/dist/lib/box/evidence.js +121 -0
  186. package/dist/lib/box/evidence.js.map +1 -0
  187. package/dist/lib/box/job-server.d.ts +72 -0
  188. package/dist/lib/box/job-server.js +250 -0
  189. package/dist/lib/box/job-server.js.map +1 -0
  190. package/dist/lib/box/provisioner.d.ts +83 -0
  191. package/dist/lib/box/provisioner.js +312 -0
  192. package/dist/lib/box/provisioner.js.map +1 -0
  193. package/dist/lib/box/proxmox.d.ts +112 -0
  194. package/dist/lib/box/proxmox.js +211 -0
  195. package/dist/lib/box/proxmox.js.map +1 -0
  196. package/dist/lib/box/wire.d.ts +98 -0
  197. package/dist/lib/box/wire.js +70 -0
  198. package/dist/lib/box/wire.js.map +1 -0
  199. package/dist/lib/bridge-invocation.test.d.ts +1 -0
  200. package/dist/lib/bridge-invocation.test.js +75 -0
  201. package/dist/lib/bridge-invocation.test.js.map +1 -0
  202. package/dist/lib/bridge-status.d.ts +144 -0
  203. package/dist/lib/bridge-status.js +227 -0
  204. package/dist/lib/bridge-status.js.map +1 -0
  205. package/dist/lib/bridge-status.test.d.ts +6 -0
  206. package/dist/lib/bridge-status.test.js +197 -0
  207. package/dist/lib/bridge-status.test.js.map +1 -0
  208. package/dist/lib/client-header.test.d.ts +1 -0
  209. package/dist/lib/client-header.test.js +103 -0
  210. package/dist/lib/client-header.test.js.map +1 -0
  211. package/dist/lib/conversation-headers.d.ts +89 -9
  212. package/dist/lib/conversation-headers.js +156 -3
  213. package/dist/lib/conversation-headers.js.map +1 -1
  214. package/dist/lib/conversation-headers.test.d.ts +1 -0
  215. package/dist/lib/conversation-headers.test.js +78 -0
  216. package/dist/lib/conversation-headers.test.js.map +1 -0
  217. package/dist/lib/credential-class.d.ts +40 -2
  218. package/dist/lib/credential-class.js +48 -6
  219. package/dist/lib/credential-class.js.map +1 -1
  220. package/dist/lib/device-connect.d.ts +45 -0
  221. package/dist/lib/device-connect.js +60 -0
  222. package/dist/lib/device-connect.js.map +1 -1
  223. package/dist/lib/exporter-coverage.d.ts +1 -1
  224. package/dist/lib/exporter-coverage.js +1 -1
  225. package/dist/lib/goal-words.d.ts +38 -0
  226. package/dist/lib/goal-words.js +115 -0
  227. package/dist/lib/goal-words.js.map +1 -0
  228. package/dist/lib/hub-client.d.ts +87 -8
  229. package/dist/lib/hub-client.js +205 -70
  230. package/dist/lib/hub-client.js.map +1 -1
  231. package/dist/lib/init-handoff.d.ts +8 -0
  232. package/dist/lib/init-handoff.js +9 -2
  233. package/dist/lib/init-handoff.js.map +1 -1
  234. package/dist/lib/key-locations.d.ts +3 -3
  235. package/dist/lib/key-locations.js +3 -39
  236. package/dist/lib/key-locations.js.map +1 -1
  237. package/dist/lib/key-source.d.ts +3 -1
  238. package/dist/lib/key-source.js +7 -4
  239. package/dist/lib/key-source.js.map +1 -1
  240. package/dist/lib/knowledge-title.d.ts +3 -2
  241. package/dist/lib/knowledge-title.js +3 -2
  242. package/dist/lib/knowledge-title.js.map +1 -1
  243. package/dist/lib/machine-instance.d.ts +7 -5
  244. package/dist/lib/machine-instance.js +7 -5
  245. package/dist/lib/machine-instance.js.map +1 -1
  246. package/dist/lib/mcp-bridge.d.ts +50 -0
  247. package/dist/lib/mcp-bridge.js +232 -11
  248. package/dist/lib/mcp-bridge.js.map +1 -1
  249. package/dist/lib/mcp-bridge.test.js +224 -4
  250. package/dist/lib/mcp-bridge.test.js.map +1 -1
  251. package/dist/lib/mcp-call.d.ts +5 -1
  252. package/dist/lib/mcp-call.js +7 -6
  253. package/dist/lib/mcp-call.js.map +1 -1
  254. package/dist/lib/mcp-connector-url.test.d.ts +1 -0
  255. package/dist/lib/mcp-connector-url.test.js +13 -0
  256. package/dist/lib/mcp-connector-url.test.js.map +1 -0
  257. package/dist/lib/mcp-snippets.d.ts +16 -0
  258. package/dist/lib/mcp-snippets.js +20 -2
  259. package/dist/lib/mcp-snippets.js.map +1 -1
  260. package/dist/lib/now-line.d.ts +66 -0
  261. package/dist/lib/now-line.js +193 -0
  262. package/dist/lib/now-line.js.map +1 -0
  263. package/dist/lib/now-line.test.d.ts +5 -0
  264. package/dist/lib/now-line.test.js +177 -0
  265. package/dist/lib/now-line.test.js.map +1 -0
  266. package/dist/lib/package-updates.d.ts +66 -0
  267. package/dist/lib/package-updates.js +76 -0
  268. package/dist/lib/package-updates.js.map +1 -0
  269. package/dist/lib/pod-moved.d.ts +70 -0
  270. package/dist/lib/pod-moved.js +146 -0
  271. package/dist/lib/pod-moved.js.map +1 -0
  272. package/dist/lib/pod-reach.d.ts +39 -0
  273. package/dist/lib/pod-reach.js +117 -0
  274. package/dist/lib/pod-reach.js.map +1 -0
  275. package/dist/lib/pod-reach.test.d.ts +1 -0
  276. package/dist/lib/pod-reach.test.js +67 -0
  277. package/dist/lib/pod-reach.test.js.map +1 -0
  278. package/dist/lib/pod.d.ts +8 -4
  279. package/dist/lib/pod.js +12 -10
  280. package/dist/lib/pod.js.map +1 -1
  281. package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
  282. package/dist/lib/register-claude-code-mcp.test.js +97 -0
  283. package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
  284. package/dist/lib/review-credential.js +3 -1
  285. package/dist/lib/review-credential.js.map +1 -1
  286. package/dist/lib/safe-open.d.ts +5 -3
  287. package/dist/lib/safe-open.js +9 -8
  288. package/dist/lib/safe-open.js.map +1 -1
  289. package/dist/lib/self-host.d.ts +17 -0
  290. package/dist/lib/self-host.js +24 -0
  291. package/dist/lib/self-host.js.map +1 -0
  292. package/dist/lib/session-feed.d.ts +185 -0
  293. package/dist/lib/session-feed.js +257 -0
  294. package/dist/lib/session-feed.js.map +1 -0
  295. package/dist/lib/targets.d.ts +52 -3
  296. package/dist/lib/targets.js +150 -209
  297. package/dist/lib/targets.js.map +1 -1
  298. package/dist/lib/template-lifecycle.d.ts +0 -31
  299. package/dist/lib/template-lifecycle.js +0 -74
  300. package/dist/lib/template-lifecycle.js.map +1 -1
  301. package/dist/lib/term.d.ts +24 -0
  302. package/dist/lib/term.js +52 -0
  303. package/dist/lib/term.js.map +1 -0
  304. package/dist/lib/term.test.d.ts +1 -0
  305. package/dist/lib/term.test.js +29 -0
  306. package/dist/lib/term.test.js.map +1 -0
  307. package/dist/lib/transcript-index.d.ts +94 -0
  308. package/dist/lib/transcript-index.js +321 -0
  309. package/dist/lib/transcript-index.js.map +1 -0
  310. package/dist/lib/transcript-index.test.d.ts +10 -0
  311. package/dist/lib/transcript-index.test.js +200 -0
  312. package/dist/lib/transcript-index.test.js.map +1 -0
  313. package/dist/lib/wait-help.d.ts +11 -0
  314. package/dist/lib/wait-help.js +25 -0
  315. package/dist/lib/wait-help.js.map +1 -0
  316. package/dist/lib/wait-state.d.ts +57 -0
  317. package/dist/lib/wait-state.js +114 -0
  318. package/dist/lib/wait-state.js.map +1 -0
  319. package/dist/lib/wake-hook-settings.d.ts +57 -0
  320. package/dist/lib/wake-hook-settings.js +153 -0
  321. package/dist/lib/wake-hook-settings.js.map +1 -0
  322. package/dist/lib/wake-state.d.ts +65 -0
  323. package/dist/lib/wake-state.js +122 -0
  324. package/dist/lib/wake-state.js.map +1 -0
  325. package/package.json +5 -2
  326. package/skills/README.md +1 -1
  327. package/skills/agent-os/SKILL.md +8 -8
  328. package/skills/synap/SKILL.md +188 -94
  329. package/skills/synap/code-skills.md +84 -0
  330. package/skills/synap/concepts.md +38 -20
  331. package/skills/synap/creative-loop.md +1 -1
  332. package/skills/synap/document-embeds.md +17 -1
  333. package/skills/synap/focus-sessions.md +17 -8
  334. package/skills/synap/from-intent.md +33 -17
  335. package/skills/synap/governance-rules.md +3 -1
  336. package/skills/synap/hand-off.md +10 -6
  337. package/skills/synap/lenses.md +4 -4
  338. package/skills/synap/linking.md +2 -2
  339. package/skills/synap/mental-model.md +1 -1
  340. package/skills/synap/operating-mode-rules.md +1 -1
  341. package/skills/synap/quick-reference.md +2 -1
  342. package/skills/synap/reflexes.md +8 -8
  343. package/skills/synap/viewframe-cells.md +1 -1
  344. package/skills/synap/work-model.md +24 -10
  345. package/skills/synap/workspace-design.md +5 -5
  346. package/skills/synap/writes.md +16 -9
  347. package/skills/synap/writing-titles.md +7 -0
  348. package/skills/synap-app/SKILL.md +148 -66
  349. package/skills/synap-app/creating-the-base-app.md +12 -7
  350. package/skills/synap-app/governance.md +27 -16
  351. package/skills/synap-app/install-commands.md +18 -9
  352. package/skills/synap-app/overview.md +16 -9
  353. package/skills/synap-app/using-the-sdk.md +75 -25
  354. package/skills/synap-market/SKILL.md +1 -1
  355. package/skills/synap-market/governance-and-catalog.md +1 -1
  356. package/skills/synap-schema/SKILL.md +24 -21
  357. package/skills/synap-schema/intent-vocabulary-ssot.md +24 -21
  358. package/templates/box/runner.py +206 -0
@@ -21,10 +21,33 @@
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.
44
+ * A run's verdict is ALSO recorded on its session (`settle`), and the worker's
45
+ * orient poll carries its served stamp (`X-Synap-Runner`): the pod's proof
46
+ * that a process serves this agent.
27
47
  */
48
+ import { type McpCallClient } from "../lib/mcp-call.js";
49
+ import { type GithubRunEnv, type InstallationTokenSource } from "./worker-github-app.js";
50
+ import { type GitFn } from "./worker-worktrees.js";
28
51
  export interface WorkerOptions {
29
52
  agent: string;
30
53
  interval?: string;
@@ -33,16 +56,29 @@ export interface WorkerOptions {
33
56
  maxParallel?: string;
34
57
  claudeBin?: string;
35
58
  claudeConfigDir?: string;
36
- mcpServer?: string;
37
59
  allowedTools?: string;
38
60
  skipPermissions?: boolean;
39
61
  dryRun?: boolean;
62
+ /** The Claude accounts file (default ~/.config/synap-worker/accounts.json, used when it exists). */
63
+ accounts?: string;
64
+ /** The GitHub App env file ({GITHUB_APP_ID, GITHUB_APP_PRIVATE_KEY_FILE}; default ~/.config/synap-agent-app.env when it exists). */
65
+ githubApp?: string;
66
+ /** Where work-folder runs get their folder, one per session (default ~/synap-work). */
67
+ workRoot?: string;
40
68
  }
41
69
  export interface HandedItem {
42
70
  id: string;
43
71
  goal: string | null;
72
+ /**
73
+ * A session that went quiet (stale) while handed to this agent, handed back
74
+ * to be RESUMED: it never launches fresh. Absent from an older pod's items.
75
+ */
76
+ resume?: true;
77
+ /** When it went quiet (ISO), with `resume`. */
78
+ quietSince?: string;
44
79
  }
45
- export type RunStatus = "running" | "done" | "failed";
80
+ /** `limited`: cut off by a usage limit, waiting to be resumed on another account. */
81
+ export type RunStatus = "running" | "done" | "failed" | "limited";
46
82
  export interface RunRecord {
47
83
  sessionId: string;
48
84
  status: RunStatus;
@@ -54,6 +90,58 @@ export interface RunRecord {
54
90
  result?: string;
55
91
  /** How many times a room follow-up resumed this Claude conversation. */
56
92
  resumes?: number;
93
+ /** How many times a run that failed before Claude started was relaunched. */
94
+ launchRetries?: number;
95
+ /** The accounts-file id the latest launch ran on — an id, never a token. */
96
+ accountId?: string;
97
+ /** `print` = `claude -p` (default); `bg` = `claude --bg`, a design run. */
98
+ mode?: "print" | "bg";
99
+ /** The short id `claude --bg` printed (what `claude agents|stop` take). */
100
+ bgId?: string;
101
+ /** When the latest launch (first or resumed) started. */
102
+ launchedAt?: string;
103
+ /** How many times a run cut off by a usage limit was resumed on another account. */
104
+ limitResumes?: number;
105
+ /** A background run first seen blocked (needs input) at this time. */
106
+ blockedSince?: string;
107
+ /** Which protocol the run was launched with (absent: a run from before protocols = code). */
108
+ protocol?: WorkerProtocol;
109
+ /** A work-folder run's folder: its cwd, which every resume reuses (Claude finds a conversation by its cwd). */
110
+ workDir?: string;
111
+ /** A code run's own folder for its worktrees: its cwd, which every resume reuses. */
112
+ treeDir?: string;
113
+ /** Worktrees a finished run left because they hold unpushed or uncommitted work. */
114
+ keptTrees?: string[];
115
+ /** The latest launch's process identity (`X-Synap-Process`), what its runner row is keyed by. */
116
+ process?: string;
117
+ /** The model the run's Claude Code said it runs (its stream's `init`), reported as `X-Synap-Model`. */
118
+ model?: string;
119
+ /** The quiet period (its `quietSince`, "" when the pod gave none) this run was last resumed for. */
120
+ resumedQuietSince?: string;
121
+ /** The latest launch's end, not yet recorded on the pod (`settle`): retried each tick until it lands. */
122
+ unsettled?: PendingSettle;
123
+ /** When the latest end was recorded on the pod. */
124
+ settledAt?: string;
125
+ }
126
+ /**
127
+ * A run's end the pod has not heard yet, saved before the first try so that a
128
+ * crash or an MCP blip between the local save and the pod write loses nothing:
129
+ * the next tick (of this worker, or of the next one after a restart) retries it.
130
+ * It names its own launch, so a later resume of the same session never changes
131
+ * which runner it ends or which Result post it is.
132
+ */
133
+ export interface PendingSettle {
134
+ /** The launch's process identity and conversation: what the pod's runner row is keyed by. */
135
+ process?: string;
136
+ claudeSessionId?: string;
137
+ /** The verdict to record; absent: the pod only hears the runner ended. */
138
+ verdict?: {
139
+ status: VerdictStatus;
140
+ sentence: string;
141
+ };
142
+ /** The Result post's `idempotencyKey`: a retry returns the post that already landed. */
143
+ key: string;
144
+ attempts: number;
57
145
  }
58
146
  interface WorkerState {
59
147
  runs: Record<string, RunRecord>;
@@ -81,14 +169,67 @@ export declare class AgentPausedError extends Error {
81
169
  * block throws `AgentBoundForDispatchError`.
82
170
  */
83
171
  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
172
  /**
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).
173
+ * A run that failed BEFORE Claude started (no Claude session: an expired login,
174
+ * exhausted credits) is relaunched after 30 min, then 1 h, 2 h and 4 h, enough
175
+ * to outlast a credit reset. A run Claude did start is resumed only by a room
176
+ * follow-up, never relaunched from scratch.
177
+ */
178
+ export declare const LAUNCH_RETRY_BASE_MS: number;
179
+ export declare const MAX_LAUNCH_RETRIES = 4;
180
+ /**
181
+ * Sessions to launch now: never launched, or due a relaunch (see above). A
182
+ * `resume` item is never one of them: it continues its conversation or waits
183
+ * (see `tick`), so an empty state file never relaunches every quiet session.
184
+ */
185
+ export declare function pickNew(items: HandedItem[], state: WorkerState, slots: number, now?: number): HandedItem[];
186
+ /**
187
+ * The pod MCP server every run gets, under this name, carrying the WORKER
188
+ * AGENT's own key. Runs never inherit the server in ~/.claude.json: whatever
189
+ * key that file holds (a `synap login --reconnect` on the box rewrites it with
190
+ * another agent's) would decide who the run posts as, and the worker would
191
+ * then read its own posts as follow-ups (2026-10-20).
192
+ */
193
+ export declare const RUN_MCP_SERVER = "synap-worker";
194
+ /**
195
+ * The provider every run's model is served by: Anthropic, on the account's
196
+ * subscription. By construction of the run's environment (`workerEnv`): no
197
+ * `ANTHROPIC_*` (key, token, base URL) and no provider switch
198
+ * (`RUN_ENV_BLOCKLIST`) reaches it. Reported as `X-Synap-Model-Provider`.
199
+ */
200
+ export declare const WORKER_MODEL_PROVIDER = "anthropic";
201
+ export declare function runMcpConfig(podUrl: string, apiKey: string,
202
+ /** The run's Claude session id: names the conversation to the pod, one id across resumes. */
203
+ claudeSessionId?: string,
204
+ /** The launch's process identity (`runProcessIdentity`): the pod keeps one runner row per process. */
205
+ processIdentity?: string,
206
+ /** The model the run is known to use (a resume: what its first launch said), when known. */
207
+ model?: string): {
208
+ mcpServers: Record<string, unknown>;
209
+ };
210
+ /**
211
+ * A launch's process identity, `<host>:<pid>:<startedAtMs>` (the pod's
212
+ * `X-Synap-Process`). The config is written before `claude` exists, so the pid
213
+ * is the worker's and the time is the launch's: a resume is a new launch and
214
+ * reads as a new process, never a twin of the one that ended.
215
+ */
216
+ export declare function runProcessIdentity(launchedAtMs: number, hostname?: string, pid?: number): string;
217
+ /**
218
+ * The headers of the worker's calls once a run's process exited: the run's
219
+ * conversation and process, state `ended`, so the pod ends that runner at once
220
+ * rather than when its live window runs out. None for a run that never named
221
+ * its conversation or process.
89
222
  */
90
- export declare function findMcpServerName(claudeJson: unknown, podUrl: string): string | null;
223
+ export declare function runEndHeaders(rec: Pick<RunRecord, "claudeSessionId" | "process" | "model">): Record<string, string> | undefined;
224
+ /** Writes the run config owner-only (it holds the key) and returns its path. */
225
+ export declare function writeRunMcpConfig(dir: string, config: {
226
+ mcpServers: Record<string, unknown>;
227
+ }, name?: string): string;
91
228
  export declare const DEFAULT_ALLOWED_TOOLS: string[];
229
+ /** The tools a design run adds: the claude.ai Artifact tool (and the search that loads deferred tools). */
230
+ export declare const DESIGN_EXTRA_TOOLS: string[];
231
+ /** The tools a work-folder run adds: skills (the HyperFrames workflow is one). */
232
+ export declare const WORK_FOLDER_EXTRA_TOOLS: string[];
92
233
  /** The protocol the launched Claude Code follows for one handed session. */
93
234
  export declare function buildWorkerPrompt(p: {
94
235
  sessionId: string;
@@ -96,11 +237,216 @@ export declare function buildWorkerPrompt(p: {
96
237
  agentName: string;
97
238
  cwd: string;
98
239
  mcpServer: string;
240
+ /** A design run: the deliverable is a claude.ai Design artifact. */
241
+ design?: boolean;
242
+ /** A code run's own folder: where its worktrees go, so two runs never share a checkout. */
243
+ treeDir?: string;
244
+ }): string;
245
+ /** How long a work-folder run waits for an answer to its ask before it ends `blocked`. */
246
+ export declare const ASK_WAIT_MINUTES = 30;
247
+ /**
248
+ * The protocol for a WORK-FOLDER session (`sessionProtocol`): no git; files in
249
+ * the session's folder; outputs filed to the pod; questions asked through a
250
+ * human-owned slot with an ask (what Content Studio, Relay and the Needs-you
251
+ * list show), never a room `QUESTION:` line.
252
+ */
253
+ export declare function buildWorkFolderPrompt(p: {
254
+ sessionId: string;
255
+ goal: string | null;
256
+ agentName: string;
257
+ workDir: string;
258
+ mcpServer: string;
99
259
  }): string;
100
- /** The launched environment: the subscription, never a stray API key. */
101
- export declare function workerEnv(base: NodeJS.ProcessEnv, claudeConfigDir?: string): NodeJS.ProcessEnv;
260
+ /**
261
+ * What the allowlist's `CLAUDE_*` must NOT pass: the variables that switch
262
+ * Claude Code off the subscription to another provider (Bedrock, Vertex,
263
+ * Foundry, Bedrock Mantle, Claude Platform on AWS — `CLAUDE_CODE_USE_*`), skip
264
+ * that provider's own auth for a gateway (`CLAUDE_CODE_SKIP_*_AUTH`), or hand
265
+ * routing to a host platform (`CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST`). Any
266
+ * future `CLAUDE_CODE_USE_*` provider is blocked too; the one `USE_` flag that
267
+ * is not a provider (the Windows PowerShell tool) passes. Without this a run
268
+ * would report `anthropic` while another provider served it.
269
+ */
270
+ export declare const RUN_ENV_BLOCKLIST: RegExp[];
271
+ export declare const RUN_ENV_ALLOWLIST: RegExp[];
272
+ /**
273
+ * The launched environment, built from an ALLOWLIST: a secret in the worker's
274
+ * own environment (its env file holds deploy tokens) never reaches a run's
275
+ * Bash. The subscription, never a stray API key. With an account picked, its
276
+ * token REPLACES any token the worker inherited. GitHub: only the App's.
277
+ */
278
+ export declare function workerEnv(base: NodeJS.ProcessEnv, claudeConfigDir?: string, oauthToken?: string, github?: GithubRunEnv): NodeJS.ProcessEnv;
279
+ export interface LimitHit {
280
+ error: string;
281
+ /** When the limit lifts (ms), when Claude Code said. */
282
+ resetsAt?: number;
283
+ }
284
+ /** What one run's events say about how it ended. */
285
+ export interface RunEnd {
286
+ claudeSessionId?: string;
287
+ /** The model the stream's `init` names, when it is an id the pod keeps. */
288
+ model?: string;
289
+ /** The `result` text (stream) or the last main assistant text (transcript). */
290
+ text?: string;
291
+ /** Set when the run's LAST main-thread turn was refused by a usage limit. */
292
+ limit?: LimitHit;
293
+ isError?: boolean;
294
+ }
295
+ /**
296
+ * Fold one event (a stream-json line of `claude -p`, or a transcript line of
297
+ * a background session — the two spell the fields differently) into the run's
298
+ * ending. A later healthy assistant message clears an earlier limit: only a
299
+ * run whose last turn hit the limit "ended on a limit".
300
+ */
301
+ export declare function foldRunEvent(end: RunEnd, ev: Record<string, unknown>, rejectedResetsAt?: {
302
+ at?: number;
303
+ }): RunEnd;
304
+ /** A run that printed its WORKER-RESULT verdict finished its protocol: never a limit. */
305
+ export declare function endedOnLimit(end: RunEnd): LimitHit | undefined;
306
+ /** How long an account stays out after a limit with no reset time given. */
307
+ export declare function limitUntil(hit: LimitHit, now: number): number;
308
+ /** At most this many usage-limit resumes per session. */
309
+ export declare const MAX_LIMIT_RESUMES = 6;
310
+ /** The prompt that resumes a run a usage limit cut off, on another account. */
311
+ 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>.";
312
+ /**
313
+ * The structured signal for a DESIGN run: the session declares an outcome of
314
+ * kind "design" (`synap_get_session` → `outcomes.outcomes[].kind`, the
315
+ * playbook's `expectedOutputs: [{kind: "design", label: "Design"}]`). The goal
316
+ * text is never read for it. A session whose outcomes could not be read
317
+ * THROWS: an unreadable session is not "not a design run".
318
+ */
319
+ export declare const DESIGN_OUTCOME_KIND = "design";
320
+ export declare function isDesignSession(getSessionText: string): boolean;
321
+ /**
322
+ * `code`: a git worktree, a `devbox/<id>` branch, a draft PR, room `QUESTION:`s.
323
+ * `work-folder`: a folder per session, no git, outputs filed to the pod, asks
324
+ * through the session's human-owned slots.
325
+ */
326
+ export type WorkerProtocol = "code" | "work-folder";
327
+ /** The run params that name a repository — the ones the pod's dispatch path mounts (`repoInputs`, external-agent-executor.ts). */
328
+ export declare const REPO_PARAM_KEYS: readonly ["repo", "repos", "branch"];
329
+ /** Deliverable kinds that only code work yields: the dispatch path's code outputs (`ExternalAgentOutputKey`) and `code`. */
330
+ export declare const CODE_OUTPUT_KINDS: readonly ["pull_request", "branch", "code"];
331
+ /**
332
+ * Which protocol a handed session gets, from the `synap_get_session` read.
333
+ *
334
+ * A session that runs NO playbook is an ad-hoc hand-off ("start this on my
335
+ * devbox"): the code protocol, exactly as before protocols existed. A PLAYBOOK
336
+ * RUN (`session.playbookId`) is a process over pod data — Produce Content's
337
+ * video edit, a CRM list, an interview — and gets the work-folder protocol,
338
+ * unless it carries code context: a repo or branch in its run params
339
+ * (`session.metadata.params`, read the same way the dispatch path reads them)
340
+ * or a code deliverable declared on the session or on any of its stages
341
+ * (`expectedOutputs`, `stages[].expectedOutputs`), so a code playbook stays
342
+ * code from its first stage on. The goal text is never read. An unreadable
343
+ * session THROWS: it is not "a code session".
344
+ */
345
+ export declare function sessionProtocol(getSessionText: string): WorkerProtocol;
346
+ /** A work-folder run's folder: `<root>/<sessionId>`. */
347
+ export declare function workFolderFor(root: string, sessionId: string): string;
348
+ /** The short id `claude --bg` prints ("backgrounded · fd009109"). */
349
+ export declare function parseBgId(output: string): string | undefined;
350
+ export interface BgEntry {
351
+ id: string;
352
+ sessionId?: string;
353
+ /** Background sessions: working | blocked | done | failed (Claude Code 2.1.296+). */
354
+ state?: string;
355
+ status?: string;
356
+ }
357
+ /** `claude agents --json --all` → entries. Anything but a JSON list THROWS (a failed read is not "gone"). */
358
+ export declare function parseAgentsList(text: string): BgEntry[];
359
+ export type BgPhase = "running" | "finished" | "blocked" | "gone";
360
+ export declare function bgPhase(entry: BgEntry | undefined): BgPhase;
361
+ /** The transcript of a Claude session: `<config>/projects/<any>/<sessionId>.jsonl`. */
362
+ export declare function findTranscript(claudeConfigDir: string | undefined, sessionId: string): string | undefined;
363
+ /** How a background run's transcript ends, reading only entries written since `sinceMs`. */
364
+ export declare function readTranscriptEnd(text: string, sinceMs: number): RunEnd & {
365
+ seen: number;
366
+ };
367
+ /** A background run blocked (it needs input nobody will give) this long is ended. */
368
+ export declare const BG_BLOCKED_MAX_MS: number;
369
+ /** A background run not yet listed, or listed with nothing new, is waited for this long after launch. */
370
+ export declare const BG_SETTLE_MS: number;
102
371
  /** The final `WORKER-RESULT:` line of a run's result text, if present. */
103
372
  export declare function workerVerdict(resultText: string | undefined): string | undefined;
373
+ export type VerdictStatus = "done" | "blocked" | "failed";
374
+ /**
375
+ * `done — <sentence>` (a `workerVerdict`) → its status and sentence; anything
376
+ * else is no verdict. The prompt's own template echoed back
377
+ * (`done | blocked | failed — …`) names no status: it is no verdict either.
378
+ */
379
+ export declare function parseVerdict(verdict: string | undefined): {
380
+ status: VerdictStatus;
381
+ sentence: string;
382
+ } | undefined;
383
+ /**
384
+ * The verdict the session hears, given how the process ended: `done` only from
385
+ * a run that exited cleanly; a run that said `done` and then exited non-zero is
386
+ * `failed`, with what it said kept. `blocked` and `failed` stand as they are.
387
+ */
388
+ export declare function verdictForExit(v: {
389
+ status: VerdictStatus;
390
+ sentence: string;
391
+ }, exitedOk: boolean, exitCode?: number | null): {
392
+ status: VerdictStatus;
393
+ sentence: string;
394
+ };
395
+ /** The one room line a verdict becomes. */
396
+ export declare function verdictRoomLine(v: {
397
+ status: VerdictStatus;
398
+ sentence: string;
399
+ }): string;
400
+ /**
401
+ * What the room hears from a run that FAILED without a verdict (it crashed,
402
+ * exited non-zero without `WORKER-RESULT:`, sat blocked, vanished, ran out of
403
+ * usage-limit resumes, or the worker restarted under it): how it ended and the
404
+ * reason the record keeps, on one line.
405
+ */
406
+ export declare function deadRunSentence(rec: Pick<RunRecord, "result" | "exitCode">): string;
407
+ /**
408
+ * At most this many tries to record one run's end on the pod. A retry runs
409
+ * only after the tick's orient read answered, so a pod outage does not use them up.
410
+ */
411
+ export declare const MAX_SETTLE_ATTEMPTS = 10;
412
+ /**
413
+ * The end a run owes the pod, given what it said and how its process ended:
414
+ * its verdict (`verdictForExit`), or for a run that failed without one a
415
+ * synthesised `failed` (`deadRunSentence`), so a dead run is never silent.
416
+ * `undefined` when there is nothing to tell (no verdict, not failed, and no
417
+ * runner to end).
418
+ */
419
+ export declare function pendingSettle(rec: RunRecord, verdictLine: string | undefined, exitedOk: boolean): PendingSettle | undefined;
420
+ /**
421
+ * Outcome kinds a verdict never claims: a pull request is delivered only when
422
+ * it merges (rule work-units), and the merge sweeper marks it met then; a
423
+ * branch or a commit is a step toward that PR, not a deliverable of its own.
424
+ */
425
+ export declare const UNCLAIMABLE_OUTCOME_KINDS: ReadonlySet<string>;
426
+ /** What the session read says a `done` verdict may claim. */
427
+ export type VerdictClaim = {
428
+ kind: "one";
429
+ key: string;
430
+ } | {
431
+ kind: "none";
432
+ } | {
433
+ kind: "several";
434
+ keys: string[];
435
+ }
436
+ /** The outcomes list could not be read: nothing is claimed, and that is said. */
437
+ | {
438
+ kind: "unreadable";
439
+ why: string;
440
+ };
441
+ /**
442
+ * The outcome a `done` verdict claims, from the `synap_get_session` read: the
443
+ * session's ONE open deliverable the agent owns (not a fact, not the person's,
444
+ * not met, not withdrawn, never a PR, branch or commit). None, or several, and
445
+ * nothing is claimed: which of several the run finished is the run's to say
446
+ * (it claims each as it records it). An outcomes list that could not be read is
447
+ * `unreadable`, never "none open".
448
+ */
449
+ export declare function verdictClaim(getSessionText: string): VerdictClaim;
104
450
  export interface RoomMessage {
105
451
  id?: string;
106
452
  content?: string;
@@ -116,7 +462,57 @@ export declare const MAX_RESUMES = 20;
116
462
  * run. The worker's own posts carry its agent id and never resume it.
117
463
  */
118
464
  export declare function followUpsSince(messages: RoomMessage[], since: string, selfAgentId: string): RoomMessage[];
465
+ /**
466
+ * Whether a session's quiet period began with THIS worker's own run: the pod's
467
+ * `quietSince` is the session's newest activity, and the run's own room posts
468
+ * (its claim, its "Look at first:", the worker's `Result:` line) count. Quiet
469
+ * since then means the run ended and nothing happened after it; resuming it
470
+ * would only re-run it (up to MAX_RESUMES paid runs). Someone else's message
471
+ * after the run resumes it through the follow-up path instead.
472
+ */
473
+ export declare function quietIsOwnRun(item: Pick<HandedItem, "quietSince">, rec: Pick<RunRecord, "launchedAt">): boolean;
474
+ /** The prompt that resumes a run whose session went quiet and was handed back (`resume`). */
475
+ export declare function buildQuietResumePrompt(quietSince: string | undefined): string;
119
476
  /** The prompt that resumes a finished run with the room's new messages. */
120
477
  export declare function buildFollowUpPrompt(messages: RoomMessage[]): string;
478
+ export interface ExecResult {
479
+ code: number | null;
480
+ stdout: string;
481
+ stderr: string;
482
+ }
483
+ /** Runs a short-lived command (`claude --bg`, `claude agents`, `claude stop`). */
484
+ export type ExecFn = (bin: string, args: string[], o: {
485
+ cwd: string;
486
+ env: NodeJS.ProcessEnv;
487
+ }) => Promise<ExecResult>;
488
+ export interface WorkerDeps {
489
+ mcp: McpCallClient;
490
+ podUrl: string;
491
+ apiKey: string;
492
+ /** The worker agent's own user id: its posts never resume it. */
493
+ selfAgentId: string;
494
+ exec?: ExecFn;
495
+ /** The account probe's fetch (tests stub it). */
496
+ fetchImpl?: typeof fetch;
497
+ now?: () => number;
498
+ say?: (line: string) => void;
499
+ /** The App's installation token (tests stub it); default: from the GitHub App file, when there is one. */
500
+ githubToken?: InstallationTokenSource;
501
+ /** `git` for the worktree sweep (tests stub it). */
502
+ git?: GitFn;
503
+ }
504
+ export interface Worker {
505
+ tick(): Promise<{
506
+ handed: number;
507
+ launched: number;
508
+ }>;
509
+ /** Re-read the background runs' state (design runs). */
510
+ watch(): Promise<void>;
511
+ waitForChildren(): Promise<void>;
512
+ backgroundRunning(): number;
513
+ stop(): void;
514
+ readonly state: WorkerState;
515
+ }
516
+ export declare function createWorker(opts: WorkerOptions, deps: WorkerDeps): Worker;
121
517
  export declare function workerCommand(opts: WorkerOptions): Promise<void>;
122
518
  export {};