@humwick/runner 0.130.5 → 0.130.6

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 (211) hide show
  1. package/agent-bin/humwick +2 -2
  2. package/agent-bin/humwick-browser +4 -0
  3. package/hooks/fff-search-redirect/fff-search-redirect.cjs +1 -1
  4. package/hooks/web-tools-redirect/web-tools-redirect.cjs +2 -2
  5. package/package.json +7 -10
  6. package/plugins/browser/skills/playwright-cli/SKILL.md +8 -6
  7. package/plugins/claude/.claude-plugin/plugin.json +3 -3
  8. package/plugins/claude/claude-statusline-probe.cjs +26 -16
  9. package/plugins/claude/hooks/gate-run-guard.provisioned.mjs +47 -17
  10. package/plugins/claude/hooks/gate-run-guard.sh +3 -3
  11. package/plugins/claude/hooks/gate-run-guard.ts +5 -5
  12. package/plugins/claude/hooks/kill-guard.sh +4 -4
  13. package/plugins/claude/hooks/kill-guard.ts +1 -1
  14. package/plugins/claude/hooks/permission-request.sh +1 -1
  15. package/plugins/claude/hooks/post-compact.sh +1 -1
  16. package/plugins/claude/hooks/post-tool-use.sh +3 -3
  17. package/plugins/claude/hooks/pre-compact.sh +2 -2
  18. package/plugins/claude/hooks/read-only-bash-guard.sh +4 -4
  19. package/plugins/claude/hooks/relay-status.sh +32 -32
  20. package/plugins/claude/hooks/session-end.sh +2 -2
  21. package/plugins/claude/hooks/session-start.sh +3 -3
  22. package/plugins/claude/hooks/shell-trust.ts +1 -1
  23. package/plugins/claude/hooks/stop-failure.sh +2 -2
  24. package/plugins/claude/hooks/stop.sh +6 -6
  25. package/plugins/claude/hooks/subagent-skill-policy.cjs +8 -6
  26. package/plugins/claude/hooks/subagent-stop.sh +3 -3
  27. package/plugins/claude/hooks/user-prompt-submit.sh +1 -1
  28. package/plugins/claude/hooks/wait-loop-guard.ts +3 -3
  29. package/plugins/claude/monitors/monitors.json +2 -2
  30. package/plugins/claude/monitors/relay-monitor.provisioned.mjs +96 -62
  31. package/plugins/claude/monitors/relay-monitor.ts +5 -5
  32. package/plugins/claude/skills/label/SKILL.md +3 -3
  33. package/plugins/claude/skills/message/SKILL.md +5 -5
  34. package/plugins/claude/skills/react/SKILL.md +1 -1
  35. package/plugins/claude/skills/read-message/SKILL.md +4 -4
  36. package/plugins/claude/skills/reply/SKILL.md +5 -5
  37. package/plugins/claude/skills/send-claimable/SKILL.md +5 -5
  38. package/plugins/claude/skills/slice-first/SKILL.md +5 -3
  39. package/plugins/claude/skills/slice-first/references/plan-recipe.md +30 -29
  40. package/plugins/claude/skills/status/SKILL.md +1 -1
  41. package/plugins/claude/skills/tags/SKILL.md +5 -5
  42. package/plugins/claude/skills/task/SKILL.md +10 -10
  43. package/plugins/claude-output-style/.claude-plugin/plugin.json +1 -1
  44. package/plugins/claude-output-style/output-styles/{agent-relay.md → humwick.md} +1 -1
  45. package/plugins/codex/skills/guide/SKILL.md +1 -1
  46. package/plugins/codex/skills/label/SKILL.md +3 -3
  47. package/plugins/codex/skills/message/SKILL.md +5 -5
  48. package/plugins/codex/skills/react/SKILL.md +1 -1
  49. package/plugins/codex/skills/read-message/SKILL.md +4 -4
  50. package/plugins/codex/skills/reply/SKILL.md +5 -5
  51. package/plugins/codex/skills/send-claimable/SKILL.md +5 -5
  52. package/plugins/codex/skills/slice-first/SKILL.md +5 -3
  53. package/plugins/codex/skills/slice-first/references/plan-recipe.md +30 -29
  54. package/plugins/codex/skills/status/SKILL.md +1 -1
  55. package/plugins/codex/skills/tags/SKILL.md +5 -5
  56. package/plugins/codex/skills/task/SKILL.md +11 -10
  57. package/src/adapter.ts +95 -92
  58. package/src/adapters/claude-api.ts +8 -11
  59. package/src/adapters/claude-context-command.ts +1 -1
  60. package/src/adapters/claude-credentials.ts +7 -3
  61. package/src/adapters/claude-delivery-lanes.ts +2 -2
  62. package/src/adapters/claude-delivery.ts +16 -16
  63. package/src/adapters/claude-effort.ts +2 -2
  64. package/src/adapters/claude-exit.ts +2 -2
  65. package/src/adapters/claude-headless-mirror.ts +18 -2
  66. package/src/adapters/claude-headless-refusal.ts +3 -3
  67. package/src/adapters/claude-headless.ts +11 -10
  68. package/src/adapters/claude-launch-exit.ts +1 -1
  69. package/src/adapters/claude-monitor-delivery-plan.ts +36 -16
  70. package/src/adapters/claude-permission.ts +5 -5
  71. package/src/adapters/claude-prompt-gates.ts +9 -9
  72. package/src/adapters/claude-prompt-hook.ts +2 -2
  73. package/src/adapters/claude-session-capture.ts +6 -6
  74. package/src/adapters/claude-session-probe.ts +25 -25
  75. package/src/adapters/claude-shutdown.ts +11 -11
  76. package/src/adapters/claude-status-detectors.ts +31 -31
  77. package/src/adapters/claude-subagents.ts +7 -7
  78. package/src/adapters/claude-submit-confirmation.ts +6 -6
  79. package/src/adapters/claude-tmux.ts +43 -43
  80. package/src/adapters/claude-token-usage-capture.ts +5 -5
  81. package/src/adapters/claude-tool-policy.ts +7 -7
  82. package/src/adapters/claude-transcript.ts +24 -24
  83. package/src/adapters/claude.ts +100 -100
  84. package/src/adapters/codex-agent-message-capture.ts +26 -63
  85. package/src/adapters/codex-app-server.ts +1 -1
  86. package/src/adapters/codex-client.ts +9 -9
  87. package/src/adapters/codex-effective-config.ts +1 -1
  88. package/src/adapters/codex-launch-config.ts +5 -5
  89. package/src/adapters/codex-rollout-context.ts +2 -2
  90. package/src/adapters/codex-skill-discovery.ts +1 -1
  91. package/src/adapters/codex-token-usage-capture.ts +16 -16
  92. package/src/adapters/codex-tool-output.ts +4 -4
  93. package/src/adapters/codex-version.ts +3 -3
  94. package/src/adapters/codex.ts +64 -64
  95. package/src/adapters/opencode-api.ts +1 -1
  96. package/src/adapters/opencode-context.ts +20 -22
  97. package/src/adapters/opencode-model-registry.ts +7 -7
  98. package/src/adapters/opencode-provider.ts +8 -8
  99. package/src/adapters/opencode-provisioning.ts +30 -0
  100. package/src/adapters/opencode-server-retry.ts +1 -1
  101. package/src/adapters/opencode-soft-steer.ts +5 -5
  102. package/src/adapters/opencode-spawn.ts +18 -14
  103. package/src/adapters/opencode-token-usage-capture.ts +12 -12
  104. package/src/adapters/opencode-tool-events.ts +15 -15
  105. package/src/adapters/opencode.ts +232 -232
  106. package/src/adapters/project-shell.ts +11 -11
  107. package/src/adapters/service-access.ts +6 -6
  108. package/src/adapters/tmux-offload.ts +9 -9
  109. package/src/adapters/tool-summary.ts +5 -5
  110. package/src/agent-redact.ts +1 -1
  111. package/src/agent-runner/commands/dispatch.ts +10 -10
  112. package/src/agent-runner/commands/lifecycle.ts +2 -2
  113. package/src/agent-runner/commands/prompt.ts +19 -19
  114. package/src/agent-runner/credentials.ts +5 -5
  115. package/src/agent-runner/inbox.ts +1 -1
  116. package/src/agent-runner/lifecycle-milestones.ts +3 -3
  117. package/src/agent-runner/lifecycle-phase.ts +2 -2
  118. package/src/agent-runner/liveness-exchange.ts +4 -10
  119. package/src/agent-runner/registration.ts +8 -8
  120. package/src/agent-runner/runner-context.ts +9 -14
  121. package/src/agent-runner/session-mirror.ts +12 -12
  122. package/src/agent-runner/task-claims.ts +2 -2
  123. package/src/agent-runner/token-usage-coverage.ts +1 -1
  124. package/src/agent-runner/turn-report.ts +12 -12
  125. package/src/api-budget-accounting.ts +3 -3
  126. package/src/area-memory.ts +6 -6
  127. package/src/artifact-path-materialize.ts +1 -1
  128. package/src/async-guard.ts +5 -5
  129. package/src/attachment-cache.ts +17 -22
  130. package/src/background-script-reconcile.ts +6 -6
  131. package/src/bounded-log.ts +1 -1
  132. package/src/busy-reconciler.ts +22 -22
  133. package/src/claim-tracker.ts +3 -3
  134. package/src/claude-settings.ts +8 -8
  135. package/src/claude-system-prompt.ts +1 -1
  136. package/src/claude-workspace-trust.ts +1 -1
  137. package/src/config.ts +62 -61
  138. package/src/context-boundary.ts +5 -5
  139. package/src/context-command.ts +3 -3
  140. package/src/control-server.ts +32 -32
  141. package/src/delivery-result.ts +2 -2
  142. package/src/effort-command.ts +2 -2
  143. package/src/empty-turn.ts +22 -14
  144. package/src/free-port.ts +1 -1
  145. package/src/gate-run-config.ts +3 -3
  146. package/src/host-asset-plan.ts +24 -17
  147. package/src/host-claude-config-worker.ts +2 -2
  148. package/src/host-sources.ts +2 -2
  149. package/src/index.ts +16 -16
  150. package/src/launch-assembly.ts +94 -96
  151. package/src/liveness.ts +15 -15
  152. package/src/logger.ts +3 -3
  153. package/src/mcp-outbox.ts +3 -3
  154. package/src/mcp-preflight.ts +2 -2
  155. package/src/mcp-source-selection.ts +2 -2
  156. package/src/mcp-tool-deferral.ts +1 -1
  157. package/src/mcp-vault-env.ts +2 -2
  158. package/src/message-body-config/config.ts +4 -4
  159. package/src/mid-turn-delivery.ts +2 -2
  160. package/src/native-memory-lever.ts +8 -8
  161. package/src/outbox.ts +15 -15
  162. package/src/pending-permission-store.ts +1 -1
  163. package/src/profile-home.ts +19 -19
  164. package/src/profile-projection.ts +26 -24
  165. package/src/project-instructions.ts +5 -5
  166. package/src/provider-auth-warning.ts +17 -0
  167. package/src/provider-double.ts +1 -1
  168. package/src/provider-hold.ts +3 -3
  169. package/src/provider-home-marker.ts +1 -1
  170. package/src/provider-home-tombstone.ts +1 -1
  171. package/src/provider-input-queue.ts +2 -2
  172. package/src/provider-integration.ts +15 -13
  173. package/src/provider-setup.ts +15 -3
  174. package/src/providers.ts +1 -1
  175. package/src/provisioning.ts +37 -40
  176. package/src/question-decision.ts +2 -2
  177. package/src/quota.ts +0 -6
  178. package/src/rate-limit.ts +24 -13
  179. package/src/refused-prompt-store.ts +2 -2
  180. package/src/relay-injection-events.ts +2 -2
  181. package/src/relay-instructions.ts +5 -5
  182. package/src/relay-mcp-proxy.long-turn-e2e.ts +13 -13
  183. package/src/relay-mcp-proxy.ts +57 -58
  184. package/src/relay-mcp.ts +55 -69
  185. package/src/reply-obligation-cache.ts +9 -9
  186. package/src/response-capture-report.ts +9 -9
  187. package/src/response-routing.ts +1 -1
  188. package/src/runner-core.ts +209 -222
  189. package/src/runner-exit.ts +1 -1
  190. package/src/runner-helpers.ts +10 -10
  191. package/src/runner-insights.ts +4 -2
  192. package/src/runner-mcp-proxy.ts +3 -3
  193. package/src/runner-spawn-config.ts +3 -3
  194. package/src/runtime-token-file.ts +1 -1
  195. package/src/runtime-token-remint.ts +1 -1
  196. package/src/service-access.ts +2 -2
  197. package/src/session-destroy.ts +1 -1
  198. package/src/session-insights.ts +1 -1
  199. package/src/session-scratch.ts +24 -37
  200. package/src/spawn-input.ts +6 -6
  201. package/src/startup-config-fetch.ts +4 -4
  202. package/src/subreaper.ts +3 -5
  203. package/src/test-run-dedup.ts +13 -13
  204. package/src/transcript-context.ts +2 -2
  205. package/src/transport-errors.ts +1 -1
  206. package/src/turn-opener.ts +1 -1
  207. package/src/turn-reconcile-event.ts +2 -2
  208. package/src/vault-proxy-hop.ts +2 -2
  209. package/src/web-tools.ts +2 -2
  210. package/agent-bin/agent-relay-browser +0 -10
  211. package/src/adapters/provider-quota-harvest.ts +0 -76
