@humwick/server 0.130.2 → 0.130.3

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 (570) hide show
  1. package/bundled/prompts/manifest.json +1 -0
  2. package/bundled/prompts/task.hydration.md +1 -1
  3. package/bundled/roles/builder.md +1 -1
  4. package/docs/guides/sub-coordinators.md +12 -5
  5. package/docs/guides/tools-coordination.md +1 -0
  6. package/docs/guides/workflows.md +16 -0
  7. package/docs/openapi.json +73 -4
  8. package/package.json +8 -7
  9. package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
  10. package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
  11. package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
  12. package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
  13. package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
  14. package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
  15. package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
  16. package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
  17. package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
  18. package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
  19. package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
  20. package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
  21. package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
  22. package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
  23. package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
  24. package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
  25. package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
  26. package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
  27. package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
  28. package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
  29. package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
  30. package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
  31. package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
  32. package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
  33. package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
  34. package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
  35. package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
  36. package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
  37. package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
  38. package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
  39. package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
  40. package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
  41. package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
  42. package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
  43. package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
  44. package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
  45. package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
  46. package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
  47. package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
  48. package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
  49. package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
  50. package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
  51. package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
  53. package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
  54. package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
  55. package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
  56. package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
  57. package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
  58. package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
  59. package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
  60. package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
  61. package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
  62. package/public/assets/provider-display-BEeLXC_D.js +2 -0
  63. package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
  64. package/public/assets/run-card-Dt4I4jaP.js +2 -0
  65. package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
  66. package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
  67. package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
  68. package/public/assets/shipping-H6gzEeZB.js +2 -0
  69. package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
  70. package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
  71. package/public/assets/store-DKPDIZBe.js +9 -0
  72. package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
  73. package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
  74. package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
  75. package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
  76. package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
  77. package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
  78. package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
  79. package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
  80. package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
  81. package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
  82. package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
  83. package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
  84. package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
  85. package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
  86. package/public/cosmos.html +4 -4
  87. package/public/index.html +28 -28
  88. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  89. package/runner/src/adapters/claude-headless.ts +1 -1
  90. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  91. package/runner/src/adapters/claude-session-probe.ts +1 -1
  92. package/runner/src/adapters/claude-tmux.ts +38 -10
  93. package/runner/src/adapters/claude.ts +28 -75
  94. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  95. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
  96. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  97. package/runner/src/claude-system-prompt.ts +49 -0
  98. package/runner/src/launch-assembly.ts +14 -10
  99. package/runner/src/profile-home.ts +1 -1
  100. package/runner/src/project-instructions.ts +2 -2
  101. package/runner/src/provider-command.ts +18 -0
  102. package/runner/src/provider-setup.ts +2 -1
  103. package/runner/src/runner-core.ts +14 -15
  104. package/runner/src/runner-helpers.ts +0 -8
  105. package/runner/src/session-scratch.ts +6 -2
  106. package/runner/test-support/provisioning-context.ts +4 -2
  107. package/runner/test-support/runner-harness.ts +2 -1
  108. package/scripts/steward-policy-cleanup.ts +2 -2
  109. package/src/agent-authz.ts +2 -2
  110. package/src/agent-drive-arbiter.ts +3 -8
  111. package/src/agent-exit-cleanup-async.ts +2 -2
  112. package/src/agent-exit-cleanup.ts +23 -19
  113. package/src/agent-lifecycle-events.ts +112 -85
  114. package/src/agent-ref.ts +3 -2
  115. package/src/agent-status-events.ts +43 -14
  116. package/src/auth/password.ts +4 -3
  117. package/src/auth/session-refresh.ts +1 -1
  118. package/src/auth/session.test-fixture.ts +2 -2
  119. package/src/auth/session.ts +7 -7
  120. package/src/automations/crud.ts +8 -81
  121. package/src/automations/dispatch.ts +33 -58
  122. package/src/automations/index.ts +1 -1
  123. package/src/automations/persistence.ts +65 -0
  124. package/src/automations/precheck.ts +18 -16
  125. package/src/automations/read-async.ts +11 -0
  126. package/src/automations/reconcile.ts +30 -39
  127. package/src/automations/storage.ts +33 -10
  128. package/src/automations/write-async.ts +33 -0
  129. package/src/branch-land-notice.ts +3 -3
  130. package/src/branch-landed.ts +25 -23
  131. package/src/bus.ts +21 -19
  132. package/src/cd-deploy-notify.ts +2 -2
  133. package/src/ci/notifications.ts +4 -4
  134. package/src/ci/root-missing.ts +3 -3
  135. package/src/ci/transition-notify.ts +5 -5
  136. package/src/claude-app/oauth-http.ts +3 -3
  137. package/src/cli/workflow.ts +12 -3
  138. package/src/commands-db.ts +4 -4
  139. package/src/commands-write.ts +8 -0
  140. package/src/compaction-watch.ts +10 -8
  141. package/src/config-store-write.ts +2 -2
  142. package/src/config.ts +4 -11
  143. package/src/connectors.ts +10 -8
  144. package/src/context-advisory.ts +22 -21
  145. package/src/db/agent-action-write.ts +36 -0
  146. package/src/db/agent-control-async.ts +9 -0
  147. package/src/db/agent-control-write.ts +49 -0
  148. package/src/db/agent-effort-observe.ts +22 -0
  149. package/src/db/agent-meta.ts +14 -3
  150. package/src/db/agents-async.ts +8 -5
  151. package/src/db/agents.ts +15 -12
  152. package/src/db/auth-identities.ts +2 -2
  153. package/src/db/automation-read-ops.ts +11 -0
  154. package/src/db/automation-write-ops.ts +46 -0
  155. package/src/db/blackboard.ts +2 -2
  156. package/src/db/browser-session-write.ts +32 -0
  157. package/src/db/bus-outbox-write-ops.ts +3 -1
  158. package/src/db/checkout-refresh-schema.ts +47 -0
  159. package/src/db/checkout-refresh.ts +5 -5
  160. package/src/db/command-agent-profile-backfill.ts +39 -0
  161. package/src/db/command-agent-profiles.ts +5 -1
  162. package/src/db/command-retention.ts +126 -0
  163. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  164. package/src/db/commands-read-ops.ts +16 -0
  165. package/src/db/connection.ts +1 -182
  166. package/src/db/context-carry-write.ts +74 -0
  167. package/src/db/continuations.ts +4 -4
  168. package/src/db/db-error-registry.ts +12 -0
  169. package/src/db/gateway.ts +26 -133
  170. package/src/db/history-retention-ops.ts +13 -0
  171. package/src/db/inbox-async.ts +2 -2
  172. package/src/db/inbox-read-ops.ts +1 -1
  173. package/src/db/inbox.ts +9 -3
  174. package/src/db/issue-associations.ts +2 -2
  175. package/src/db/issue-refs-async.ts +4 -1
  176. package/src/db/issue-refs-read-ops.ts +6 -0
  177. package/src/db/issue-refs.ts +8 -8
  178. package/src/db/kernel-event-log-schema.ts +2 -0
  179. package/src/db/land-boundaries.ts +51 -5
  180. package/src/db/land-gate-attestations.ts +2 -2
  181. package/src/db/landing-receipts.ts +2 -2
  182. package/src/db/lifecycle-context-write.ts +5 -0
  183. package/src/db/lifecycle-tail-async.ts +76 -0
  184. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  185. package/src/db/lifecycle-write-window.ts +2 -1
  186. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  187. package/src/db/main-connection-mode.ts +11 -0
  188. package/src/db/main-connection-writes.ts +20 -2
  189. package/src/db/maintenance-job-runs-async.ts +2 -2
  190. package/src/db/maintenance-job-write-ops.ts +1 -1
  191. package/src/db/maintenance-pauses.ts +2 -2
  192. package/src/db/message-send.ts +4 -0
  193. package/src/db/messages.ts +31 -25
  194. package/src/db/migrations.ts +18 -1
  195. package/src/db/notification-write-ops.ts +19 -0
  196. package/src/db/operator-answer-write.ts +19 -0
  197. package/src/db/orchestrators.ts +10 -4
  198. package/src/db/pairs-async.ts +22 -1
  199. package/src/db/pairs-write-ops.ts +8 -3
  200. package/src/db/pairs.ts +41 -48
  201. package/src/db/plan-dispatch-schema.ts +5 -1
  202. package/src/db/plan-ready-notices.ts +43 -0
  203. package/src/db/plan-tools-include-migration.ts +36 -0
  204. package/src/db/plans-write-ops.ts +2 -0
  205. package/src/db/presence-buffer.ts +5 -0
  206. package/src/db/presence-loop.ts +18 -23
  207. package/src/db/presence-write.ts +0 -6
  208. package/src/db/project-entries-async.ts +14 -0
  209. package/src/db/project-entries-read-ops.ts +5 -1
  210. package/src/db/project-entries-write-ops.ts +8 -0
  211. package/src/db/project-entries.ts +15 -12
  212. package/src/db/project-journal.ts +2 -2
  213. package/src/db/project-trust-approvals.ts +2 -2
  214. package/src/db/prompt-templates.ts +4 -4
  215. package/src/db/read-op-marshaling-fixtures.ts +18 -0
  216. package/src/db/read-ops.ts +4 -0
  217. package/src/db/retention.ts +13 -2
  218. package/src/db/review-publish-write.ts +8 -0
  219. package/src/db/runtime-admin-async.ts +19 -0
  220. package/src/db/runtime-admin-write-ops.ts +36 -0
  221. package/src/db/runtime-tail-async.ts +288 -0
  222. package/src/db/runtime-tail-write-ops.ts +97 -0
  223. package/src/db/schema.ts +4 -1
  224. package/src/db/spawn-budget.ts +5 -0
  225. package/src/db/spawn-delegation.ts +1 -11
  226. package/src/db/sql-audit-indexes.ts +3 -0
  227. package/src/db/stats-async.ts +5 -3
  228. package/src/db/task-entity.ts +5 -4
  229. package/src/db/team-claim-policy.ts +60 -0
  230. package/src/db/teams-async.ts +4 -0
  231. package/src/db/teams-write-ops.ts +4 -0
  232. package/src/db/terminal-events.ts +15 -0
  233. package/src/db/timer-cutover-bodies.ts +292 -0
  234. package/src/db/timer-cutover-core.ts +37 -278
  235. package/src/db/timer-cutover-state.ts +40 -0
  236. package/src/db/timer-cutover-write-ops.ts +1 -40
  237. package/src/db/token-db-write-ops.ts +2 -0
  238. package/src/db/token-standing-async.ts +12 -0
  239. package/src/db/token-standing.ts +6 -9
  240. package/src/db/token-usage-retention.ts +33 -0
  241. package/src/db/token-usage-write-ops.ts +1 -1
  242. package/src/db/token-usage.ts +4 -1
  243. package/src/db/user-invites-async.ts +13 -0
  244. package/src/db/user-invites.ts +3 -3
  245. package/src/db/users.ts +14 -6
  246. package/src/db/workspaces.ts +8 -5
  247. package/src/db/write-ops.ts +31 -12
  248. package/src/db/writer-fault-seam.ts +2 -9
  249. package/src/db/writer-fault-test-ops.ts +18 -0
  250. package/src/db/writer-gateway.ts +42 -46
  251. package/src/dev.ts +8 -3
  252. package/src/event-loop-lag.ts +4 -2
  253. package/src/event-loop-yield.ts +2 -2
  254. package/src/events.ts +10 -8
  255. package/src/host-provider-store.ts +5 -4
  256. package/src/hub-metrics-report.ts +5 -1
  257. package/src/hub-metrics.ts +38 -18
  258. package/src/injection-sweep-pacing.ts +6 -8
  259. package/src/land-gate-notifications.ts +11 -10
  260. package/src/land-gate-queue-progress.ts +3 -3
  261. package/src/land-settle-dispatch.ts +52 -92
  262. package/src/lifecycle-context-pressure.ts +11 -10
  263. package/src/lifecycle-manager.ts +104 -98
  264. package/src/maintenance/breaker.ts +18 -16
  265. package/src/maintenance/checkout-refresh.ts +18 -1
  266. package/src/maintenance/critical-job-watchdog.ts +3 -3
  267. package/src/maintenance/events.ts +3 -3
  268. package/src/maintenance/history-retention-job.ts +30 -0
  269. package/src/maintenance/jobs.ts +29 -67
  270. package/src/maintenance/long-running-work.ts +3 -1
  271. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  272. package/src/maintenance/orphaned-sessions.ts +5 -4
  273. package/src/maintenance/pauses.ts +4 -10
  274. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  275. package/src/maintenance/scheduler.ts +18 -13
  276. package/src/maintenance/stalled-delivery-pager.ts +4 -4
  277. package/src/maintenance/teams.ts +19 -30
  278. package/src/maintenance/workspaces.ts +17 -27
  279. package/src/managed-policy-escalation.ts +7 -7
  280. package/src/managed-policy.ts +3 -3
  281. package/src/managed-provider-gate.ts +5 -4
  282. package/src/managed-spawn-reservation.ts +5 -4
  283. package/src/mcp/index.ts +8 -8
  284. package/src/mcp/output-descriptions.ts +1 -1
  285. package/src/mcp/presentation.ts +2 -1
  286. package/src/mcp/runtime-output.ts +6 -1
  287. package/src/mcp/self-care-visibility.ts +2 -2
  288. package/src/mcp/spawn-targets-matrix.ts +10 -1
  289. package/src/mcp/tool-groups.ts +3 -2
  290. package/src/mcp/tool-roles.ts +81 -0
  291. package/src/mcp/tools-workspace.ts +1 -1
  292. package/src/mcp-blackboard-tools.ts +6 -5
  293. package/src/mcp-decision-tools.ts +7 -7
  294. package/src/mcp-egress-tools.ts +10 -9
  295. package/src/mcp-issue-activity-tools.ts +2 -2
  296. package/src/mcp-issue-association-tools.ts +4 -4
  297. package/src/mcp-issue-ref-tools.ts +3 -3
  298. package/src/mcp-merge-tools.ts +5 -5
  299. package/src/mcp-notification-subscription-tools.ts +14 -15
  300. package/src/mcp-output-levels.test-fixture.ts +1 -1
  301. package/src/mcp-profile-trust-tools.ts +1 -1
  302. package/src/mcp-project-journal-tools.ts +4 -12
  303. package/src/mcp-project-tools.ts +17 -18
  304. package/src/mcp-routing-policy-tools.ts +3 -2
  305. package/src/mcp-team-tools.ts +6 -6
  306. package/src/mcp-workflow-tools.ts +5 -3
  307. package/src/memory-area-injection.ts +13 -12
  308. package/src/memory-boundary-capture.ts +6 -6
  309. package/src/memory-injection.ts +45 -43
  310. package/src/merge-pause-maintenance.ts +5 -4
  311. package/src/notification-router.ts +44 -17
  312. package/src/notify.ts +5 -5
  313. package/src/observed-reset-refresh.ts +4 -4
  314. package/src/operator-alarm.ts +2 -5
  315. package/src/project-ingest.ts +6 -6
  316. package/src/project-instructions.ts +8 -1
  317. package/src/project-trust.ts +12 -11
  318. package/src/prompt-resolver.ts +3 -3
  319. package/src/provider-quota-async.ts +5 -7
  320. package/src/provider-timeline-event.ts +4 -7
  321. package/src/quota-band-delivery.ts +2 -2
  322. package/src/recipe-runner.ts +4 -3
  323. package/src/retention-config-store.ts +4 -3
  324. package/src/reviewer-pipeline.ts +11 -10
  325. package/src/routes/_route.ts +4 -4
  326. package/src/routes/_shared.ts +13 -12
  327. package/src/routes/agent-effort.ts +5 -5
  328. package/src/routes/agent-heartbeat-quota.ts +23 -0
  329. package/src/routes/agent-keep.ts +1 -1
  330. package/src/routes/agent-reporting.ts +1 -1
  331. package/src/routes/agent-self-effort.ts +5 -5
  332. package/src/routes/agent-sessions.ts +24 -24
  333. package/src/routes/agents-spawn.ts +1 -1
  334. package/src/routes/agents.ts +17 -119
  335. package/src/routes/auth.ts +14 -15
  336. package/src/routes/authority-audit.ts +2 -2
  337. package/src/routes/automations.ts +6 -5
  338. package/src/routes/channel-binding-delete.ts +1 -1
  339. package/src/routes/channel-output.ts +3 -3
  340. package/src/routes/claude-api-budget.ts +5 -5
  341. package/src/routes/commands-listing.ts +1 -1
  342. package/src/routes/commands.ts +29 -27
  343. package/src/routes/context-resets.ts +2 -2
  344. package/src/routes/coordinator-teams.ts +1 -1
  345. package/src/routes/decisions.ts +2 -2
  346. package/src/routes/host-secret-files.ts +1 -1
  347. package/src/routes/hosts.ts +11 -11
  348. package/src/routes/inbox.ts +3 -2
  349. package/src/routes/index.ts +2 -1
  350. package/src/routes/integrations.ts +9 -7
  351. package/src/routes/issue-activity.ts +2 -2
  352. package/src/routes/issue-associations.ts +4 -4
  353. package/src/routes/issue-refs.ts +3 -3
  354. package/src/routes/kernel-timers-operator.ts +1 -1
  355. package/src/routes/memory.ts +1 -1
  356. package/src/routes/merges.ts +11 -11
  357. package/src/routes/messages.ts +23 -17
  358. package/src/routes/orchestrator-bootstrap.ts +1 -1
  359. package/src/routes/orchestrator-host-registration.ts +2 -0
  360. package/src/routes/orchestrator-host-utilization.ts +2 -2
  361. package/src/routes/orchestrator-proxy.ts +2 -2
  362. package/src/routes/orchestrator.ts +27 -18
  363. package/src/routes/pairs.ts +8 -8
  364. package/src/routes/project-profile-instructions.ts +1 -1
  365. package/src/routes/project-trust.ts +1 -1
  366. package/src/routes/projects.ts +16 -16
  367. package/src/routes/prompt-templates.ts +12 -12
  368. package/src/routes/provider-quotas.ts +10 -10
  369. package/src/routes/run-command.ts +1 -1
  370. package/src/routes/secrets-backup.ts +2 -2
  371. package/src/routes/secrets-import.ts +1 -1
  372. package/src/routes/secrets-vault.ts +7 -7
  373. package/src/routes/settings.ts +1 -1
  374. package/src/routes/shipping.ts +9 -1
  375. package/src/routes/spawn-policy.ts +8 -7
  376. package/src/routes/sse.ts +2 -2
  377. package/src/routes/team-templates.ts +7 -7
  378. package/src/routes/teams.ts +10 -10
  379. package/src/routes/tokens.ts +18 -17
  380. package/src/routes/users.ts +24 -24
  381. package/src/routes/viewer-read.ts +3 -3
  382. package/src/routes/web-tool-calls.ts +4 -4
  383. package/src/routes/workflows.ts +2 -2
  384. package/src/routes/workspaces.ts +17 -16
  385. package/src/routing-policy-push.ts +6 -6
  386. package/src/runtime-grant.ts +17 -11
  387. package/src/runtime-tokens.ts +20 -28
  388. package/src/secrets-broker/config.ts +1 -1
  389. package/src/secrets-broker/service.ts +2 -2
  390. package/src/security.ts +3 -1
  391. package/src/self-resume-carry.ts +21 -110
  392. package/src/self-resume-supersede.ts +4 -3
  393. package/src/self-resume.ts +54 -66
  394. package/src/server-background.ts +1 -1
  395. package/src/server.ts +21 -22
  396. package/src/services/agent-action.ts +12 -31
  397. package/src/services/agent-effort.ts +7 -32
  398. package/src/services/agent-hang-watchdog-job.ts +2 -2
  399. package/src/services/agent-heartbeat.ts +166 -0
  400. package/src/services/agent-reporting.ts +1 -1
  401. package/src/services/browser-inventory.ts +3 -3
  402. package/src/services/browser-session-state.ts +3 -2
  403. package/src/services/browser-session.ts +21 -27
  404. package/src/services/bus-command-update.ts +9 -9
  405. package/src/services/checkout-refresh-state.ts +1 -0
  406. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  407. package/src/services/command-host.ts +7 -2
  408. package/src/services/coordinator-digest.ts +3 -2
  409. package/src/services/dispatch-command.ts +12 -13
  410. package/src/services/effective-launch-driver.ts +14 -9
  411. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  412. package/src/services/host-project-readiness.ts +2 -2
  413. package/src/services/host-providers.ts +1 -1
  414. package/src/services/host-utilization.ts +9 -9
  415. package/src/services/idle-agent-digest.ts +17 -12
  416. package/src/services/idle-epics.ts +4 -4
  417. package/src/services/interrupt-agent.ts +12 -9
  418. package/src/services/issue-activity.ts +3 -3
  419. package/src/services/issue-associations.ts +15 -18
  420. package/src/services/issue-lifecycle-comments.ts +3 -2
  421. package/src/services/issue-lifecycle.ts +14 -13
  422. package/src/services/issue-refs.ts +4 -5
  423. package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
  424. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  425. package/src/services/kernel-timers-ingress.ts +3 -3
  426. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  427. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  428. package/src/services/kernel-timers-outbox.ts +1 -1
  429. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  430. package/src/services/kernel-timers.ts +4 -3
  431. package/src/services/land-gate-placement.ts +11 -2
  432. package/src/services/land-issue-relations.ts +5 -4
  433. package/src/services/land-restart-retry.ts +7 -6
  434. package/src/services/landed-ancestry.ts +6 -5
  435. package/src/services/legacy-landing-host.ts +4 -1
  436. package/src/services/legacy-landing-recovery.ts +8 -6
  437. package/src/services/managed-running.ts +17 -17
  438. package/src/services/memory-areas.ts +3 -3
  439. package/src/services/merge-pause.ts +9 -15
  440. package/src/services/operator-decisions.ts +37 -41
  441. package/src/services/orchestrator-registration-recovery.ts +6 -2
  442. package/src/services/orchestrator-upgrade.ts +14 -12
  443. package/src/services/permission-decision.ts +4 -3
  444. package/src/services/plan-ci-notice.ts +1 -1
  445. package/src/services/plan-conformance.ts +4 -4
  446. package/src/services/plan-dispatch-policy.ts +10 -3
  447. package/src/services/plan-dispatch.ts +35 -14
  448. package/src/services/plan-graph.ts +39 -261
  449. package/src/services/plan-import.ts +1 -1
  450. package/src/services/plan-live-bindings.ts +8 -37
  451. package/src/services/plan-task-create.ts +1 -1
  452. package/src/services/plan-terminal-refs.ts +2 -12
  453. package/src/services/plan-wake-digest.ts +8 -3
  454. package/src/services/profile-trust.ts +2 -2
  455. package/src/services/project.ts +11 -10
  456. package/src/services/prompt-templates.ts +6 -5
  457. package/src/services/provider-hold-nudge.ts +9 -9
  458. package/src/services/provider-hold-record.ts +13 -12
  459. package/src/services/provider-state-audit.ts +19 -18
  460. package/src/services/provisioning-harness/driver.ts +1 -1
  461. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  462. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  463. package/src/services/provisioning-harness/prepare.ts +16 -17
  464. package/src/services/rate-limit-resume.ts +10 -9
  465. package/src/services/red-main-auto-revert.ts +7 -5
  466. package/src/services/red-main-controller-deps.ts +20 -3
  467. package/src/services/red-main-incident.ts +3 -1
  468. package/src/services/red-main-quarantine.ts +2 -3
  469. package/src/services/register-agent.ts +22 -22
  470. package/src/services/restart-project-role.ts +1 -1
  471. package/src/services/restart-spawn.ts +17 -16
  472. package/src/services/review-publish.ts +7 -24
  473. package/src/services/review-ref-reconcile.ts +29 -38
  474. package/src/services/runtime-dependency-alert.ts +27 -0
  475. package/src/services/scheduler-command.ts +11 -9
  476. package/src/services/scheduler.ts +5 -5
  477. package/src/services/self-effort-grant.ts +5 -25
  478. package/src/services/send-message.ts +16 -33
  479. package/src/services/shutdown-agent.ts +17 -14
  480. package/src/services/spawn-agent.ts +12 -41
  481. package/src/services/spawn-chain-inspector.ts +1 -1
  482. package/src/services/spawn-cwd-placement.ts +21 -5
  483. package/src/services/spawn-issue-activity.ts +8 -6
  484. package/src/services/spawn-launch.ts +17 -1
  485. package/src/services/spawn-loss-escalation.ts +1 -1
  486. package/src/services/spawn-registration-watchdog.ts +2 -2
  487. package/src/services/spawn-repo-probe.ts +7 -5
  488. package/src/services/spawn-tree-cleanup.ts +7 -8
  489. package/src/services/steward-reaper.ts +4 -4
  490. package/src/services/task-context-hydration.ts +25 -1
  491. package/src/services/task-delivery.ts +20 -34
  492. package/src/services/task-entity.ts +40 -203
  493. package/src/services/task-issue-link.ts +13 -20
  494. package/src/services/task-issue-weave.ts +12 -11
  495. package/src/services/task-lifecycle.ts +27 -31
  496. package/src/services/task-repo-cwd.ts +37 -0
  497. package/src/services/task-review-hold.ts +4 -17
  498. package/src/services/task-semantic-events.ts +13 -11
  499. package/src/services/task-state-reconcile.ts +3 -4
  500. package/src/services/task-validation.ts +2 -2
  501. package/src/services/team-templates.ts +5 -5
  502. package/src/services/team.ts +31 -98
  503. package/src/services/terminal-provider-exit.ts +6 -5
  504. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  505. package/src/services/timer-message-fire-outbox.ts +1 -1
  506. package/src/services/transient-agent-reaper.ts +22 -19
  507. package/src/services/turn-reconcile-audit.ts +9 -9
  508. package/src/services/user-onboarding.ts +8 -6
  509. package/src/services/user-profile.ts +6 -9
  510. package/src/services/work-finality.ts +16 -4
  511. package/src/services/workflow-auto-start.ts +2 -1
  512. package/src/services/workflow-caller.ts +61 -4
  513. package/src/services/workflow-child-proof-worker.ts +1 -1
  514. package/src/services/workflow-control-proof-worker.ts +1 -1
  515. package/src/services/workflow-coordinator.ts +8 -2
  516. package/src/services/workflow-decisions.ts +5 -5
  517. package/src/services/workflow-deferred-cleanup.ts +1 -1
  518. package/src/services/workflow-effect-driver.ts +42 -19
  519. package/src/services/workflow-effects.ts +41 -27
  520. package/src/services/workflow-pins.ts +7 -4
  521. package/src/services/workflow-reconcile.ts +1 -0
  522. package/src/services/workflow-resume-pins.ts +3 -3
  523. package/src/services/workflow-routing-defaults.ts +18 -0
  524. package/src/services/workflow-run-view.ts +4 -3
  525. package/src/services/workflow-run.test-fixture.ts +1 -1
  526. package/src/services/workflow-runs.ts +34 -22
  527. package/src/services/workflow-supervisor-state.ts +21 -1
  528. package/src/services/workflow-supervisor.ts +4 -3
  529. package/src/services/workspace-recovery.ts +4 -3
  530. package/src/spawn-admission.ts +10 -2
  531. package/src/spawn-placement.ts +27 -9
  532. package/src/spawn-targets.ts +8 -8
  533. package/src/sse-agent-status.ts +15 -6
  534. package/src/sse.ts +49 -24
  535. package/src/startup-context-injection.ts +61 -57
  536. package/src/steward-handoff.ts +4 -3
  537. package/src/steward-policy-cleanup.ts +9 -8
  538. package/src/steward.ts +2 -2
  539. package/src/task-dispatch-live.ts +5 -2
  540. package/src/task-dispatcher.ts +2 -2
  541. package/src/token-db.ts +2 -2
  542. package/src/token-usage-async.ts +2 -4
  543. package/src/user-awaiting-reply.ts +5 -5
  544. package/src/workspace-actions.ts +24 -29
  545. package/src/workspace-auto-merge.ts +14 -12
  546. package/src/workspace-changed-paths-client.ts +16 -5
  547. package/src/workspace-cleanup-stale.ts +30 -7
  548. package/src/workspace-command-settle.ts +24 -16
  549. package/src/workspace-config.ts +1 -1
  550. package/src/workspace-conflict-resolver.ts +9 -7
  551. package/src/workspace-dead-owner-recovery.ts +5 -4
  552. package/src/workspace-escalation.ts +12 -11
  553. package/src/workspace-human-escalation.ts +3 -3
  554. package/src/workspace-land-gate-watchdog.ts +3 -3
  555. package/src/workspace-land-refusal.ts +20 -0
  556. package/src/workspace-land-stopped.ts +1 -0
  557. package/src/workspace-merge.ts +10 -26
  558. package/src/workspace-nothing-to-land-notice.ts +2 -2
  559. package/src/workspace-orphans.ts +18 -37
  560. package/src/workspace-pr-completion.ts +10 -8
  561. package/src/workspace-rekey.ts +3 -3
  562. package/src/workspace-steward-failure.ts +2 -2
  563. package/src/workspace-steward-wake.ts +2 -2
  564. package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
  565. package/public/assets/provider-display-DsuWMvVL.js +0 -2
  566. package/public/assets/run-card-CpKqRbhg.js +0 -2
  567. package/public/assets/shipping-B9YtnwtG.js +0 -2
  568. package/public/assets/store-DcClXLH0.js +0 -9
  569. package/runner/src/agent-runner/http-liveness.ts +0 -85
  570. package/src/db/on-loop-write-transaction.ts +0 -34