package/src/adapter.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { readHumwickRecord } from "@humwick/sdk/stored-names";
1
2
  import type { ServiceAccessHandoff } from "@humwick/sdk";
2
3
  import type { AgentProfile, InteractivePrompt, LivenessSignal, Message, MessageFinalityConfidence, MessageTurnEndReason, OperatorDecisionFileInput, ProviderState, ToolCallCategory } from "@humwick/sdk";
3
4
  // Leaf subpaths, not the barrel: the Claude monitor bundle imports this module and must stay small.
@@ -16,7 +17,7 @@ export { resolveRelayContext } from "./relay-instructions";
16
17
  export type SemanticStatus = "idle" | "busy" | "offline" | "error";
17
18
 
18
19
  /**
19
- * #1656 — the independent pane read is THREE-VALUED on its non-busy side, and collapsing it to a
20
+ * the independent pane read is THREE-VALUED on its non-busy side, and collapsing it to a
20
21
  * boolean was the defect. `false` used to mean both "captured the pane, no spinner" (evidence the
21
22
  * turn is over) and "could not read the pane at all" (no evidence of anything), and the busy
22
23
  * backstop's force-clear consumed the second as if it were the first: absence of evidence taken
@@ -51,7 +52,7 @@ export interface ProviderStatusEvent {
51
52
  label?: string;
52
53
  role?: string;
53
54
  parentId?: string;
54
- // OS pids of the process(es) this busy work tracks (#650). When supplied, the
55
+ // OS pids of the process(es) this busy work tracks. When supplied, the
55
56
  // runner reconciles them against actual liveness and clears the busy marker if
56
57
  // every pid is dead — recovering from a tracked process killed out-of-band.
57
58
  pids?: number[];
@@ -62,7 +63,7 @@ export interface ProviderStatusEvent {
62
63
  */
63
64
  refusedInputIds?: number[];
64
65
  metadata?: Record<string, unknown>;
65
- // #1235 — the live transcript path for a hookless (monitorless) provider turn. When an
66
+ // the live transcript path for a hookless (monitorless) provider turn. When an
66
67
  // adapter that learns turn boundaries WITHOUT Stop/UserPromptSubmit hooks (Claude's tmux
67
68
  // monitorless watch) supplies this on a `provider-turn` busy/idle event, the runner drives
68
69
  // the transcript reasoning tail natively: start on turn-start, capture the final response on
@@ -73,9 +74,9 @@ export interface ProviderStatusEvent {
73
74
  export type ProviderStatusUpdate = SemanticStatus | ProviderStatusEvent;
74
75
 
75
76
  /**
76
- * #1651 — pane evidence cannot end a turn, clear work, complete claims, decide a restart,
77
+ * pane evidence cannot end a turn, clear work, complete claims, decide a restart,
77
78
  * or send input. It carries no SemanticStatus or work-kind `clear`. The one display-only
78
- * exception is a startup-scoped bypass acceptance dialog (#2629): the runner may show a
79
+ * exception is a startup-scoped bypass acceptance dialog: the runner may show a
79
80
  * blocked badge and timeline alert until the modal disappears. This does not mutate work.
80
81
  *
81
82
  * A detector that wants to say something about the pane emits one of these via
@@ -122,17 +123,17 @@ export interface ProviderSessionEvent {
122
123
  replyToUserObligation?: boolean;
123
124
  /** Route captured with the submitted inbox turn; null means mirror only, undefined uses the runner cache. */
124
125
  replyRoute?: { to: string; replyToMessageId: number; channelTarget?: boolean; replyExpected?: boolean } | null;
125
- /** #2840 — the turn opener, already resolved by the runner (a hookless capture finishing after its idle
126
+ /** the turn opener, already resolved by the runner (a hookless capture finishing after its idle
126
127
  * edge); null = none. Absent ⇒ the runner resolves it from the final's turn id. */
127
128
  opener?: ProviderSessionEvent["replyRoute"];
128
129
  label?: string;
129
- /** Provider-independent tool-call category (#1498), adapter-resolved; only set when type is "tool". */
130
+ /** Provider-independent tool-call category, adapter-resolved; only set when type is "tool". */
130
131
  category?: ToolCallCategory;
131
- /** #3411 — absolute paths of the files a tool reads or edits, from its raw input (never `params`,
132
+ /** absolute paths of the files a tool reads or edits, from its raw input (never `params`,
132
133
  * which is capped); only set when type is "tool". The runner matches them to path areas. */
133
134
  paths?: string[];
134
135
  /**
135
- * Tool/step lifecycle status. `cancelled` (#2354) is the terminal outcome for a tool the
136
+ * Tool/step lifecycle status. `cancelled` is the terminal outcome for a tool the
136
137
  * provider interrupted before it finished (OpenCode's ToolPart error state with
137
138
  * `interrupted:true`), distinct from `failed` (ran and errored). Extended ONCE here for every
138
139
  * provider — see MessageSessionMeta.status.
@@ -144,16 +145,16 @@ export interface ProviderSessionEvent {
144
145
  * appending a duplicate (a tool's running→completed, a streamed reasoning row). */
145
146
  stepId?: string;
146
147
  /**
147
- * #2397 round 3 — true only for a narration ABOUT the adapter's own retry/failure mechanics
148
+ * round 3 — true only for a narration ABOUT the adapter's own retry/failure mechanics
148
149
  * (e.g. "retrying in 4s…", "gave up after N retries"), never for anything the model itself
149
150
  * produced. `noteOutput` (empty-turn.ts) excludes these from empty-turn evidence the same way it
150
151
  * already excludes an echoed `prompt`: a retry storm that ends in terminal failure must not read
151
- * as forward progress and cancel the #2389 input-armed escalation that wakes the spawn parent.
152
+ * as forward progress and cancel the input-armed escalation that wakes the spawn parent.
152
153
  * Distinct from `status: "failed"` on purpose — a failed TOOL call is still evidence the model is
153
154
  * alive and working; this is evidence only that the TRANSPORT is still failing.
154
155
  */
155
156
  diagnostic?: boolean;
156
- /** #2437 — redacted, size-capped tool input/arguments, only set when type is "tool". Carried
157
+ /** redacted, size-capped tool input/arguments, only set when type is "tool". Carried
157
158
  * straight into MessageSessionMeta.params by the adapter-event→session-meta conversion. */
158
159
  params?: unknown;
159
160
  }
@@ -185,7 +186,7 @@ export interface ProviderTokenUsageRecord {
185
186
  reasoningOutputTokens?: number;
186
187
  dedupeKey: string;
187
188
  createdAt: number;
188
- /** #3351 — the provider recorded usage without counts; buckets are zero and the ledger marks it unknown. */
189
+ /** the provider recorded usage without counts; buckets are zero and the ledger marks it unknown. */
189
190
  usageStatus?: "unknown";
190
191
  }
191
192
 