@@ -3,9 +3,9 @@ import { claudeSubagentEnv, claudeSubagentPolicy, configureClaudeSubagentLaunch,
3
3
  import { submitClaudeContextCommand } from "./claude-context-command";
4
4
  import { scopeClaudeCredentialEnv } from "./claude-credentials";
5
5
  import { claudeEffortLaunch, claudeEffortSwitchMeta, switchClaudeEffort } from "./claude-effort";
6
- import { existsSync } from "node:fs";
7
- import { homedir } from "node:os";
8
- import { join, resolve } from "node:path";
6
+ import { claudeLaunchExitStatus } from "./claude-launch-exit";
7
+ import { claudeCallerAppends } from "../claude-system-prompt";
8
+ import { resolveLaunchCommand } from "../provider-command";
9
9
  import { fireAndForget, sanitizeLaunchBoundary, sanitizeLaunchText, type LivenessSignal, type Message } from "@humwick/sdk";
10
10
  import { shellEscape as shellQuote } from "@humwick/sdk/shell-utils";
11
11
  import { tmuxCommand, tmuxHasSession } from "@humwick/sdk/tmux-utils";
@@ -25,13 +25,13 @@ import { claudeActivityFromProbeAndPane, claudeBypassDialogDisplayGate, claudeBy
25
25
  import { ClaudeSessionCapture, collectClaudeTranscriptArchiveSegment, collectClaudeTranscriptSessionEvents } from "./claude-session-capture";
26
26
  import { claudeToolHookPaths, extractLatestContextUsage } from "./claude-transcript";
27
27
  import { ClaudeTranscriptTokenUsageCapture } from "./claude-token-usage-capture";
28
- import { CLAUDE_CLEAR_COMMIT_CAPTURE, CLAUDE_TMUX_READY_TIMEOUT_MS, claudeOneShotExitStatus, confirmClaudeSubmitRecovery, confirmTmuxSessionGone, createLauncherGate, createTmuxSessionWithEnv, releaseClaudeSubmitFence, releaseLauncherGate, seedClaudeInitialPrompt, submitTextToTmux, tmuxEnvKeys, tmuxSessionName, tmuxSessionTargetName, tmuxSocketName, waitForClaudeClearCommitted, waitForClaudeInputReady, writeLauncherScript } from "./claude-tmux";
28
+ import { CLAUDE_CLEAR_COMMIT_CAPTURE, CLAUDE_TMUX_READY_TIMEOUT_MS, buildClaudeTmuxArgs, confirmClaudeSubmitRecovery, confirmTmuxSessionGone, createLauncherGate, createTmuxSessionWithEnv, releaseClaudeSubmitFence, releaseLauncherGate, seedClaudeInitialPrompt, submitTextToTmux, waitForClaudeClearCommitted, waitForClaudeInputReady } from "./claude-tmux";
29
29
  import { captureTmuxPaneAsync, captureTmuxVisiblePaneAsync, resolveClaudePanePidAsync, tmuxSessionPresence } from "./tmux-offload";
30
30
  import { claudeShutdownGraceMs, shutdownClaudeTmux, type ClaudeShutdownDeps } from "./claude-shutdown";
31
31
  import { claudePermissionPromptHandler } from "./claude-permission";
32
32
  import { claudeHarnessTrim, claudeProfileDisallowedToolsArgs } from "./claude-tool-policy";
33
33
  import { claudeProjectShellEnv } from "./project-shell";
34
- import { launcherGatePathForSession, stageOneShotPrompt } from "../session-scratch";
34
+ import { stageOneShotPrompt } from "../session-scratch";
35
35
 
36
36
  type MonitorlessTurnWatchDeps = {
37
37
  resolvePanePid: typeof resolveClaudePanePidAsync;
@@ -635,32 +635,22 @@ export class ClaudeAdapter implements ProviderAdapter {
635
635
  // #557 — ONE assembler owns the provisioning/vanilla/instruction launch surface
636
636
  // (--setting-sources, --plugin-dir, --mcp-config, status-line, --append-system-prompt);
637
637
  // profile-projection describes the SAME assembled result, so report == launch. The
638
- // adapter only adds the bits the assembler does not own: claude-rig command resolution,
638
+ // adapter only adds the bits the assembler does not own: launch command resolution,
639
639
  // headless permission flags, --model, and the positional prompt. materializeLaunchAssembly
640
640
  // writes the provisioned skills/plugins the assembled args point at.
641
641
  const assembled = assembleLaunch(this.provider, config, providerConfig);
642
- materializeLaunchAssembly(this.provider, config);
642
+ materializeLaunchAssembly(this.provider, config, assembled);
643
643
  const defaultArgs = assembled.hostDefaultArgs;
644
- const isClaudeRig = /claude-rig/.test(providerConfig.command);
645
- // Profiled launches run their own CLAUDE_CONFIG_DIR (#3387) and must never route through
646
- // claude-rig — claude-rig resolves host rig config and would redirect the assembled home.
647
- // Only a profile-less (user-wrapped) session may use claude-rig.
648
- const usesClaudeRig = isClaudeRig && !assembled.configHome;
649
- const bypassRigDefaults = config.headless && usesClaudeRig && config.approvalMode !== "open";
650
- const rigPrefix = usesClaudeRig && !bypassRigDefaults && config.rig ? ["launch", config.rig] : [];
651
- const command = !usesClaudeRig || bypassRigDefaults || (!config.rig && !findClaudeRigRC(config.cwd))
652
- ? "claude"
653
- : providerConfig.command;
654
- const providerArgs = config.headless
644
+ const command = resolveLaunchCommand(providerConfig.command);
645
+ const providerArgs = claudeCallerAppends(config.headless
655
646
  ? claudeLaunchArgs(defaultArgs, config.providerArgs, config.approvalMode)
656
- : [...defaultArgs, ...config.providerArgs];
647
+ : [...defaultArgs, ...config.providerArgs]).args;
657
648
  // #1096 — when the assembler merged the caller's own `--settings` into relay's (so the
658
649
  // baseline hooks/projectSettings/statusLine survive), drop the caller's now-redundant
659
650
  // `--settings` here so exactly ONE reaches the launch (relay's merged copy in assembled.args).
660
651
  // #2453 — the coding/review profiles' --disallowedTools trim unions in at this single
661
652
  // claude-family launch seam (helpers + per-profile config in ./claude-tool-policy).
662
653
  const args = claudeProfileDisallowedToolsArgs([
663
- ...rigPrefix,
664
654
  ...assembled.args,
665
655
  ...(assembled.callerSettingsConsumed ? stripSettingsArgs(providerArgs) : providerArgs),
666
656
  ], config);
@@ -673,12 +663,10 @@ export class ClaudeAdapter implements ProviderAdapter {
673
663
  ...config.env,
674
664
  // #557 — the assembler owns the isolated config-home env (CLAUDE_CONFIG_DIR).
675
665
  ...assembled.env,
676
- // Plain `claude` (isolated profiles) runs its own CLAUDE_CONFIG_DIR and never
677
- // routes through claude-rig, so it never inherits the host's long-lived
678
- // CLAUDE_CODE_OAUTH_TOKEN. Without it, claude falls back to the (often stale)
679
- // file-based .credentials.json and bails to /login (401). claude-rig launches
680
- // inject their own token, so only thread it for the plain-claude path, and
681
- // never override an explicit per-launch value.
666
+ // Bare `claude` runs its own CLAUDE_CONFIG_DIR and so never inherits the host's long-lived
667
+ // CLAUDE_CODE_OAUTH_TOKEN; without it claude falls back to the (often stale) file-based
668
+ // .credentials.json and bails to /login (401). A custom wrapper command manages its own
669
+ // token, and an explicit per-launch value always wins.
682
670
  ...(command === "claude" && process.env.CLAUDE_CODE_OAUTH_TOKEN && !config.env?.CLAUDE_CODE_OAUTH_TOKEN
683
671
  ? { CLAUDE_CODE_OAUTH_TOKEN: process.env.CLAUDE_CODE_OAUTH_TOKEN }
684
672
  : {}),
@@ -758,36 +746,13 @@ export class ClaudeAdapter implements ProviderAdapter {
758
746
  });
759
747
  }
760
748
 
761
- buildTmuxArgs(config: RunnerSpawnConfig, spawnArgs: SpawnArgs): { sessionName: string; socketName: string; args: string[]; launcherScript: string; gateFifo?: string } {
762
- const requestedSessionName = config.tmuxSession || tmuxSessionName(config.providerConfig.headless.tmuxPrefix, config.instanceId, config.label);
763
- // Keep the socket derived from the orchestrator's stable identity, but carry
764
- // tmux's rendered session name everywhere we later target the pane. Without
765
- // this, `opus-4.8` is created as `opus-4_8` and every watcher/restart lookup
766
- // immediately misses it.
767
- const socketName = tmuxSocketName(requestedSessionName); const sessionName = tmuxSessionTargetName(requestedSessionName);
768
- const shellCmd = [spawnArgs.command, ...spawnArgs.args].map(shellQuote).join(" ");
769
- const tmuxArgs = ["new-session", "-d", "-s", sessionName, "-x", "200", "-y", "50"];
770
-
771
- const envKeys = tmuxEnvKeys(spawnArgs.env, config.providerConfig.env, this.provider);
772
- const env: Record<string, string> = {};
773
- for (const key of envKeys) if (relayEnv(spawnArgs.env, key) !== undefined) writeChildEnv(env, { [key]: relayEnv(spawnArgs.env, key)! });
774
-
775
- // Only gate the launch behind pipe-pane attachment when there's a log file to
776
- // protect (#1317) — no point serializing dev/interactive spawns that never
777
- // read AGENT_RELAY_LOG_FILE.
778
- const gateFifo = relayEnv(spawnArgs.env, "AGENT_RELAY_LOG_FILE") ? launcherGatePathForSession(sessionName) : undefined;
779
-
780
- // tmux new-session has a hard command-length limit that includes every argv item,
781
- // including `-e KEY=value`. The script holds the command; its private FIFO
782
- // carries env values without writing credentials to disk or argv.
783
- const launcherScript = writeLauncherScript(sessionName, env, shellCmd, gateFifo, spawnArgs.stdinFile, spawnArgs.exitCodeFile, spawnArgs.envUnset);
784
- tmuxArgs.push("-c", spawnArgs.cwd, `bash ${shellQuote(launcherScript)}`);
785
- return { sessionName, socketName, args: tmuxArgs, launcherScript, gateFifo };
749
+ buildTmuxArgs(config: RunnerSpawnConfig, spawnArgs: SpawnArgs): ReturnType<typeof buildClaudeTmuxArgs> {
750
+ return buildClaudeTmuxArgs(config, spawnArgs, this.provider);
786
751
  }
787
752
 
788
753
  private async spawnHeadless(config: RunnerSpawnConfig, spawnArgs: SpawnArgs): Promise<ManagedProcess> {
789
754
  if (spawnArgs.stdinFile && spawnArgs.exitCodeFile && spawnArgs.stdinContents !== undefined) await stageOneShotPrompt(spawnArgs.stdinFile, spawnArgs.exitCodeFile, spawnArgs.stdinContents);
790
- const { sessionName, socketName, args: tmuxArgs, launcherScript, gateFifo } = this.buildTmuxArgs(config, spawnArgs);
755
+ const { sessionName, socketName, args: tmuxArgs, launcherScript, gateFifo, printMode } = this.buildTmuxArgs(config, spawnArgs);
791
756
  const providerEpoch = ++this.providerEpoch;
792
757
  this.modelUnavailableObservationState = initialClaudeModelUnavailableObservationState();
793
758
  this.connectionRetryActive = false;
@@ -802,7 +767,8 @@ export class ClaudeAdapter implements ProviderAdapter {
802
767
 
803
768
  await createTmuxSessionWithEnv(sessionName, socketName, tmuxArgs, launcherScript, spawnArgs.env, config.providerConfig.env, gateFifo, this.provider);
804
769
 
805
- this.watchTmuxSession(sessionName, socketName, spawnArgs.exitCodeFile);
770
+ const exitCodeFile = spawnArgs.exitCodeFile ?? `${launcherScript}.exit-code`;
771
+ this.watchTmuxSession(sessionName, socketName, exitCodeFile, printMode);
806
772
  // #1838 review MED — resolve the pane pid OFF the loop now that the session exists and cache
807
773
  // it, so the synchronous resolveBusyPid() never has to shell out on a hot busy edge. Fenced
808
774
  // on providerEpoch so a resolve that lands after a restart can't stamp a stale pid.
@@ -832,14 +798,15 @@ export class ClaudeAdapter implements ProviderAdapter {
832
798
  tmuxSession: sessionName,
833
799
  tmuxSocket: socketName,
834
800
  launcherScript,
835
- ...claudeEffortSwitchMeta(this.provider, config, Boolean(spawnArgs.exitCodeFile)),
836
- ...(spawnArgs.exitCodeFile ? { oneShotExitCodeFile: spawnArgs.exitCodeFile } : {}),
801
+ exitCodeFile,
802
+ ...claudeEffortSwitchMeta(this.provider, config, printMode),
803
+ printMode,
837
804
  providerEpoch,
838
805
  },
839
806
  };
840
807
  }
841
808
 
842
- private watchTmuxSession(sessionName: string, socketName?: string, oneShotExitCodeFile?: string): void {
809
+ private watchTmuxSession(sessionName: string, socketName?: string, exitCodeFile?: string, oneShot = false): void {
843
810
  if (this.tmuxWatcher) clearInterval(this.tmuxWatcher);
844
811
  // #1838 row 12 — the highest-frequency blocking site in the runner (every 2s for the
845
812
  // agent's whole lifetime). Its two tmux subprocesses (has-session + capture-pane) now run
@@ -849,6 +816,7 @@ export class ClaudeAdapter implements ProviderAdapter {
849
816
  // probe on the same pane. `this.tmuxWatcher !== watcher` still fences a predecessor tick
850
817
  // whose session was replaced by a respawn.
851
818
  let tickInFlight = false;
819
+ let lastPane = "";
852
820
  const watcher = setInterval(() => {
853
821
  if (this.tmuxWatcher !== watcher || tickInFlight) return;
854
822
  tickInFlight = true;
@@ -866,7 +834,7 @@ export class ClaudeAdapter implements ProviderAdapter {
866
834
  // confirm itself only returns true when BOTH reads are `absent` (#1838 HIGH-2).
867
835
  const gone = await confirmTmuxSessionGone(sessionName, socketName).catch(() => false);
868
836
  if (this.tmuxWatcher !== watcher || !gone) return;
869
- const exitStatus = await claudeOneShotExitStatus(oneShotExitCodeFile);
837
+ const exitStatus = await claudeLaunchExitStatus(exitCodeFile, this.startupReadyObserved, oneShot, lastPane);
870
838
  if (this.tmuxWatcher !== watcher) return;
871
839
  clearInterval(watcher); this.tmuxWatcher = undefined; this.publishConfirmedTmuxExit(exitStatus);
872
840
  return;
@@ -879,6 +847,7 @@ export class ClaudeAdapter implements ProviderAdapter {
879
847
  }
880
848
  // #1838 HIGH-1: fence again after the capture await, before any observation/status emit.
881
849
  if (this.tmuxWatcher !== watcher) return;
850
+ lastPane = pane;
882
851
  // A reused tmux pane can leave an old ready footer in scrollback. Until the
883
852
  // current launch is visibly ready, derive both readiness and modal state
884
853
  // from the visible grid. After that, avoid an extra capture every tick.
@@ -938,7 +907,7 @@ export class ClaudeAdapter implements ProviderAdapter {
938
907
  this.tmuxWatcher = watcher;
939
908
  }
940
909
 
941
- private publishConfirmedTmuxExit(status: "offline" | "error"): void {
910
+ private publishConfirmedTmuxExit(status: ProviderStatusUpdate): void {
942
911
  // The pane and turn pollers are independent. Invalidate the turn generation BEFORE publishing
943
912
  // the terminal edge so an in-flight incarnation/activity read cannot land a later idle and
944
913
  // resurrect the row with its shutting-down lifecycle pill still latched (#2505).
@@ -962,7 +931,7 @@ export class ClaudeAdapter implements ProviderAdapter {
962
931
  const socketName = process.meta?.tmuxSocket as string | undefined;
963
932
  const turnWatchResume = this.turnWatchResume?.process === process ? this.turnWatchResume : undefined;
964
933
  this.statusWatchersStopped = false;
965
- if (sessionName) this.watchTmuxSession(sessionName, socketName, process.meta?.oneShotExitCodeFile as string | undefined);
934
+ if (sessionName) this.watchTmuxSession(sessionName, socketName, process.meta?.exitCodeFile as string | undefined, process.meta?.printMode === true);
966
935
  if (turnWatchResume) await this.beginMonitorlessTurnWatch(process, turnWatchResume.sessionName, turnWatchResume.socketName, false);
967
936
  }
968
937
 
@@ -1058,22 +1027,6 @@ export { claudeActivityFromProbeAndPane, claudePaneLooksReady, claudePaneIsBusy,
1058
1027
  // Shared shell-quoting; re-exported so `./claude` consumers + tests resolve it.
1059
1028
  export { shellQuote };
1060
1029
 
1061
- export function findClaudeRigRC(cwd: string): string | null {
1062
- const home = homedir();
1063
- let dir = resolve(cwd);
1064
- while (true) {
1065
- // Stop at $HOME without inspecting it: ~/.claude-rig is the claude-rig tool's
1066
- // own config home, not a per-project rc marker. Matching it would make every
1067
- // project under $HOME look like a claude-rig project.
1068
- if (dir === home) return null;
1069
- const rc = join(dir, ".claude-rig");
1070
- if (existsSync(rc)) return rc;
1071
- const parent = resolve(dir, "..");
1072
- if (parent === dir) return null;
1073
- dir = parent;
1074
- }
1075
- }
1076
-
1077
1030
  async function terminateSingleProcess(process: ManagedProcess, opts: { graceful: boolean; timeoutMs: number }): Promise<ShutdownOutcome> {
1078
1031
  const proc = process.process;
1079
1032
  if (!proc) return "killed"; // nothing to kill — vacuously terminal
@@ -1,61 +1,47 @@
1
1
  import { writeChildEnv } from "@humwick/sdk/env";
2
- import type { QuotaState, HumwickHttpClient } from "@humwick/sdk";
2
+ import type { QuotaState, HeartbeatReport, HeartbeatResult } from "@humwick/sdk";
3
3
  import { getManifest } from "@humwick/providers";
4
4
  import { quotaStateFromProbeMetrics } from "@humwick/sdk/context-probe";
5
5
  import { claudeQuotaGeneration, claudeQuotaUnavailableWindows } from "@humwick/sdk/provider-quota-order";
6
6
  import { readRunnerContextProbeState } from "../context-probe-state";
7
7
  import { providerHostConfigHome } from "../profile-home";
8
- import { DEFAULT_PROVIDER_QUOTA_CONFIG, normalizeProviderQuotaConfig, resolveClaudeStatuslineQuotaIdentity, type ProviderQuotaIdentity } from "../quota";
8
+ import { resolveClaudeStatuslineQuotaIdentity, type ProviderQuotaIdentity } from "../quota";
9
9
 
10
- const PASSIVE_QUOTA_CONFIG_REFRESH_MS = 60_000;
11
10
  const PASSIVE_QUOTA_SAMPLE_STALE_MS = 10 * 60_000;
12
- const PASSIVE_QUOTA_LEASE_MAX_TTL_MS = 10 * 60_000;
13
- const PASSIVE_QUOTA_LEASE_PADDING_MS = 60_000;
14
11
 
15
12
  interface ProviderQuotaHarvestOptions {
16
13
  agentId: string;
17
14
  provider: string;
18
15
  /** The runner's per-provider config env (central provider-config values), read lazily each publish. */
19
16
  providerConfigEnv: () => Record<string, string>;
20
- http: () => Pick<HumwickHttpClient, "acquireProviderQuotaPublisherLease" | "getProviderQuotaConfig" | "upsertProviderQuota">;
21
17
  }
22
18
 
23
19
  export class ProviderQuotaHarvest {
24
- private config = { ...DEFAULT_PROVIDER_QUOTA_CONFIG };
25
- private configRefreshAt = 0;
26
- private lastReportAt?: number;
27
20
  private lastReportedObservedAt?: number;
28
- private lease?: { accountKey: string; leaseToken: string; expiresAt: number };
29
- private nextLeaseAttemptAt?: number;
21
+ private nextAttemptAt = 0;
22
+ private lease?: { accountKey: string; leaseToken: string };
30
23
 
31
24
  constructor(private readonly options: ProviderQuotaHarvestOptions) {}
32
25
 
33
- async publish(): Promise<void> {
34
- // #2514 — the statusline harvest serves the whole claude FAMILY (claude + claude-b): the
35
- // manifest's shim kind is the family declaration, so a second-subscription provider reuses
36
- // this path under its own id without a provider list here.
37
- if (getManifest(this.options.provider)?.shim?.kind !== "claude-relay") return;
38
- const probeMetrics = readRunnerContextProbeState(this.options.agentId);
39
- const now = Date.now();
40
- const quota = probeMetrics ? freshQuotaFromProbeMetrics(probeMetrics, now) : undefined;
41
- // An idle session re-sends nothing new; skipping lets its lease lapse to an active session (#3082).
26
+ async sample(): Promise<Pick<HeartbeatReport, "providerQuota" | "quotaLeaseToken"> | undefined> {
27
+ if (getManifest(this.options.provider)?.shim?.kind !== "claude-relay" || Date.now() < this.nextAttemptAt) return;
28
+ const metrics = readRunnerContextProbeState(this.options.agentId);
29
+ const quota = metrics ? freshQuotaFromProbeMetrics(metrics, Date.now()) : undefined;
42
30
  if (!quota || (this.lastReportedObservedAt !== undefined && quota.updatedAt <= this.lastReportedObservedAt)) return;
43
- const config = await this.refreshConfig();
44
- if (!config.enabled) return;
45
- if (this.lastReportAt !== undefined && now - this.lastReportAt < config.pollIntervalMs) return;
46
31
  const identity = await this.resolveIdentity();
47
32
  if (!identity) return;
48
- if (!await this.ensurePublisherLease(identity.accountKey, config.pollIntervalMs, now)) return;
49
- await this.options.http().upsertProviderQuota({
50
- provider: this.options.provider,
51
- accountKey: identity.accountKey,
52
- quota,
53
- unavailableWindows: claudeQuotaUnavailableWindows(quota),
54
- lastAttemptAt: now,
55
- sourceAgentId: this.options.agentId,
56
- });
57
- this.lastReportAt = now;
58
- this.lastReportedObservedAt = quota.updatedAt;
33
+ return {
34
+ providerQuota: { provider: this.options.provider, accountKey: identity.accountKey, quota,
35
+ unavailableWindows: claudeQuotaUnavailableWindows(quota), lastAttemptAt: Date.now(), sourceAgentId: this.options.agentId },
36
+ ...(this.lease?.accountKey === identity.accountKey ? { quotaLeaseToken: this.lease.leaseToken } : {}),
37
+ };
38
+ }
39
+
40
+ accept(report: HeartbeatReport, result: HeartbeatResult["providerQuota"]): void {
41
+ if (!result || !report.providerQuota) return;
42
+ this.nextAttemptAt = Date.now() + result.retryAfterMs;
43
+ if (result.reported) this.lastReportedObservedAt = report.providerQuota.quota?.updatedAt;
44
+ if (result.leaseToken) this.lease = { accountKey: report.providerQuota.accountKey, leaseToken: result.leaseToken };
59
45
  }
60
46
 
61
47
  // #2514 — quota identity resolves exactly as the LAUNCH authenticates. The primary claude
@@ -77,43 +63,6 @@ export class ProviderQuotaHarvest {
77
63
  });
78
64
  }
79
65
 
80
- private async refreshConfig() {
81
- const now = Date.now();
82
- if (now < this.configRefreshAt) return this.config;
83
- this.configRefreshAt = now + PASSIVE_QUOTA_CONFIG_REFRESH_MS;
84
- try {
85
- const map = await this.options.http().getProviderQuotaConfig();
86
- const providerCfg = map[this.options.provider];
87
- this.config = providerCfg
88
- ? normalizeProviderQuotaConfig(providerCfg)
89
- : { ...DEFAULT_PROVIDER_QUOTA_CONFIG };
90
- } catch {
91
- // Keep the previous config; defaults preserve collection if the relay is older
92
- // or temporarily unreachable during a liveness tick.
93
- }
94
- return this.config;
95
- }
96
-
97
- private async ensurePublisherLease(accountKey: string, pollIntervalMs: number, now: number): Promise<boolean> {
98
- if (this.lease?.accountKey === accountKey && this.lease.expiresAt > now) return true;
99
- if (this.nextLeaseAttemptAt !== undefined && now < this.nextLeaseAttemptAt) return false;
100
- const leaseToken = this.lease?.accountKey === accountKey ? this.lease.leaseToken : undefined;
101
- const result = await this.options.http().acquireProviderQuotaPublisherLease({
102
- provider: this.options.provider,
103
- accountKey,
104
- sourceAgentId: this.options.agentId,
105
- ...(leaseToken ? { leaseToken } : {}),
106
- ttlMs: Math.min(PASSIVE_QUOTA_LEASE_MAX_TTL_MS, pollIntervalMs + PASSIVE_QUOTA_LEASE_PADDING_MS),
107
- });
108
- if (!result.acquired || !result.lease) {
109
- this.lease = undefined;
110
- this.nextLeaseAttemptAt = now + Math.min(result.retryAfterMs ?? pollIntervalMs, pollIntervalMs);
111
- return false;
112
- }
113
- this.lease = { accountKey, leaseToken: result.lease.leaseToken, expiresAt: result.lease.expiresAt };
114
- this.nextLeaseAttemptAt = undefined;
115
- return true;
116
- }
117
66
  }
118
67
 
119
68
  function freshQuotaFromProbeMetrics(metrics: NonNullable<ReturnType<typeof readRunnerContextProbeState>>, now: number): QuotaState | undefined {
@@ -24,7 +24,7 @@ interface LifecycleMilestoneDeps {
24
24
  stopDrainTimer(): void;
25
25
  stopSubmitRecoveryPoll(): void;
26
26
  stopTaskClaims(): void;
27
- stopHttpLiveness(): void;
27
+ stopLiveness(): void;
28
28
  stopCredentials(): void;
29
29
  disarmBusyLivenessReconcile(): void;
30
30
  disarmBusyReconciler(): void;
@@ -140,7 +140,7 @@ export class LifecycleMilestones {
140
140
  this.deps.stopDrainTimer();
141
141
  this.deps.stopSubmitRecoveryPoll();
142
142
  this.deps.stopTaskClaims();
143
- this.deps.stopHttpLiveness();
143
+ this.deps.stopLiveness();
144
144
  this.deps.stopCredentials();
145
145
  this.deps.disarmBusyLivenessReconcile();
146
146
  this.deps.disarmBusyReconciler();
@@ -0,0 +1,104 @@
1
+ import { errMessage, type HumwickBusClient, type HumwickHttpClient, type HeartbeatReport, type HeartbeatResult, type Message } from "@humwick/sdk";
2
+ import { httpErrorKey, isHttpAuthError, runnerAgentStatus } from "../runner-helpers";
3
+ import type { ClaimTracker } from "../claim-tracker";
4
+
5
+ const LIVENESS_INTERVAL_MS = 20_000;
6
+ // Shorter than the interval, so a wedged bus exchange falls back to HTTP before the next tick.
7
+ const BUS_LIVENESS_TIMEOUT_MS = 15_000;
8
+
9
+ interface LivenessExchangeDeps {
10
+ http: Pick<HumwickHttpClient, "heartbeat">;
11
+ bus(): Pick<HumwickBusClient, "livenessAvailable" | "reportLiveness">;
12
+ agentId: string;
13
+ instanceId: string;
14
+ logIntervalMs: number;
15
+ isStopped(): boolean;
16
+ isTerminalStatusLatched(): boolean;
17
+ currentStatus: ClaimTracker["currentStatus"];
18
+ sampleQuota(): Promise<Pick<HeartbeatReport, "providerQuota" | "quotaLeaseToken"> | undefined>;
19
+ acceptQuota(report: HeartbeatReport, result: HeartbeatResult["providerQuota"]): void;
20
+ enqueueMessage(message: Message): void;
21
+ triggerEffort(): void;
22
+ recoverRuntimeTokenAfterAuthFailure(source: string): void;
23
+ logRunnerDiagnostic(message: string): void;
24
+ }
25
+
26
+ /** The runner's periodic liveness exchange (#3608). It rides the registered bus socket and falls
27
+ * back to HTTP while the socket is down or the exchange fails on it (#3618). */
28
+ export class LivenessExchange {
29
+ private timer?: Timer;
30
+ private inFlight = false;
31
+ private authFailed = false;
32
+ private lastLog?: { key: string; at: number };
33
+
34
+ constructor(private readonly deps: LivenessExchangeDeps) {}
35
+
36
+ stop(): void {
37
+ if (this.timer) clearInterval(this.timer);
38
+ this.timer = undefined;
39
+ }
40
+
41
+ resetAuthFailure(): void { this.authFailed = false; }
42
+
43
+ start(): void {
44
+ if (this.timer) clearInterval(this.timer);
45
+ void this.publish();
46
+ this.timer = setInterval(() => {
47
+ void this.publish();
48
+ }, LIVENESS_INTERVAL_MS);
49
+ }
50
+
51
+ private async publish(): Promise<void> {
52
+ if (this.deps.isStopped() || this.deps.isTerminalStatusLatched() || this.inFlight || this.authFailed) return;
53
+ this.inFlight = true;
54
+ const status = this.deps.currentStatus();
55
+ const agentStatus = runnerAgentStatus(status);
56
+ try {
57
+ const quota = await this.deps.sampleQuota().catch((error) => {
58
+ this.deps.logRunnerDiagnostic(`passive provider quota sample failed: ${errMessage(error)}`);
59
+ });
60
+ // #3608 — inbox recovery and fresh quota samples ride the single liveness exchange.
61
+ const report: HeartbeatReport = { status: agentStatus, ready: agentStatus !== "offline", unread: true, ...quota };
62
+ const result = await this.exchange(report);
63
+ this.deps.acceptQuota(report, result?.providerQuota);
64
+ for (const message of result?.messages ?? []) this.deps.enqueueMessage(message);
65
+ this.deps.triggerEffort();
66
+ } catch (error) {
67
+ if (!this.deps.isStopped()) this.handleHttpFailure(error);
68
+ } finally {
69
+ this.inFlight = false;
70
+ }
71
+ }
72
+
73
+ private async exchange(report: HeartbeatReport): Promise<HeartbeatResult> {
74
+ const bus = this.deps.bus();
75
+ if (bus.livenessAvailable) {
76
+ try {
77
+ return await bus.reportLiveness(report, BUS_LIVENESS_TIMEOUT_MS);
78
+ } catch (error) {
79
+ // The report is idempotent (status, readiness, unread by id), so a retry over HTTP is safe.
80
+ this.logFailure(`bus:${errMessage(error)}`, `[runner] bus liveness exchange failed, using HTTP: ${errMessage(error)}`);
81
+ }
82
+ }
83
+ return await this.deps.http.heartbeat(this.deps.agentId, this.deps.instanceId, report);
84
+ }
85
+
86
+ private handleHttpFailure(error: unknown): void {
87
+ const authFailed = isHttpAuthError(error);
88
+ const suffix = authFailed ? "auth failed; stopping HTTP liveness retries until restart" : String(error);
89
+ this.logFailure(httpErrorKey(error), `[runner] HTTP liveness update failed: ${suffix}`);
90
+ if (!authFailed) return;
91
+ this.authFailed = true;
92
+ this.stop();
93
+ // A 401/403 here is the only timely signal that the token died — stopping the
94
+ // liveness timer means there is no second chance, so recover from THIS failure.
95
+ this.deps.recoverRuntimeTokenAfterAuthFailure("http-liveness");
96
+ }
97
+
98
+ private logFailure(key: string, message: string): void {
99
+ const now = Date.now();
100
+ if (this.lastLog?.key === key && now - this.lastLog.at < this.deps.logIntervalMs) return;
101
+ this.lastLog = { key, at: now };
102
+ this.deps.logRunnerDiagnostic(message);
103
+ }
104
+ }
@@ -0,0 +1,49 @@
1
+ import { dirname, join, resolve } from "node:path";
2
+ import { HARNESS_SUBAGENTS_DISABLED, harnessSubagentsEnabled } from "@humwick/sdk";
3
+ import type { RunnerSpawnConfig } from "./adapter";
4
+ import { bundledIntegrationHome } from "./provider-integration";
5
+ import { composeSystemPromptAppend } from "./project-instructions";
6
+ import { CLAUDE_NO_ATTRIBUTION_RULE } from "./claude-settings";
7
+ import { claudeWebToolsSteer } from "./web-tools";
8
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
9
+
10
+ const APPEND_FLAGS = ["--append-system-prompt", "--append-system-prompt-file"];
11
+
12
+ // #3830 — caller/default appends share the same file channel as Relay context.
13
+ export function claudeCallerAppends(args: string[]): { args: string[]; appends: Array<{ value: string; file: boolean }> } {
14
+ const remaining: string[] = [];
15
+ const appends: Array<{ value: string; file: boolean }> = [];
16
+ for (let i = 0; i < args.length; i++) {
17
+ const arg = args[i]!;
18
+ if (arg === "--") { remaining.push(...args.slice(i)); break; }
19
+ const flag = APPEND_FLAGS.find(flag => arg === flag || arg.startsWith(`${flag}=`));
20
+ if (!flag) { remaining.push(arg); continue; }
21
+ const value = arg === flag ? args[++i] : arg.slice(flag.length + 1);
22
+ if (value === undefined) throw new Error(`${flag} requires a value`);
23
+ appends.push({ value, file: flag.endsWith("-file") });
24
+ }
25
+ return { args: remaining, appends };
26
+ }
27
+
28
+ export function resolveClaudeSystemPrompt(config: RunnerSpawnConfig, defaultArgs: string[], assetHome?: string) {
29
+ const composed = composeSystemPromptAppend(config);
30
+ const parts: Array<{ text: string } | { file: string }> = [{ text: composed.text }];
31
+ for (const append of claudeCallerAppends([...defaultArgs, ...config.providerArgs]).appends) {
32
+ parts.push(append.file ? { file: resolve(config.cwd, append.value) } : { text: append.value });
33
+ }
34
+ parts.push(...[...(harnessSubagentsEnabled(config) ? [] : [HARNESS_SUBAGENTS_DISABLED]), claudeWebToolsSteer(config), CLAUDE_NO_ATTRIBUTION_RULE].map(text => ({ text })));
35
+ return {
36
+ path: join(assetHome ?? bundledIntegrationHome(config), "system-prompt-append.md"),
37
+ reinjected: composed.reinjected,
38
+ parts,
39
+ };
40
+ }
41
+
42
+ export function materializeClaudeSystemPrompt(file?: ReturnType<typeof resolveClaudeSystemPrompt>): void {
43
+ if (!file) return;
44
+ // Report-only assembly never opens caller files; launch materialization owns that failure.
45
+ const text = file.parts.map(part => "text" in part ? part.text : readFileSync(part.file, "utf8")).filter(Boolean).join("\n\n");
46
+ mkdirSync(dirname(file.path), { recursive: true, mode: 0o700 });
47
+ writeFileSync(file.path, text, { mode: 0o600 });
48
+ chmodSync(file.path, 0o600);
49
+ }
@@ -1,10 +1,10 @@
1
1
  import { bundledIntegrationAssets, bundledIntegrationHome, suppressOwnedClaudePlugins, selectClaudePluginDirs } from "./provider-integration";
2
2
  import { relayEnv, writeChildEnv } from "@humwick/sdk/env";
3
3
  import { codexRetiredMcpConfigArgs } from "./adapters/codex-effective-config";
4
- import { activeSharedMcpServers, HARNESS_SUBAGENTS_DISABLED, harnessSubagentsEnabled } from "@humwick/sdk";
4
+ import { activeSharedMcpServers } from "@humwick/sdk";
5
5
  import { claudeSubagentHooks, claudeSubagentSettings } from "./adapters/claude-subagents";
6
6
  import { serviceAccessLaunchEnv, serviceAccessMcpServers } from "./adapters/service-access";
7
- import { claudeSettingsArgs, CLAUDE_NO_ATTRIBUTION_RULE, extractCallerSettings, stripSettingsArgs, mergeHookSets, hasSettingsArg, sessionStatusLineSettingsArgs } from "./claude-settings";
7
+ import { claudeSettingsArgs, extractCallerSettings, stripSettingsArgs, mergeHookSets, hasSettingsArg, sessionStatusLineSettingsArgs } from "./claude-settings";
8
8
  export { stripSettingsArgs, sessionStatusLineSettingsArgs } from "./claude-settings";
9
9
  import { rmSync, writeFileSync } from "node:fs";
10
10
  import { basename, relative, resolve, join } from "node:path";
@@ -45,8 +45,8 @@ import type { ResolvedProjectClaudeSettings } from "./provisioning";
45
45
  import { resolveMcpSources, type McpSourceSelection } from "./mcp-source-selection";
46
46
  import { resolveProjectHooks } from "./project-hooks";
47
47
  import { agentRedactEnv, agentRedactOn, isAgentRedactInstall, resolveAgentRedact, type AgentRedactState } from "./agent-redact";
48
- import { composeSystemPromptAppend } from "./project-instructions";
49
- import { claudeWebToolsSteer, disabledSharedWebTools, webToolsEnv, withDisabledWebTools } from "./web-tools";
48
+ import { resolveClaudeSystemPrompt, materializeClaudeSystemPrompt } from "./claude-system-prompt";
49
+ import { disabledSharedWebTools, webToolsEnv, withDisabledWebTools } from "./web-tools";
50
50
  import {
51
51
  claudeMcpConfigPayload,
52
52
  claudeMcpLaunchArgs,
@@ -160,6 +160,7 @@ export interface AssembledMcp {
160
160
 
161
161
  export interface AssembledLaunch {
162
162
  provider: SpawnProvider;
163
+ systemPromptFile?: ReturnType<typeof resolveClaudeSystemPrompt>;
163
164
  /** The resolved profile this launch was assembled from; undefined for a profile-less
164
165
  * (legacy default) spawn, which behaves as host base with relay features default-on. */
165
166
  profile?: AgentProfile;
@@ -546,8 +547,8 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
546
547
  // #2086 — when P.hooks forces the project scope off but P.instructions is on, re-inject the repo
547
548
  // CLAUDE.md/AGENTS.md through the controlled append-system-prompt channel so the docs are honored
548
549
  // rather than silently dropped (see composeSystemPromptAppend / resolveProjectInstructions).
549
- const { text: composedAppend, reinjected: repoInstructionsReinjected } = composeSystemPromptAppend(config);
550
- const systemPromptAppend = [composedAppend, ...(harnessSubagentsEnabled(config) ? [] : [HARNESS_SUBAGENTS_DISABLED]), claudeWebToolsSteer(config), CLAUDE_NO_ATTRIBUTION_RULE].filter(Boolean).join("\n\n");
550
+ const promptFile = resolveClaudeSystemPrompt(config, hostDefaultArgs, assetHome);
551
+ const repoInstructionsReinjected = promptFile.reinjected;
551
552
  const instructions = assembleInstructions(config, {
552
553
  projectScopeDropped,
553
554
  isolatedHome: Boolean(configHome),
@@ -570,11 +571,12 @@ function assembleClaude(config: RunnerSpawnConfig, providerConfig: ProviderConfi
570
571
  ...(mcpConfigFilePath ? { configFilePath: mcpConfigFilePath } : {}),
571
572
  }),
572
573
  ...settings.args,
573
- ...(systemPromptAppend ? ["--append-system-prompt", systemPromptAppend] : []),
574
+ "--append-system-prompt-file", promptFile.path,
574
575
  ];
575
576
 
576
577
  return {
577
578
  provider,
579
+ systemPromptFile: promptFile,
578
580
  ...(config.agentProfile ? { profile: config.agentProfile } : {}),
579
581
  base: config.agentProfile?.base ?? "host",
580
582
  vanilla,
@@ -938,10 +940,12 @@ export function assembleLaunch(provider: SpawnProvider, config: RunnerSpawnConfi
938
940
  /**
939
941
  * Write the provisioned assets the assembly describes (skills/plugins/hooks and Codex
940
942
  * hooks.json). Driven by the SAME resolvers `assembleLaunch` uses, so disk == launch ==
941
- * report. Idempotent; the isolated home must already exist (prepare*ProfileHome). No-op
942
- * for a host-base profile.
943
+ * report. Idempotent; the isolated home must already exist (prepare*ProfileHome). Claude
944
+ * system context also uses a private file for host-base and profile-less launches.
943
945
  */
944
- export function materializeLaunchAssembly(provider: SpawnProvider, config: RunnerSpawnConfig): void {
946
+ export function materializeLaunchAssembly(provider: SpawnProvider, config: RunnerSpawnConfig, assembled?: AssembledLaunch): void {
947
+ // #3830 — every Claude path, including host-base/profile-less, uses a private file.
948
+ if (getManifest(provider)?.shim?.kind === "claude-relay") materializeClaudeSystemPrompt((assembled ?? assembleLaunch(provider, config, config.providerConfig)).systemPromptFile);
945
949
  if (!config.agentProfile && runnerMcpGeneration(config.env) === "humwick") {
946
950
  const feature = getManifest(provider)?.provisioning?.bundledSkills ? "skills" : "plugins";
947
951
  if (profileAllowsRelayFeature(config, feature)) {
@@ -78,7 +78,7 @@ export function providerHomePathFor(provider: SpawnProvider, config: RunnerSpawn
78
78
  // the repo's CLAUDE.md / AGENTS.md as behavioral instructions, NOT "don't
79
79
  // operate here" — an isolated agent must still read/edit/execute in its own cwd.
80
80
  //
81
- // #2254 — claude-rig / host-base launches skip the onboarding/theme bootstrap (an
81
+ // #2254 — host-base launches skip the onboarding/theme bootstrap (an
82
82
  // onboarded host config already answers those), but they do NOT dodge folder trust:
83
83
  // --dangerously-skip-permissions does not bypass the trust gate, and a cwd the host
84
84
  // config has never seen still renders the dialog and wedges the spawn. Trust is
@@ -11,8 +11,8 @@ import { projectSettingSourcesOn } from "./profile-home";
11
11
  // the Claude re-injection channel and lists both names the cwd may carry.
12
12
  const REPO_INSTRUCTION_FILES = ["CLAUDE.md", "AGENTS.md"] as const;
13
13
 
14
- // Bound each re-injected file so a pathological repo doc can't balloon the launch argv
15
- // (append-system-prompt rides the command line). Mirrors the spirit of Codex's
14
+ // Bound each re-injected file so a pathological repo doc cannot balloon the context.
15
+ // The composed append travels by private file (#3830). Mirrors Codex's
16
16
  // project_doc_max_bytes default; oversized content is truncated with a loud marker
17
17
  // rather than silently dropped.
18
18
  const REPO_INSTRUCTIONS_MAX_BYTES = 64 * 1024;
@@ -0,0 +1,18 @@
1
+ import { basename } from "node:path";
2
+ import { logger } from "./logger";
3
+
4
+ const warned = new Set<string>();
5
+
6
+ /**
7
+ * The ONE place a provider's launch command is resolved. The launch and the pre-spawn login check
8
+ * both call it, so the check can never probe a different binary than the launch runs.
9
+ * A stored `claude-rig` command (the retired wrapper) is treated as plain `claude`, with one warning.
10
+ */
11
+ export function resolveLaunchCommand(command: string): string {
12
+ if (basename(command) !== "claude-rig") return command;
13
+ if (!warned.has(command)) {
14
+ warned.add(command);
15
+ logger.warn("provider-command", `stored provider command "${command}" is the retired claude-rig wrapper; launching plain "claude" instead. Set the provider command to "claude" in the dashboard.`);
16
+ }
17
+ return "claude";
18
+ }