@@ -201,7 +202,7 @@ export interface ProviderTokenUsageReporter {
201
202
  export interface ProviderSessionTurnContext {
202
203
  turnId?: string;
203
204
  turnStartedAt?: number;
204
- /** #2840 — set only on a hookless capture after the idle edge: the opener snapshotted there. */
205
+ /** set only on a hookless capture after the idle edge: the opener snapshotted there. */
205
206
  opener?: ProviderSessionEvent["opener"];
206
207
  chatCaptureMode: ProviderConfig["chatCaptureMode"];
207
208
  reasoningCapture?: boolean;
@@ -211,7 +212,7 @@ export interface ProviderSessionTurnContext {
211
212
  pendingSessionEventCount(): number;
212
213
  log(message: string): void;
213
214
  debug(message: string): void;
214
- /** #2919 — set only on a turn-end capture: input the provider already accepted runs as the next turn
215
+ /** set only on a turn-end capture: input the provider already accepted runs as the next turn
215
216
  * with no busy edge of its own, so the runner keeps a turn open across this end. */
216
217
  noteQueuedTurn?(): void;
217
218
  }
@@ -257,12 +258,12 @@ export interface ProviderPermissionPromptHandler {
257
258
  buildView(id: string, body: Record<string, unknown>, reasoningSettled: boolean): InteractivePrompt;
258
259
  buildHookResponse(decision: ProviderPermissionDecisionInput, body: Record<string, unknown>): Record<string, unknown>;
259
260
  buildResolvedPrompt(view: InteractivePrompt, decision: ProviderPermissionDecisionInput, body: Record<string, unknown>, occurredAt: number): ProviderPermissionResolvedPrompt;
260
- // #1173: for prompt kinds whose PreToolUse hook is answered immediately (deny-then-hold —
261
+ // for prompt kinds whose PreToolUse hook is answered immediately (deny-then-hold —
261
262
  // see control-server.ts's AskUserQuestion branch) rather than held open for the decision,
262
263
  // this renders the eventual "answer" decision as the normal user-prompt text to inject back
263
264
  // into the session. Absent for prompt kinds that still ride the hook response directly.
264
265
  buildAnswerInjectionPrompt?(view: InteractivePrompt, decision: ProviderPermissionDecisionInput, body: Record<string, unknown>): string;
265
- // #2914: maps a "questions" prompt to a durable operator decision a coordinator files instead.
266
+ // maps a "questions" prompt to a durable operator decision a coordinator files instead.
266
267
  buildDecisionRequest?(body: Record<string, unknown>): OperatorDecisionFileInput | undefined;
267
268
  }
268
269
 
@@ -279,7 +280,7 @@ export interface ProviderConfig {
279
280
  // When false, the runner does not stream reasoning/tool steps into chat. Defaults
280
281
  // to enabled (steps render discreetly, never as chat bubbles).
281
282
  reasoningCapture?: boolean;
282
- // #2539 Phase A — how a provider WITH a mid-turn steer channel treats an ordinary message
283
+ // Phase A — how a provider WITH a mid-turn steer channel treats an ordinary message
283
284
  // offered while a turn is active. Optional everywhere: absent resolves through the OWNING
284
285
  // adapter's default (see resolveActiveTurnMessageDelivery in mid-turn-delivery.ts — adapters
285
286
  // with a mid-turn steer channel, codex and opencode/zai, default to steer; adapters without
@@ -292,7 +293,7 @@ export interface ProviderConfig {
292
293
  };
293
294
  }
294
295
 
295
- /** #2539 Phase A — the mid-turn delivery policy. `"steer"` folds an ordinary message offered
296
+ /** Phase A — the mid-turn delivery policy. `"steer"` folds an ordinary message offered
296
297
  * mid-turn into the in-flight turn; `"defer"` keeps queue-until-turn-end. */
297
298
  export type ActiveTurnMessageDelivery = "steer" | "defer";
298
299
 
@@ -305,12 +306,12 @@ export interface RunnerSpawnConfig {
305
306
  provider: string;
306
307
  model?: string;
307
308
  effort?: string;
308
- /** #2595 — effective-catalog context window from the spawn payload (incl. DB overrides);
309
+ /** effective-catalog context window from the spawn payload (incl. DB overrides);
309
310
  * adapters prefer it over their static manifest lookup. Absent ⇒ fall back to the manifest. */
310
311
  contextWindowTokens?: number;
311
- /** #2599 — the full server-resolved model record (protocol ≥ 2). Precedence over the manifest
312
+ /** the full server-resolved model record (protocol ≥ 2). Precedence over the manifest
312
313
  * for window / qualified name / descriptor / threshold; absent ⇒ manifest (or the legacy
313
- * #2595 `contextWindowTokens` above, which the adapter reads only when no record is present). */
314
+ * `contextWindowTokens` above, which the adapter reads only when no record is present). */
314
315
  modelRecord?: ResolvedModelRecord;
315
316
  runnerId: string;
316
317
  instanceId: string;
@@ -318,6 +319,8 @@ export interface RunnerSpawnConfig {
318
319
  relayUrl: string;
319
320
  /** Runner-owned live credential accessor for adapter accounting RPCs. */
320
321
  getRelayToken?: () => string | undefined;
322
+ /** Runner-local warning sink; published through the ordinary durable timeline audit. */
323
+ onLaunchWarning?: (event: import("./turn-reconcile-event").RunnerTimelineEvent) => void;
321
324
  cwd: string;
322
325
  headless: boolean;
323
326
  lifecycle?: "persistent" | "transient";
@@ -338,15 +341,15 @@ export interface RunnerSpawnConfig {
338
341
  hostClaudeSettings?: Record<string, unknown>;
339
342
  env: Record<string, string>;
340
343
  controlPort: number;
341
- // Stage 2 (#215): the MCP endpoint the agent connects to — the runner-local proxy URL when the
344
+ // Stage 2: the MCP endpoint the agent connects to — the runner-local proxy URL when the
342
345
  // proxy is active. Undefined → the adapter targets the relay's MCP endpoint directly (Stage 1).
343
346
  relayMcpEndpoint?: string;
344
- // #1450: the per-session proxy secret the agent authenticates to the runner-local proxy with (the
345
- // same value exported as AGENT_RELAY_SESSION_TOKEN). Set only when the proxy is active; the Codex
347
+ // the per-session proxy secret the agent authenticates to the runner-local proxy with (the
348
+ // same value exported as HUMWICK_SESSION_TOKEN). Set only when the proxy is active; the Codex
346
349
  // per-agent metaOnly callmux uses it to reach the relay endpoint on-demand THROUGH the proxy, so
347
350
  // identity rides the proxy's live-token injection and no relay token is ever written to disk.
348
351
  mcpProxySecret?: string;
349
- // #672: the shared host-listener URL the per-agent `callmux bridge` connects to, when the
352
+ // the shared host-listener URL the per-agent `callmux bridge` connects to, when the
350
353
  // profile/spawn opted into `agentProfile.sharedMcp`. Resolved runner-side (env → default);
351
354
  // the launch assembler only emits the bridge entry when sharedMcp is on.
352
355
  sharedMcpUrl?: string;
@@ -361,7 +364,7 @@ export interface SpawnArgs {
361
364
  args: string[];
362
365
  cwd: string;
363
366
  env: Record<string, string>;
364
- /** #2513 — env keys that must be explicitly UNSET in the launch environment (the tmux
367
+ /** env keys that must be explicitly UNSET in the launch environment (the tmux
365
368
  * launcher script exports only whitelisted keys but still inherits the tmux server's
366
369
  * env, so deleting from `env` alone cannot scrub an ambient credential). */
367
370
  envUnset?: string[];
@@ -380,11 +383,11 @@ export interface ManagedProcess {
380
383
  }
381
384
 
382
385
  /**
383
- * #1746 — the terminal verdict of a provider shutdown. `killed` means the provider
386
+ * the terminal verdict of a provider shutdown. `killed` means the provider
384
387
  * process (tmux pane / pid tree) is POSITIVELY confirmed gone; `failed-to-kill` means it
385
388
  * survived even a SIGKILL of its process group (near-impossible on a same-user Linux host,
386
389
  * so it is the operator-visible safety surface, not the happy path). The runner uses this
387
- * to gate deregistration: a roster removal must imply the process is dead (#1746 ask 2), so
390
+ * to gate deregistration: a roster removal must imply the process is dead, so
388
391
  * a `failed-to-kill` keeps the agent visible rather than turning it into a silent zombie.
389
392
  */
390
393
  export type ShutdownOutcome = "killed" | "failed-to-kill";
@@ -395,7 +398,7 @@ export interface TerminalAttachSpec {
395
398
  cwd: string;
396
399
  command: string[];
397
400
  /**
398
- * #2459 round 1 (review A) — REMOVED: a per-key env record let the guest credential ride
401
+ * round 1 (review A) — REMOVED: a per-key env record let the guest credential ride
399
402
  * the attach-spec HTTP response body and the orchestrator's process state. Credentials now
400
403
  * travel ONLY via {@link envFile}: the runner pre-stages a 0600 env file it owns and the
401
404
  * spec carries its PATH (never its contents); the orchestrator wraps the guest command in a
@@ -405,14 +408,14 @@ export interface TerminalAttachSpec {
405
408
  title?: string;
406
409
  ttlMs?: number;
407
410
  /**
408
- * #2459 — absolute path to a 0600 env file written by the runner (same host + user), for
411
+ * absolute path to a 0600 env file written by the runner (same host + user), for
409
412
  * the orchestrator's guest wrapper to source into the guest process environment. The path
410
413
  * is not a secret; the file contents never travel through the control server, the
411
414
  * orchestrator's memory/persistence, logs, or any argv.
412
415
  */
413
416
  envFile?: string;
414
417
  /**
415
- * #2459 — non-secret attachment generation, derived from the provider's ACTIVE session id
418
+ * non-secret attachment generation, derived from the provider's ACTIVE session id
416
419
  * (a one-way digest — never the session id itself, never a credential). The orchestrator
417
420
  * stores it with the guest tmux session and re-reads the runner's current generation before
418
421
  * terminal input and on stream connect/reconnect; a mismatch means clearContext()/retry
@@ -441,7 +444,7 @@ export interface ProviderPermissionDecisionReason {
441
444
  }
442
445
 
443
446
  // Fresh, per-turn context usage a transcript-backed adapter reads from its
444
- // session log (#1512). tokensUsed is the context-window token sum for the turn;
447
+ // session log. tokensUsed is the context-window token sum for the turn;
445
448
  // occurredAt is the wall-clock ms of the turn when the log stamps one.
446
449
  export interface ProviderContextUsage {
447
450
  tokensUsed: number;
@@ -452,7 +455,7 @@ export interface ProviderContextUsage {
452
455
  /**
453
456
  * Runner-owned live turn state is sampled when the adapter offers input.
454
457
  *
455
- * #2539 Phase B — the SAME context carries the deferred-settlement handoff for a mid-turn steer whose
458
+ * Phase B — the SAME context carries the deferred-settlement handoff for a mid-turn steer whose
456
459
  * acceptance is not yet consumption (OpenCode/zai noReply persist: the provider row exists, the model
457
460
  * reads it at a LATER step). The callbacks are runner-owned implementations of the ONE settlement seam —
458
461
  * `settleMidTurnConsumed` completes an awaiting id's settlement exactly like an immediate ack (mark read,
@@ -469,23 +472,23 @@ export interface ProviderInputObserver {
469
472
 
470
473
  export interface ProviderDeliverContext {
471
474
  inputObserver?: ProviderInputObserver;
472
- /** #2840 — for an adapter that runs one provider turn PER message: these messages open the next turn.
475
+ /** for an adapter that runs one provider turn PER message: these messages open the next turn.
473
476
  * Returns a disarm for when they open none (failed, refused). Absent call ⇒ the whole batch opens one. */
474
477
  openTurnFor?: (messages: Message[]) => () => void;
475
- /** #3415 — this offer's turn is opened by only these messages (a split batch); a no-op unless the offer armed an opener. Returns its disarm. */
478
+ /** this offer's turn is opened by only these messages (a split batch); a no-op unless the offer armed an opener. Returns its disarm. */
476
479
  narrowTurnOpener?: (messages: Message[]) => () => void;
477
480
  isRecipientMidTurn?: () => boolean;
478
481
  /** Text an adapter types as a provider user turn, so its prompt-hook echo is not mirrored as terminal input. */
479
482
  recordSubmittedPrompt?: (text: string, imagePaths?: readonly string[]) => void;
480
483
  /**
481
- * #2539 Phase B — positively CONSUMED ids for a batch previously reported through
484
+ * Phase B — positively CONSUMED ids for a batch previously reported through
482
485
  * {@link DeliverResult.awaitingConsumptionIds}. Fires once per id when the model has read the
483
486
  * persisted row (SSE parentID correlation or the bounded idle-wake settle). Absent callback ⇒
484
487
  * the adapter must hold the ids in its ledger (fail-safe: never silently settled).
485
488
  */
486
489
  settleMidTurnConsumed?: (relayIds: number[]) => void;
487
490
  /**
488
- * #2539 Phase B — ids to hand BACK to the normal queue (settled as undelivered, re-offered at
491
+ * Phase B — ids to hand BACK to the normal queue (settled as undelivered, re-offered at
489
492
  * the next boundary) because their persisted row can no longer be consumed where it lives.
490
493
  * Absent callback ⇒ hold in the ledger, same fail-safe as {@link settleMidTurnConsumed}.
491
494
  */
@@ -495,7 +498,7 @@ export interface ProviderDeliverContext {
495
498
  export interface DeliverResult {
496
499
  acknowledgedIds: number[];
497
500
  /**
498
- * #2539 Phase B — ids the adapter positively accepted for the in-flight turn (or holds in
501
+ * Phase B — ids the adapter positively accepted for the in-flight turn (or holds in
499
502
  * ambiguous custody after ONE timed-out POST whose bounded exact-id reconcile was inconclusive)
500
503
  * but whose CONSUMPTION has not happened yet, so their settlement completes LATER through
501
504
  * {@link ProviderDeliverContext.settleMidTurnConsumed} / {@link ProviderDeliverContext.reofferMidTurnIds}.
@@ -505,7 +508,7 @@ export interface DeliverResult {
505
508
  */
506
509
  awaitingConsumptionIds?: number[];
507
510
  /**
508
- * #2397 round 3 review (MED-3r) — ids the adapter positively knows failed a TERMINAL provider
511
+ * round 3 review (MED-3r) — ids the adapter positively knows failed a TERMINAL provider
509
512
  * error (e.g. OpenCode's retry+reroll budget exhausted against a rate-limited upstream), as
510
513
  * opposed to an ordinary un-acknowledged id (recipient mid-turn, transport busy). The runner
511
514
  * paces its re-drain of these with bounded exponential backoff instead of an immediate re-drain — without
@@ -514,7 +517,7 @@ export interface DeliverResult {
514
517
  */
515
518
  terminalFailureIds?: number[];
516
519
  /**
517
- * #2619 — ids the provider REFUSED under a rate-limit/quota hold (the turn ended in the shared
520
+ * ids the provider REFUSED under a rate-limit/quota hold (the turn ended in the shared
518
521
  * `blocked/rate_limit` hold, not a terminal failure). Not delivered and not failed: the runner
519
522
  * parks them (never re-drained into the wall, claims released so no Task completes) until a
520
523
  * provider turn goes through again, then redelivers them. Must be disjoint from `acknowledgedIds`.
@@ -523,7 +526,7 @@ export interface DeliverResult {
523
526
  }
524
527
 
525
528
  /**
526
- * #2534 — thrown by a synchronous-endpoint adapter (OpenCode/zai) when its outbound prompt was
529
+ * thrown by a synchronous-endpoint adapter (OpenCode/zai) when its outbound prompt was
527
530
  * positively ACCEPTED and persisted by the provider, but the turn's COMPLETION await itself
528
531
  * failed afterwards (transport drop, turn-timeout abort). The provider is already working on the
529
532
  * prompt, so the caller must NOT requeue it: a requeue would run the same assignment a second
@@ -543,8 +546,8 @@ export interface ProviderAdapter {
543
546
  statusSourceId?: string;
544
547
  stopObligationPath?: string;
545
548
  permissionPromptHandler?: ProviderPermissionPromptHandler;
546
- spawn(config: RunnerSpawnConfig): Promise<ManagedProcess>;
547
- // #1746 — resolves once the provider is terminal. Returns the outcome so the runner can
549
+ spawn(config: RunnerSpawnConfig, preparedArgs?: SpawnArgs): Promise<ManagedProcess>;
550
+ // resolves once the provider is terminal. Returns the outcome so the runner can
548
551
  // gate deregistration on confirmed death; `void` from a legacy adapter is treated as
549
552
  // `killed` (best-effort back-compat), but both first-party adapters now report explicitly.
550
553
  shutdown(process: ManagedProcess, opts: { graceful: boolean; timeoutMs: number }): Promise<ShutdownOutcome | void>;
@@ -555,51 +558,51 @@ export interface ProviderAdapter {
555
558
  compact?(process: ManagedProcess, opts?: { instructions?: string; signal?: AbortSignal; onSubmitted?: () => void }): Promise<Record<string, unknown> | void>;
556
559
  compactSupportsInstructions?: boolean;
557
560
  // Blind submits stamp onSubmitted and need a separate compacted/idle completion barrier.
558
- /** #3398 — the adapter emits its own `compacted` / `context-cleared` timelines; hook copies are not reset facts. */
561
+ /** the adapter emits its own `compacted` / `context-cleared` timelines; hook copies are not reset facts. */
559
562
  reportsContextResets?: boolean;
560
563
  compactReportsSubmission?: boolean;
561
564
  clearContext?(process: ManagedProcess): Promise<Record<string, unknown> | void>;
562
- // #2950 — change effort in place. Resolves with the confirmed `effort`, throws when the provider
565
+ // change effort in place. Resolves with the confirmed `effort`, throws when the provider
563
566
  // refused or never confirmed it. Only processes whose meta.effortSwitch is true may receive it.
564
567
  setEffort?(process: ManagedProcess, effort: string): Promise<{ effort: string } & Record<string, unknown>>;
565
- // #1588 — when true, the runner delivers a self-resume clear-inject continuation IN-PROCESS,
568
+ // when true, the runner delivers a self-resume clear-inject continuation IN-PROCESS,
566
569
  // coupled to the very same agent.clearContext command (deliverCoupledContinuationAfterClear),
567
570
  // rather than leaving it to the separate reactive agent.injectContext command, and only when
568
571
  // clearContext reports `clearConfirmed: true`. Set it when a separate inject could race the clear
569
- // (Claude tmux's async `/clear`, the #1588 silent mind-wipe) or land after a queued inbox message
572
+ // (Claude tmux's async `/clear`, the silent mind-wipe) or land after a queued inbox message
570
573
  // (headless Claude, whose clear resolves on its native conversation_reset boundary). Codex leaves
571
574
  // it unset: its awaited threadStart is the barrier and the separate inject (backstopped by the
572
- // server-side #1023 sweep) stays untouched.
575
+ // server-side sweep) stays untouched.
573
576
  couplesClearInjectContinuation?: boolean;
574
- // #2043 F1 — when true, this provider's `/compact` // `/clear` must be submitted to an IDLE
577
+ // F1 — when true, this provider's `/compact` // `/clear` must be submitted to an IDLE
575
578
  // provider: Claude tmux keystrokes typed mid-turn dequeue as literal chat, and headless Claude
576
579
  // queues stream-json input behind the live turn. The runner therefore gates the submit on the
577
580
  // live provider turn CLEARING first (waitForProviderTurnClear). Providers whose compact/clear is an
578
581
  // awaited app-server handshake (Codex) leave this unset — a plain turn-clear wait would time out
579
582
  // on their in-turn compaction. Those providers fence the PREDECESSOR turn a different way
580
- // instead — see interruptsTurnBeforeContextCommand below (#2569).
583
+ // instead — see interruptsTurnBeforeContextCommand below.
581
584
  awaitsIdleBeforeContextCommand?: boolean;
582
- // #2569 — when true, the runner must INTERRUPT and SETTLE the predecessor provider turn before
585
+ // when true, the runner must INTERRUPT and SETTLE the predecessor provider turn before
583
586
  // this provider's compact/clearContext runs. Set for app-server providers (Codex) whose
584
587
  // clearContext starts a FRESH thread (and whose compact rewrites the current one) via an awaited
585
588
  // handshake: the await confirms the NEW generation is ready but does NOT settle the OLD turn.
586
- // relay_compact_and_resume is called from within the model's own live turn, so that turn keeps
589
+ // humwick_compact_and_resume is called from within the model's own live turn, so that turn keeps
587
590
  // running on the previous thread while the successor generation is armed on the new one — two
588
- // generations then write the single worktree and revert each other (the #2569 silent overlap).
591
+ // generations then write the single worktree and revert each other.
589
592
  // A plain wait would time out on the still-live in-turn compaction (why blind-submit providers
590
593
  // can't share this path), so the fence actively interrupts the turn, then waits for it to reach
591
594
  // a terminal state (interrupt-then-settle, mirroring the redirect path) before the destructive
592
595
  // step. Adapters that fence internally (OpenCode's turnQueue) or have no interrupt leave this unset.
593
596
  interruptsTurnBeforeContextCommand?: boolean;
594
597
  // Derive the current context-window token usage from a transcript-backed
595
- // provider's session log (#1512). The runner calls this every heartbeat with the
598
+ // provider's session log. The runner calls this every heartbeat with the
596
599
  // latest transcript so context stats keep advancing per-turn even when a provider's
597
600
  // out-of-band probe (Claude's status-line command) goes silent after a
598
601
  // compact/clear/native-resume. Pure parse — no process state. Event-stream
599
602
  // providers (Codex) report context through `meta.getContext` instead and omit this.
600
603
  contextUsageFromTranscript?(jsonl: string): ProviderContextUsage | undefined;
601
604
  // Normalize the session so far into the provider-agnostic SessionEvent stream the
602
- // Insights context-ratio signal (#183/#184) reduces. Called by the runner's
605
+ // Insights context-ratio signal reduces. Called by the runner's
603
606
  // pre-session-destroy seam before any compact/clear/restart/shutdown. The runner owns
604
607
  // the per-segment cursor (it slices events since the last capture), so this returns the
605
608
  // full ordered event list for the current process lifetime. `ctx.transcriptPath` is
@@ -621,7 +624,7 @@ export interface ProviderAdapter {
621
624
  // Whether the adapter supports additive input into a running provider turn.
622
625
  supportsMidTurnSteer?: boolean;
623
626
  /**
624
- * #2539 Phase A — the shared mid-turn steer contract (Phase B: opencode/zai implement against
627
+ * Phase A — the shared mid-turn steer contract (Phase B: opencode/zai implement against
625
628
  * the same shape). Given a batch offered while the recipient is mid-turn, the adapter owns the
626
629
  * ONE eligibility decision: fold the steerable subset (ordinary persisted messages,
627
630
  * `partitionMidTurnDelivery`) into the in-flight turn and return/ack ONLY those ids;
@@ -633,7 +636,7 @@ export interface ProviderAdapter {
633
636
  * `supportsMidTurnSteer`; their `deliver` consults it at the paste instant, so the runner
634
637
  * keeps a single call path.
635
638
  *
636
- * #2539 Phase B (OpenCode/zai) — the acceptance/consumption split: the ack for this adapter
639
+ * Phase B (OpenCode/zai) — the acceptance/consumption split: the ack for this adapter
637
640
  * means POSITIVE PERSISTENCE (POST /session/:id/message with a caller messageID +
638
641
  * noReply:true — a user row the active loop consumes at its next step; live-proven on pinned
639
642
  * 1.18.21), not consumption, so persisted/ambiguous ids are returned as
@@ -650,21 +653,21 @@ export interface ProviderAdapter {
650
653
  // turn was interrupted from the web terminal so no Stop hook fired). "unknown"
651
654
  // means the provider can't be cheaply probed and the reconciler should defer.
652
655
  probeActivity?(process: ManagedProcess): Promise<"busy" | "idle" | "unknown">;
653
- // #769 P1-A: an independent "is the provider still visibly busy?" read, consulted by the
656
+ // P1-A: an independent "is the provider still visibly busy?" read, consulted by the
654
657
  // busy backstop — a probeActivity()=idle must not clear a live turn while this reads `busy`
655
658
  // (defense-in-depth when the primary probe can momentarily read idle mid-turn, e.g. a
656
- // connection retry). #1656: three-valued on purpose. Only `not-busy` is evidence the turn
659
+ // connection retry).: three-valued on purpose. Only `not-busy` is evidence the turn
657
660
  // ended; `no-session`/`unreadable` are unknown and must never authorize a clear.
658
661
  probePaneBusy?(process: ManagedProcess): Promise<PaneBusyReading>;
659
- // #1138: resolve a real OS pid for a busy provider-turn whose ManagedProcess carries
662
+ // resolve a real OS pid for a busy provider-turn whose ManagedProcess carries
660
663
  // none directly (e.g. Claude's tmux launch — process.pid is undefined, only a tmux
661
664
  // session/socket). The runner calls this as a fallback when a busy report supplies no
662
- // explicit pids, so the #650 liveness reconcile (and the stale-turn backstop) has real
665
+ // explicit pids, so the liveness reconcile (and the stale-turn backstop) has real
663
666
  // proof-of-life instead of only an elapsed-time heuristic. Returning undefined leaves
664
667
  // the runner's existing process.pid fallback (or no pid at all) unchanged.
665
668
  resolveBusyPid?(process: ManagedProcess): number | undefined;
666
669
  terminalAttachSpec?(process: ManagedProcess): Promise<TerminalAttachSpec>;
667
- // #2459 — the CURRENT non-secret attachment generation (see TerminalAttachSpec.generation).
670
+ // the CURRENT non-secret attachment generation (see TerminalAttachSpec.generation).
668
671
  // Read by the runner control server's GET /terminal/generation so the orchestrator can
669
672
  // detect a session rotation without ever learning the session id or any credential.
670
673
  // Absent ⇒ the provider's attach target cannot go stale (codex) and the endpoint reports
@@ -677,7 +680,7 @@ export interface ProviderAdapter {
677
680
  captureSubagentTokenUsage?(transcriptPath: string): Promise<void>;
678
681
  /**
679
682
  * Bounded final provider-native accounting pass before a session is torn down. `transcriptPath`
680
- * is `undefined` for a provider with no transcript file to tail (#2484 round 2 review MED-1 —
683
+ * is `undefined` for a provider with no transcript file to tail (round 2 review MED-1 —
681
684
  * OpenCode's capture is event-sourced, not file-tailed); the adapter owns whatever precondition
682
685
  * it needs (a transcript-tailing adapter bails itself on a missing path, an event-sourced one
683
686
  * ignores the argument entirely).
@@ -686,9 +689,9 @@ export interface ProviderAdapter {
686
689
  /** Start the provider-owned lifecycle observation for a prompt seeded in the launch command. */
687
690
  startLaunchSeededTurn?(process: ManagedProcess): Promise<void>;
688
691
  handleUserPrompt?(input: ProviderUserPromptInput, ctx: ProviderSessionTurnContext): Promise<void>;
689
- /** Whether a prompt the provider reports is one the runner submitted, through the provider's paste transport (#3081). */
692
+ /** Whether a prompt the provider reports is one the runner submitted, through the provider's paste transport. */
690
693
  matchesSubmittedPrompt?(providerPrompt: string, submitted: string, imagePaths?: readonly string[]): boolean;
691
- /** A session-start hook's stamped check-in (#2664): the provider's hook path works. */
694
+ /** A session-start hook's stamped check-in: the provider's hook path works. */
692
695
  handleHookCheck?(input: { firedAt?: number }, ctx: ProviderSessionTurnContext): void;
693
696
  /** File paths from a synchronous provider tool hook; absent means transcript delivery. */
694
697
  toolHookPaths?(input: unknown): string[] | undefined;
@@ -697,29 +700,29 @@ export interface ProviderAdapter {
697
700
  stopSessionTrace?(): void;
698
701
  publishPassiveTelemetry?(): Promise<void>;
699
702
  // `options.readyTimeoutMs` lets the runner widen the provider-ready wait for the
700
- // first (cold-start) delivery vs. a fast re-attempt after a ready signal (#329).
703
+ // first (cold-start) delivery vs. a fast re-attempt after a ready signal.
701
704
  // `options.isInitial` (default true) tells the adapter whether this delivery is the
702
705
  // agent's genuine first turn — the runner passes false from the dashboard
703
- // prompt-injection / continue paths (#1228) so a mid-session nudge isn't mislabeled
706
+ // prompt-injection / continue paths so a mid-session nudge isn't mislabeled
704
707
  // as the initial prompt.
705
- // Resolves "held" (#2619) when the provider REFUSED the prompt under a rate-limit/quota hold:
708
+ // Resolves "held" when the provider REFUSED the prompt under a rate-limit/quota hold:
706
709
  // not delivered, not failed — the runner parks it for redelivery (provider-hold.ts).
707
710
  deliverInitialPrompt?(process: ManagedProcess, prompt: string, options?: PromptOfferOptions): Promise<void | "held">;
708
711
  /** Confirm that a previously ambiguous input was consumed before the runner lifts its delivery hold. */
709
712
  confirmSubmitRecovery?(process: ManagedProcess, turnStarted: boolean): Promise<boolean>;
710
- /** The operator released the runner's submit hold (#2664): drop any adapter-side submit fence. */
713
+ /** The operator released the runner's submit hold: drop any adapter-side submit fence. */
711
714
  releaseSubmitHold?(process: ManagedProcess): void;
712
715
  // When true, the adapter seeds the spawn-time initial prompt as a launch argument
713
716
  // (Claude's positional `claude "<prompt>"`), so it's already delivered the instant the
714
717
  // session starts. The runner must then NOT also deliver it post-launch via
715
718
  // deliverInitialPrompt — that would double-deliver and re-introduce the send-keys
716
- // onboarding race (#352). deliverInitialPrompt stays available for mid-session injection
719
+ // onboarding race. deliverInitialPrompt stays available for mid-session injection
717
720
  // (dashboard chat box) and ongoing message delivery, which have no launch-arg equivalent.
718
721
  seedsInitialPromptAtLaunch?: boolean;
719
722
  /** Return accepted ids, plus consumption or failure outcomes when the transport reports them. */
720
723
  deliver(process: ManagedProcess, messages: Message[], ctx?: ProviderDeliverContext): Promise<void | number[] | DeliverResult>;
721
724
  onStatusChange(cb: (status: ProviderStatusUpdate) => void): void;
722
- // #1651 — subscribe to pane-derived DIAGNOSTICS. Separate from onStatusChange on purpose:
725
+ // subscribe to pane-derived DIAGNOSTICS. Separate from onStatusChange on purpose:
723
726
  // this channel's payload cannot carry a status, a clear, or a providerState, so wiring a
724
727
  // detector here is a structural guarantee that it cannot mutate runner state. Optional;
725
728
  // adapters with no pane to scrape simply never call it.
@@ -728,7 +731,7 @@ export interface ProviderAdapter {
728
731
  // shared idempotency for multiple trace steps discovered in one provider poll.
729
732
  onSessionEvent?(cb: (event: ProviderSessionEvent) => void): void;
730
733
  onSessionEvents?(cb: (events: ProviderSessionEventBatch) => void): void;
731
- // #2389 — "the model produced something in the current turn", for output an adapter can OBSERVE
734
+ // "the model produced something in the current turn", for output an adapter can OBSERVE
732
735
  // but cannot mirror. It exists because the runner has to tell a turn that did nothing at all from
733
736
  // one that finished work, and mirrored session events do not cover every provider: OpenCode's
734
737
  // wire carries tool parts whose internal shape we deliberately do not guess at, so they are
@@ -736,10 +739,10 @@ export interface ProviderAdapter {
736
739
  // — nothing is displayed, nothing is persisted. Optional; adapters whose output is fully mirrored
737
740
  // never need it.
738
741
  onTurnActivity?(cb: () => void): void;
739
- // §4.1 of the Runner↔provider contract (#725 / #746): fold the runner-tracked raw
742
+ // §4.1 of the Runner↔provider contract: fold the runner-tracked raw
740
743
  // transport/timeline/token/work-kind signals into ONE normalized LivenessSignal the
741
744
  // server reads instead of six raw `meta` fields. Each adapter owns what counts as
742
- // progress for its provider (Claude #713 timeline transitions; Codex #724 live
745
+ // progress for its provider (Claude timeline transitions; Codex live
743
746
  // subprocess work). Optional so test/mock adapters fall back to the shared
744
747
  // {@link computeLivenessSignal} fold — the runner always has a verdict to ship.
745
748
  liveness?(inputs: LivenessInputs): LivenessSignal;
@@ -756,7 +759,7 @@ export interface ProviderAdapter {
756
759
  buildSpawnArgs(config: RunnerSpawnConfig, providerConfig: ProviderConfig): SpawnArgs;
757
760
  }
758
761
 
759
- // #552 — the strictest base. Beyond the isolated provider home that every
762
+ // the strictest base. Beyond the isolated provider home that every
760
763
  // non-host base already gets (fresh CLAUDE_CONFIG_DIR / CODEX_HOME, which drops
761
764
  // the GLOBAL instruction + host MCP/hooks/plugins cascade), "vanilla" actively
762
765
  // suppresses every remaining host customization channel at launch, including the
@@ -771,7 +774,7 @@ export function relayContext(): string {
771
774
  return resolveRelayContext({ slug: "relay.context.codex" }).text;
772
775
  }
773
776
 
774
- // #306 — deliver the FULL message body by default. Only a pathological body beyond this
777
+ // deliver the FULL message body by default. Only a pathological body beyond this
775
778
  // high cap truncates (with a get-message hint) so it can't nuke an agent's context; the 99%
776
779
  // case (incl. multi-thousand-char handoffs/reports) arrives whole in one shot, no extra
777
780
  // round-trip. The mirror flow (user typing directly) already injects full text — this removes
@@ -789,7 +792,7 @@ export function providerMessageBodyMaxChars(): number {
789
792
  return DEFAULT_PROVIDER_MESSAGE_BODY_MAX_CHARS;
790
793
  }
791
794
 
792
- // #1935 — the Claude Code monitor surfaces each delivered event with a HARD cap on the content that
795
+ // the Claude Code monitor surfaces each delivered event with a HARD cap on the content that
793
796
  // reaches the agent's context; beyond it the harness truncates the event and spills the tail to an
794
797
  // output file the agent must re-read (paying for the message ~twice, both copies persisting in
795
798
  // context). Two independent bounds, measured 2026-08-02 against the live harness:
@@ -842,7 +845,7 @@ export interface DeliveredBodyPreview {
842
845
  guidance: string[];
843
846
  }
844
847
 
845
- // #1058 — one home for the delivered-body cap. Head-only truncation silently ate the TAIL, which is
848
+ // one home for the delivered-body cap. Head-only truncation silently ate the TAIL, which is
846
849
  // exactly where a report-up final puts its verdict / SHIP recommendation. Preserve BOTH ends: keep a
847
850
  // head slice for opening context and a tail slice for the conclusion, eliding the middle and pointing
848
851
  // at the untrimmed body. The tail is favored (it holds the verdict). Slices snap to whitespace so we
@@ -854,10 +857,10 @@ export function previewDeliveredBody(
854
857
  ): DeliveredBodyPreview {
855
858
  if (rawBody.length <= maxChars) return { body: rawBody, truncated: false, guidance: [] };
856
859
  const fetchLines = [
857
- `Read full: agent-relay get-message ${messageId}`,
858
- `Body only: agent-relay get-message ${messageId} --body`,
860
+ `Read full: humwick get-message ${messageId}`,
861
+ `Body only: humwick get-message ${messageId} --body`,
859
862
  ];
860
- const marker = (elided: number) => `[… ${elided} chars elided from the middle — full report: relay_get_message #${messageId} …]`;
863
+ const marker = (elided: number) => `[… ${elided} chars elided from the middle — full report: humwick_get_message #${messageId} …]`;
861
864
  // Reserve room for the marker and its two blank-line joins; upper-bound the marker length by using
862
865
  // the (always-larger) full body length so the reserved budget can never underflow the real marker.
863
866
  const budget = maxChars - marker(rawBody.length).length - 4;
@@ -900,8 +903,8 @@ function attachmentLabel(ref: Record<string, unknown>): string {
900
903
 
901
904
  function attachmentCacheMetadata(ref: Record<string, unknown>): Record<string, unknown> | undefined {
902
905
  const metadata = isRecord(ref.metadata) ? ref.metadata : undefined;
903
- const agentRelay = metadata && isRecord(metadata.agentRelay) ? metadata.agentRelay : undefined;
904
- return agentRelay;
906
+ const humwick = readHumwickRecord(metadata);
907
+ return humwick;
905
908
  }
906
909
 
907
910
  export function isMemoryInjection(message: Message): boolean {
@@ -921,7 +924,7 @@ export function isPersistedRelayMessage(message: Message): boolean {
921
924
  return Number.isSafeInteger(message.id) && message.id > 0;
922
925
  }
923
926
 
924
- // #283 — one-line nudge that replaces the reply-scaffold footer for notification-class
927
+ // one-line nudge that replaces the reply-scaffold footer for notification-class
925
928
  // (replyExpected:false) messages. Deliberately tiny so a bloated context can't drown the
926
929
  // no-reply rule established at session start. Shared with the Claude delivery path.
927
930
  export const NOTIFICATION_NUDGE = "↪ Notification — no reply needed.";
@@ -951,7 +954,7 @@ export function dedupePersistedMessages(messages: Message[]): Message[] {
951
954
  });
952
955
  }
953
956
 
954
- /** A human wrote it: a human address, or a prompt parked on a human's behalf (#3415). */
957
+ /** A human wrote it: a human address, or a prompt parked on a human's behalf. */
955
958
  export function isHumanSenderMessage(message: Message): boolean {
956
959
  return isHumanAgentId(heldForSender(message) ?? message.from);
957
960
  }
@@ -969,10 +972,10 @@ export function providerSenderLabel(message: Message): string {
969
972
  return isHumanChannel ? `human user via ${message.from}` : message.from;
970
973
  }
971
974
 
972
- /** `imagePaths`: cached attachment paths the prompt text lists (#2664). */
975
+ /** `imagePaths`: cached attachment paths the prompt text lists. */
973
976
  export interface PromptOfferOptions { readyTimeoutMs?: number; isInitial?: boolean; imagePaths?: string[]; inputObserver?: ProviderInputObserver }
974
977
 
975
- /** A parked prompt's attachment paths, carried on its inbox row so the redelivery keeps them (#2664). */
978
+ /** A parked prompt's attachment paths, carried on its inbox row so the redelivery keeps them. */
976
979
  export const HELD_PROMPT_IMAGE_PATHS = "heldPromptImagePaths";
977
980
 
978
981
  /** Local cache paths of the messages' attachments, as providerAttachmentText lists them. */
@@ -1013,11 +1016,11 @@ export function providerAttachmentText(message: Message): string | undefined {
1013
1016
  : hasLocalPaths
1014
1017
  ? [
1015
1018
  "Use the local path above when inspecting the attachment.",
1016
- `Read attachment details: agent-relay get-message ${message.id} --json`,
1019
+ `Read attachment details: humwick get-message ${message.id} --json`,
1017
1020
  ]
1018
1021
  : [
1019
- `Read attachment details: agent-relay get-message ${message.id} --json`,
1020
- `Fetch content: curl -fsS -H "X-Agent-Relay-Token: $AGENT_RELAY_TOKEN" "$AGENT_RELAY_URL/api/artifacts/<artifactId>/content" -o <filename>`,
1022
+ `Read attachment details: humwick get-message ${message.id} --json`,
1023
+ `Fetch content: curl -fsS -H "X-Humwick-Token: $HUMWICK_TOKEN" "$HUMWICK_URL/api/artifacts/<artifactId>/content" -o <filename>`,
1021
1024
  ];
1022
1025
  return [
1023
1026
  "Attachments:",
@@ -1042,7 +1045,7 @@ export function providerMessageText(messages: Message[]): string {
1042
1045
  : undefined;
1043
1046
  if (isMemoryContext) {
1044
1047
  return [
1045
- `[agent-relay ${isSelfResumeInjection(message) ? "self-resume continuation" : "context"} from ${message.from}]`,
1048
+ `[humwick ${isSelfResumeInjection(message) ? "self-resume continuation" : "context"} from ${message.from}]`,
1046
1049
  providerAttachmentText(message),
1047
1050
  `${subject}${preview.body}`,
1048
1051
  ].join("\n");