@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/liveness.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  import { PROVIDER_TURN_EMPTY_TIMELINE_STATUS, PROVIDER_TURN_WATCHDOG_TIMELINE_STATUS, RECONCILED_TURN_TIMELINE_STATUS } from "@humwick/sdk";
2
2
  import type { BusyPhase, LivenessSignal } from "@humwick/sdk";
3
3
 
4
- // #2010 — these timeline statuses are the runner ADMITTING it could not confirm progress (a
5
- // held-but-unproven turn), an end (a force-cleared one), or — #2389 — a turn that demonstrably
4
+ // these timeline statuses are the runner ADMITTING it could not confirm progress (a
5
+ // held-but-unproven turn), an end (a force-cleared one), or — a turn that demonstrably
6
6
  // produced NOTHING. Folding their `timestamp` in as
7
7
  // progress would be circular: the watchdog fires exactly when the runner has NO positive
8
8
  // evidence, yet its own publish (`timestamp: now`) would otherwise stamp that same status frame
9
9
  // as freshly-progressing, poisoning any consumer (e.g. the server's prolonged-hold coordinator
10
- // wake, #2010) that reads `lastProgressAt` off it. Every OTHER timeline transition (e.g. Claude's
10
+ // wake) that reads `lastProgressAt` off it. Every OTHER timeline transition (e.g. Claude's
11
11
  // `compacting`) is genuine forward progress and must keep counting.
12
- // #2389 belongs here most sharply of the three: an empty-turn event is the runner reporting the
12
+ // belongs here most sharply of the three: an empty-turn event is the runner reporting the
13
13
  // ABSENCE of output, so stamping its own publish as fresh progress would let the frame that says
14
14
  // "this agent did nothing" be read as evidence that it just did something.
15
15
  const NON_PROGRESS_TIMELINE_STATUSES: ReadonlySet<string> = new Set([
@@ -19,7 +19,7 @@ const NON_PROGRESS_TIMELINE_STATUSES: ReadonlySet<string> = new Set([
19
19
  ]);
20
20
 
21
21
  // The raw runner-tracked signals an adapter folds into a normalized LivenessSignal.
22
- // This is the INPUT to the contract computation (#746): the runner owns this state
22
+ // This is the INPUT to the contract computation: the runner owns this state
23
23
  // (transport frames, the last provider event, the pending timeline transition, the
24
24
  // active-work set), passes it to the adapter's `liveness()` verdict, and ships the
25
25
  // resulting LivenessSignal on the agent card. Provider-raw interpretation stops here —
@@ -36,12 +36,12 @@ export interface LivenessInputs {
36
36
  activeWork: Array<{ kind?: string; startedAt?: number }>;
37
37
  /** Fallback progress floor when no other progress evidence exists yet (e.g. work start). */
38
38
  fallbackProgressAt?: number;
39
- /** #1980 — the runner's coarse provider status (`claims.currentStatus()`), used together with
39
+ /** the runner's coarse provider status (`claims.currentStatus`), used together with
40
40
  * `providerBlocked` + `activeWork` to derive {@link LivenessSignal.busyPhase}. Provider-agnostic:
41
41
  * `busy` + a live provider-turn ⇒ `active` (the provider is doing turn work — including a
42
42
  * token-silent foreground `shell` gate), regardless of which provider. Omitted → no phase. */
43
43
  providerStatus?: "idle" | "busy" | "offline" | "error";
44
- /** #1980 — the runner's provider-hold flag (rate-limit / pendingQuestion / a `blocked`
44
+ /** the runner's provider-hold flag (rate-limit / pendingQuestion / a `blocked`
45
45
  * providerState, e.g. Claude `waiting`). When set, the phase is `blocked` — the provider is
46
46
  * parked, not actively computing — and takes precedence over `active`. */
47
47
  providerBlocked?: boolean;
@@ -52,7 +52,7 @@ function num(value: unknown): number {
52
52
  }
53
53
 
54
54
  /**
55
- * The shared liveness fold (#725 / #746). Both reference adapters (Claude #713, Codex #724)
55
+ * The shared liveness fold. Both reference adapters
56
56
  * route through this so the verdict is computed in ONE place; each adapter's `liveness()`
57
57
  * decides WHICH raw signals it feeds in (Claude surfaces a `compacting` timeline transition
58
58
  * as progress; Codex surfaces live subprocess work-kinds). The fold itself is provider-
@@ -63,8 +63,8 @@ export function computeLivenessSignal(inputs: LivenessInputs): LivenessSignal {
63
63
  num(inputs.transport?.lastServerFrameAt),
64
64
  num(inputs.transport?.lastHeartbeatAckAt),
65
65
  );
66
- // Progress = provider tokens OR a lifecycle/timeline transition (e.g. native compaction,
67
- // #713) — whichever is latest, with the caller-supplied floor as the baseline. #2010: a
66
+ // Progress = provider tokens OR a lifecycle/timeline transition (e.g. native compaction)
67
+ // — whichever is latest, with the caller-supplied floor as the baseline. A
68
68
  // timeline event that is itself an admission of no-confirmed-progress (the prolonged-hold
69
69
  // watchdog, or a reconciled/force-cleared turn) must NOT count as progress — see
70
70
  // NON_PROGRESS_TIMELINE_STATUSES above.
@@ -77,7 +77,7 @@ export function computeLivenessSignal(inputs: LivenessInputs): LivenessSignal {
77
77
  timelineProgressAt,
78
78
  num(inputs.fallbackProgressAt),
79
79
  );
80
- // Any work-kind that is NOT the bare provider turn is live tool/subprocess work (#724):
80
+ // Any work-kind that is NOT the bare provider turn is live tool/subprocess work:
81
81
  // a wedged provider turn with a live `bun test` child must read as progressing.
82
82
  const hasLiveWork = inputs.activeWork.some((work) => Boolean(work.kind && work.kind !== "provider-turn"));
83
83
  const busyPhase = deriveBusyPhase(inputs, hasLiveWork);
@@ -85,15 +85,15 @@ export function computeLivenessSignal(inputs: LivenessInputs): LivenessSignal {
85
85
  }
86
86
 
87
87
  /**
88
- * #1980 / #1069 — derive the coarse {@link BusyPhase} from the runner's own state. Provider-
89
- * agnostic by construction (the point of the #746 contract): a live `provider-turn` while the
88
+ * derive the coarse {@link BusyPhase} from the runner's own state. Provider-
89
+ * agnostic by construction (the point of the contract): a live `provider-turn` while the
90
90
  * runner status is `busy` is `active` for EVERY provider — for Claude that already covers both
91
91
  * `busy` (thinking) and `shell` (a foreground gate), and for Codex it covers `inProgress`,
92
92
  * because the adapter mints/holds the `provider-turn` work-kind for exactly those states. A
93
93
  * provider hold (`providerBlocked`) is `blocked` and wins over `active` (a parked turn is not
94
- * computing). Otherwise, live background-script work with no active turn is `passive` (#1856).
94
+ * computing). Otherwise, live background-script work with no active turn is `passive`.
95
95
  * `hasLiveWork` stays the narrower "is there background-script work" projection so its existing
96
- * stuck-busy veto (#724, a live `bun test` child during an active turn) is unchanged; `passive`
96
+ * stuck-busy veto (a live `bun test` child during an active turn) is unchanged; `passive`
97
97
  * always implies `hasLiveWork`, but `active` deliberately does not.
98
98
  */
99
99
  function deriveBusyPhase(inputs: LivenessInputs, hasLiveWork: boolean): BusyPhase | undefined {
package/src/logger.ts CHANGED
@@ -4,7 +4,7 @@ import { sanitizeFsName } from "@humwick/sdk/fs-name";
4
4
  import { logDirFromEnv, logLevelFromEnv } from "./config";
5
5
  import { appendBoundedLog, RUNNER_LOG_MAX_BYTES, RUNNER_LOG_RECORD_MAX_BYTES } from "./bounded-log";
6
6
 
7
- // Phase 1 observability (#198): one leveled, runtime-togglable logger for the
7
+ // Phase 1 observability: one leveled, runtime-togglable logger for the
8
8
  // Runner and the provider adapters below it. Replaces the ad-hoc scatter of
9
9
  // `console.error`, `logRunnerDiagnostic` (-> runner-<agent>.log) and
10
10
  // `sessionLog`/`sessionDebug` (-> session-mirror-<agent>.log) with a single
@@ -14,7 +14,7 @@ import { appendBoundedLog, RUNNER_LOG_MAX_BYTES, RUNNER_LOG_RECORD_MAX_BYTES } f
14
14
  // already surfaces to the dashboard log-viewer (captureSessionMirror). One place
15
15
  // to look when anything in the Runner misbehaves.
16
16
  //
17
- // Level is read once from AGENT_RELAY_LOG_LEVEL (default "info") and can be
17
+ // Level is read once from HUMWICK_LOG_LEVEL (default "info") and can be
18
18
  // flipped at runtime via the control port (no restart) — so a phase refactor can
19
19
  // be watched at debug without bouncing the agent.
20
20
 
@@ -55,7 +55,7 @@ export class Logger {
55
55
  this.level = config.level ?? parseLogLevel(logLevelFromEnv()) ?? "info";
56
56
  this.agentId = config.agentId ?? "runner";
57
57
  this.headless = config.headless ?? false;
58
- this.logDir = config.logDir ?? logDirFromEnv() ?? join(process.env.HOME || ".", ".agent-relay", "logs");
58
+ this.logDir = config.logDir ?? logDirFromEnv() ?? join(process.env.HOME || ".", ".humwick", "logs");
59
59
  this.logFileMaxBytes = config.logFileMaxBytes ?? RUNNER_LOG_MAX_BYTES;
60
60
  }
61
61
 
package/src/mcp-outbox.ts CHANGED
@@ -108,7 +108,7 @@ async function deliverSessionBatchItems(input: RunnerOutboxDelivery, messages: S
108
108
  }
109
109
 
110
110
  // Deterministic session validation rejections are classified once in runner-helpers.ts
111
- // (isDeterministicClientError) and shared with the outbox poison policy (#2433).
111
+ // (isDeterministicClientError) and shared with the outbox poison policy.
112
112
 
113
113
  function sessionBatchItemKeys(record: OutboxRecord): string[] {
114
114
  const messages = sessionBatchMessages(record);
@@ -122,7 +122,7 @@ function sessionBatchMessages(record: OutboxRecord): SendMessageInput[] {
122
122
  }
123
123
 
124
124
  // The subset of RunnerOutboxDelivery the notice seam needs — also satisfied by the narrower
125
- // Outbox.onPoison call site (#2433), which only holds the poisoned record + the HTTP client.
125
+ // Outbox.onPoison call site, which only holds the poisoned record + the HTTP client.
126
126
  type MirrorDropNoticeSource = Pick<RunnerOutboxDelivery, "record"> & { http: HumwickHttpClient };
127
127
 
128
128
  async function emitMirrorDropNotice(input: MirrorDropNoticeSource, messages: SendMessageInput[], count: number, reason: string, suffix: string): Promise<void> {
@@ -158,7 +158,7 @@ function shortHash(value: string): string {
158
158
  return (h >>> 0).toString(36);
159
159
  }
160
160
 
161
- // #2433 — the Outbox.onPoison seam for SESSION rows. A permanently-dropped session-message /
161
+ // the Outbox.onPoison seam for SESSION rows. A permanently-dropped session-message /
162
162
  // batch is REAL report-up/mirror loss (chat replyTo lineage rides the session outbox), so
163
163
  // surface it in-session through the same notice channel as duplicate/invalid drops instead
164
164
  // of only in a FATAL host log. Non-session kinds carry no chat lineage to notify about.
@@ -3,7 +3,7 @@ import { hostname } from "node:os";
3
3
  import { basename, isAbsolute } from "node:path";
4
4
  import { PORTABLE_SHARED_MCP_SERVER_NAMES, activeSharedMcpServers, portableMcpDescriptorPath, type PortableMcpDescriptor, type ProvisioningMcpServer } from "@humwick/sdk";
5
5
 
6
- // #2729 — a registry descriptor is authored on one host (e.g. the hub's `~/.npm-global/bin/<server>`)
6
+ // a registry descriptor is authored on one host (e.g. the hub's `~/.npm-global/bin/<server>`)
7
7
  // but launched on any. A stdio command that does not exist on THIS host would reach the agent as a
8
8
  // broken server ("MCP server failed to start (ENOENT)"). A core shared server (tokenlean/...) is
9
9
  // swapped for the descriptor this host's orchestrator provisioned (same binary + URL the shared
@@ -35,7 +35,7 @@ export interface McpPreflightOptions {
35
35
  sharedListener: boolean;
36
36
  /** Names exempt from the check (their command is provisioned after launch resolution). */
37
37
  skip?: readonly string[];
38
- /** AGENT_RELAY_HOME of this host, where the orchestrator records provisioned core descriptors. */
38
+ /** HUMWICK_HOME of this host, where the orchestrator records provisioned core descriptors. */
39
39
  home?: string;
40
40
  }
41
41
 
@@ -22,7 +22,7 @@ export interface McpSourceSelection {
22
22
  sourceShadows: ResolvedSourceShadow[];
23
23
  }
24
24
 
25
- // #2368 — providers load their native host declarations, then share this precedence policy.
25
+ // providers load their native host declarations, then share this precedence policy.
26
26
  // Serialization, service-access overlays and tool deferral consume the selected sources.
27
27
  export function resolveMcpSources(
28
28
  config: RunnerSpawnConfig,
@@ -39,7 +39,7 @@ export function resolveMcpSources(
39
39
  );
40
40
  const projectServers = Object.keys(projectMcp);
41
41
 
42
- // #2114 — sharedMcp is a resolved sibling opt-in, independent of ambient H.mcp.
42
+ // sharedMcp is a resolved sibling opt-in, independent of ambient H.mcp.
43
43
  const sharedListenerUrl = config.agentProfile?.sharedMcp ? resolveSharedMcpUrl(config.sharedMcpUrl) : undefined;
44
44
  const sharedMcp: Record<string, ProvisioningMcpServer> = sharedListenerUrl
45
45
  ? { [SHARED_MCP_SERVER_NAME]: sharedMcpBridgeServer(sharedListenerUrl, config.cwd) }
@@ -28,7 +28,7 @@ export function runnerManagedRelayOnDemandTools(
28
28
  || !isCodexLeanWorkerProfile(profile?.name)
29
29
  || !profile?.sharedMcp
30
30
  || profile.relay?.mcp === false
31
- // #3024 — a switched-off web tool keeps the flat bridge (launch-assembly), so nothing fronts this set.
31
+ // a switched-off web tool keeps the flat bridge (launch-assembly), so nothing fronts this set.
32
32
  || WEB_TOOL_NAMES.some((name) => !profileWebToolEnabled(profile, name))
33
33
  ) return undefined;
34
34
  return new Set(CODEX_WORKER_ONDEMAND_TOOLS);
@@ -4,11 +4,11 @@ import { shellQuote } from "@humwick/sdk/shell-utils";
4
4
 
5
5
  /** Codex has env_vars inheritance but no Claude-style interpolation in stdio env. */
6
6
  export function codexVaultMcpEnv(server: ProvisioningMcpServer): ProvisioningMcpServer {
7
- const env = writeChildEnv({}, { ...server.env });
7
+ const env = writeChildEnv({}, { ...server.env }, []);
8
8
  const assignments: string[] = [];
9
9
  const slots = new Set<string>();
10
10
  for (const [key, value] of Object.entries(env)) {
11
- const match = /^\$\{(AGENT_RELAY_VAULT_[A-F0-9]{24})\}$/.exec(value);
11
+ const match = /^\$\{(HUMWICK_VAULT_[A-F0-9]{24})\}$/.exec(value);
12
12
  if (!match) continue;
13
13
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key) || !server.command) throw new Error("Invalid vault MCP environment projection");
14
14
  assignments.push(`export ${key}="\${${match[1]}:?}"`);
@@ -1,16 +1,16 @@
1
1
  import { relayEnv } from "@humwick/sdk/env";
2
2
  export function messageBodyMaxCharsFromEnv(): string | undefined {
3
- return relayEnv(process.env, "AGENT_RELAY_MESSAGE_BODY_MAX_CHARS");
3
+ return relayEnv(process.env, "HUMWICK_MESSAGE_BODY_MAX_CHARS");
4
4
  }
5
5
 
6
- // #1935 — the Claude Code monitor delivery caps (empirically measured against the live harness on
6
+ // the Claude Code monitor delivery caps (empirically measured against the live harness on
7
7
  // 2026-08-02: ~3000 chars per delivered event, ~500 chars per line). Overridable per deployment,
8
8
  // since the right ceiling tracks the host's harness build — set on the host/orchestrator that
9
9
  // spawns runners. See DEFAULT_MONITOR_DELIVERY_* in adapter.ts for the resolved defaults.
10
10
  export function monitorDeliveryMaxCharsFromEnv(): string | undefined {
11
- return relayEnv(process.env, "AGENT_RELAY_MONITOR_DELIVERY_MAX_CHARS");
11
+ return relayEnv(process.env, "HUMWICK_MONITOR_DELIVERY_MAX_CHARS");
12
12
  }
13
13
 
14
14
  export function monitorDeliveryLineMaxCharsFromEnv(): string | undefined {
15
- return relayEnv(process.env, "AGENT_RELAY_MONITOR_DELIVERY_LINE_MAX_CHARS");
15
+ return relayEnv(process.env, "HUMWICK_MONITOR_DELIVERY_LINE_MAX_CHARS");
16
16
  }
@@ -1,4 +1,4 @@
1
- // #2539 Phase A — the shared soft-steer foundation.
1
+ // Phase A — the shared soft-steer foundation.
2
2
  //
3
3
  // One adapter-owned eligibility decision (`partitionMidTurnDelivery`), one config seam
4
4
  // (`resolveActiveTurnMessageDelivery`) and one acceptance-correlation id (`midTurnClientUserId`),
@@ -32,7 +32,7 @@ function isSteerableMidTurnMessage(message: Message): boolean {
32
32
  }
33
33
 
34
34
  /**
35
- * Stable acceptance-correlation id for one steered composition (#2539 design C). Derived from
35
+ * Stable acceptance-correlation id for one steered composition. Derived from
36
36
  * the ordered batch ids, so a re-offer of the SAME subset reuses the id: the app-server echoes
37
37
  * it back as the `userMessage.clientId` item field, and an echo observed after a lost steer
38
38
  * response lets the next offer settle by correlation instead of re-steering (which would
@@ -1,5 +1,5 @@
1
1
  import { writeChildEnv } from "@humwick/sdk/env";
2
- // #1565 P5.7 (design §10.3) — the provider-NATIVE-memory lever.
2
+ // P5.7 (design §10.3) — the provider-NATIVE-memory lever.
3
3
  //
4
4
  // WHAT THIS IS FOR. Every agent today can carry two competing memory stores: relay memory (which
5
5
  // survives a respawn) and the provider's own (which, for 8 of 11 built-in profiles, is destroyed
@@ -27,7 +27,7 @@ import { writeChildEnv } from "@humwick/sdk/env";
27
27
  //
28
28
  // NEVER THROWS. Resolution is total: any unexpected input degrades to "nothing applied, reported
29
29
  // as suppressed" rather than propagating. A failure to apply this lever must not fail a spawn
30
- // (the #1612 discipline, applied to the switch instead of the preamble) — an agent that launches
30
+ // (the discipline, applied to the switch instead of the preamble) — an agent that launches
31
31
  // with its native memory still on is a two-store agent, which is exactly today's state; an agent
32
32
  // that fails to launch is an outage.
33
33
 
@@ -63,7 +63,7 @@ export interface NativeMemoryLever {
63
63
  /** The levers that actually reach this launch, as short stable ids for the projection report. */
64
64
  applied: string[];
65
65
  /** Levers that were resolved but could NOT be delivered on this base/provider. Reported LOUDLY
66
- * (the `hooksSuppressed` precedent, #1096) so a lever is never silently absent while the
66
+ * so a lever is never silently absent while the
67
67
  * report claims it applied. */
68
68
  suppressed?: { reason: string; levers: string[] };
69
69
  }
@@ -107,7 +107,7 @@ function resolveClaudeLever(
107
107
  // The env var is unconditional and authoritative — it works on EVERY base, host included, and
108
108
  // outranks the settings read inside the CLI's own predicate.
109
109
  const disable = policy === "off";
110
- const env = writeChildEnv({}, { [CLAUDE_DISABLE_AUTO_MEMORY_ENV]: disable ? "1" : "0" });
110
+ const env = writeChildEnv({}, { [CLAUDE_DISABLE_AUTO_MEMORY_ENV]: disable ? "1" : "0" }, []);
111
111
  const applied = [`env:${CLAUDE_DISABLE_AUTO_MEMORY_ENV}=${disable ? "1" : "0"}`];
112
112
 
113
113
  const settings: Record<string, unknown> = { [CLAUDE_AUTO_MEMORY_ENABLED_SETTING]: !disable };
@@ -179,7 +179,7 @@ type NativeMemoryLeverRenderer = (
179
179
  input: ResolveNativeMemoryLeverInput,
180
180
  ) => NativeMemoryLever;
181
181
 
182
- // #2513 — the claude renderer is shared by every claude-family provider id (claude-b reuses
182
+ // the claude renderer is shared by every claude-family provider id (claude-b reuses
183
183
  // the claude adapter/launch path whole), so the absent⇒off invariant holds for it too.
184
184
  const claudeLeverRenderer: NativeMemoryLeverRenderer = (policy, input) => resolveClaudeLever(
185
185
  policy,
@@ -238,7 +238,7 @@ export function resolveNativeMemoryLever(input: ResolveNativeMemoryLeverInput):
238
238
  suppressed: { reason: `provider ${input.provider} has no known native-memory lever; nothing was applied`, levers: ["nativeMemory"] },
239
239
  };
240
240
  } catch (err) {
241
- // The fail-safe (#1612's discipline applied to the switch). A lever we could not compute must
241
+ // The fail-safe (discipline applied to the switch). A lever we could not compute must
242
242
  // degrade to "not applied, loudly reported" — never to a failed spawn.
243
243
  return {
244
244
  ...none(),
@@ -293,7 +293,7 @@ export function claudeManagedNativeMemorySettings(
293
293
  }
294
294
 
295
295
  /**
296
- * The fail-safe at the APPLY seam (#1612's discipline, moved from the preamble to the switch). The
296
+ * The fail-safe at the APPLY seam (discipline, moved from the preamble to the switch). The
297
297
  * file-channel belt is best-effort by construction: the authoritative lever is the env var / `-c`
298
298
  * arg, computed into the launch and touching no disk, so a failed belt write costs nothing an
299
299
  * operator can observe — while a THROW here would fail the whole spawn. So: never propagate, and
@@ -305,7 +305,7 @@ export function applyNativeMemoryBelt(label: string, apply: () => void): string
305
305
  return undefined;
306
306
  } catch (err) {
307
307
  const reason = `native-memory lever: ${label} could not be written: ${(err as Error)?.message ?? String(err)}. `
308
- + "The authoritative env/argv lever still applies (it outranks the file channel), and the spawn continues — design #1565 §10.3.";
308
+ + "The authoritative env/argv lever still applies (it outranks the file channel), and the spawn continues — design §10.3.";
309
309
  console.warn(reason);
310
310
  return reason;
311
311
  }
package/src/outbox.ts CHANGED
@@ -8,7 +8,7 @@ import { logger } from "./logger";
8
8
  import { runnerOutboxDirFromEnv } from "./config";
9
9
  import { isDeterministicClientError, isTransientDeliveryError } from "./runner-helpers";
10
10
 
11
- // Phase 2 (#196) — the "nothing is ever lost" half. Runner→server events that used to be
11
+ // Phase 2 — the "nothing is ever lost" half. Runner→server events that used to be
12
12
  // fire-and-forget over HTTP (session turns, reasoning/tool traces, prompt echoes, insights,
13
13
  // hook-fatal reports) were silently dropped whenever the server was momentarily down. This
14
14
  // is a durable, FIFO, disk-backed queue that:
@@ -18,7 +18,7 @@ import { isDeterministicClientError, isTransientDeliveryError } from "./runner-h
18
18
  // reorder turns),
19
19
  // - poisons a DETERMINISTICALLY-failing head immediately and an unknown-failure head after
20
20
  // maxAttempts so it can't block the queue — but NEVER poisons on attempt count for
21
- // TRANSIENT (connection-class / 5xx / 429) failures (#2433): report-up chat rides this
21
+ // TRANSIENT (connection-class / 5xx / 429) failures: report-up chat rides this
22
22
  // queue, so a poisoned row is real message loss. A transient head instead parks onto a
23
23
  // slow periodic re-drive after a long CONTINUOUS-failure wall-clock budget, so an ordinary
24
24
  // relay-restart window can't drop anything no matter how hard flush() hammers,
@@ -58,14 +58,14 @@ type OutboxSend = (record: OutboxRecord) => Promise<void>;
58
58
  interface OutboxOptions {
59
59
  agentId: string;
60
60
  send: OutboxSend;
61
- // Storage directory. Defaults to AGENT_RELAY_RUNNER_OUTBOX_DIR, else a per-host temp dir.
61
+ // Storage directory. Defaults to HUMWICK_RUNNER_OUTBOX_DIR, else a per-host temp dir.
62
62
  dir?: string;
63
63
  maxRows?: number;
64
64
  maxAttempts?: number;
65
65
  baseBackoffMs?: number;
66
66
  maxBackoffMs?: number;
67
67
  pollMs?: number;
68
- // #2433 — transient (connection-class / 5xx / 429) failures NEVER poison on attempt count.
68
+ // transient (connection-class / 5xx / 429) failures NEVER poison on attempt count.
69
69
  // After this much CONTINUOUS wall-clock failure on a row, park it onto a slow periodic
70
70
  // re-drive (every transientRedriveMs) instead of hot-looping, so a long relay outage still
71
71
  // recovers every frame once the relay returns. Sized to outlast any ordinary restart/deploy
@@ -75,7 +75,7 @@ interface OutboxOptions {
75
75
  // Observability seam: called when a row is actually POISONED (permanently dropped). Only
76
76
  // deterministic client rejections and unknown-class failures past maxAttempts get here —
77
77
  // never transient ones. The session outbox uses it to surface mirror/report-up loss
78
- // in-session (#2433) rather than only in a FATAL host log.
78
+ // in-session rather than only in a FATAL host log.
79
79
  onPoison?: (record: OutboxRecord, reason: string) => void | Promise<void>;
80
80
  }
81
81
 
@@ -142,7 +142,7 @@ export class Outbox {
142
142
  this.transientRedriveMs = options.transientRedriveMs ?? DEFAULTS.transientRedriveMs;
143
143
  this.onPoison = options.onPoison;
144
144
 
145
- const dir = options.dir ?? runnerOutboxDirFromEnv() ?? join(tmpdir(), "agent-relay-outbox");
145
+ const dir = options.dir ?? runnerOutboxDirFromEnv() ?? join(tmpdir(), "humwick-outbox");
146
146
  this.path = options.dir === ":memory:" ? ":memory:" : join(dir, `outbox-${safeName(this.agentId)}.sqlite`);
147
147
  if (this.path !== ":memory:") mkdirSync(dirname(this.path), { recursive: true });
148
148
 
@@ -165,7 +165,7 @@ export class Outbox {
165
165
  created_at INTEGER NOT NULL
166
166
  )
167
167
  `);
168
- // Pre-#2433 databases lack the transient-park bookkeeping column (fresh CREATEs include it).
168
+ // Previous databases lack the transient-park bookkeeping column (fresh CREATEs include it).
169
169
  const columns = this.db.query("PRAGMA table_info(outbox)").all() as Array<{ name: string }>;
170
170
  if (!columns.some((column) => column.name === "first_failed_at")) {
171
171
  this.db.exec("ALTER TABLE outbox ADD COLUMN first_failed_at INTEGER NOT NULL DEFAULT 0");
@@ -229,13 +229,13 @@ export class Outbox {
229
229
  this.pollTimer.unref?.();
230
230
  }
231
231
 
232
- // (#1617) — the ONE way a background caller starts a drain. `drain()` is a bare try/finally with
232
+ // the ONE way a background caller starts a drain. `drain` is a bare try/finally with
233
233
  // no catch, and drainOnce() touches SQLite outside the send() try/catch (the head SELECT, and the
234
234
  // attempt/poison UPDATEs in the failure path), so a closed or erroring database rejects it. Every
235
235
  // pump site is fire-and-forget — an enqueue microtask, start()'s initial pump and poll timer, the
236
236
  // scheduleDue wake-up — with nobody to await the promise, and Bun exits(1) on an unhandled
237
- // rejection with no handler installed anywhere in the runner (#1614). That crashed the whole
238
- // agent over a queue error, on a runner nothing respawns (#1618).
237
+ // rejection with no handler installed anywhere in the runner. That crashed the whole
238
+ // agent over a queue error, on a runner nothing respawns.
239
239
  //
240
240
  // Reported through this module's own existing channel (logger, same as the bound-exceeded warn
241
241
  // and the poison fatal) rather than swallowed: a pump that stops pumping is its own bug, and
@@ -248,13 +248,13 @@ export class Outbox {
248
248
  }
249
249
 
250
250
  // Drain everything we can before the process exits, ignoring per-row backoff. Used on
251
- // shutdown/kill/crash (#183): the capture seam durably enqueues the end-of-session
251
+ // shutdown/kill/crash: the capture seam durably enqueues the end-of-session
252
252
  // Insights datapoint, but the per-agent outbox is never reopened once the agent is gone,
253
253
  // so a row that hasn't been POSTed yet is stranded forever. flush() blocks (bounded) on
254
254
  // delivery — the opposite intent of the polite, backoff-respecting steady-state drain.
255
255
  // Returns true if the queue fully drained within the deadline.
256
256
  //
257
- // #2433: the forced 150ms retry loop here used to consume the per-row attempt/poison
257
+ // the forced 150ms retry loop here used to consume the per-row attempt/poison
258
258
  // budget, so <2s of relay downtime at a flush boundary poisoned frames. Force-drain
259
259
  // failures no longer burn the TRANSIENT poison budget (see drainOnce) — flush() can
260
260
  // hammer as hard as it likes during an outage without ever pushing a row toward poison.
@@ -314,7 +314,7 @@ export class Outbox {
314
314
  const reason = errMessage(error);
315
315
  const transient = isTransientDeliveryError(error);
316
316
  const deterministic = !transient && isDeterministicClientError(error);
317
- // #2433: flush()'s forced loop hammers every 150ms while ignoring backoff; letting
317
+ // flush's forced loop hammers every 150ms while ignoring backoff; letting
318
318
  // those passes consume the TRANSIENT attempt budget is what let a <2s relay restart
319
319
  // window poison frames at a flush boundary. Forced drains of transient failures
320
320
  // therefore burn NO attempt budget — classification still applies, counting does
@@ -328,7 +328,7 @@ export class Outbox {
328
328
  }
329
329
 
330
330
  if (transient) {
331
- // Never poisoned on attempt count (#2433): retry under backoff until either the
331
+ // Never poisoned on attempt count: retry under backoff until either the
332
332
  // relay returns (the row delivers) or the CONTINUOUS-failure wall-clock budget
333
333
  // runs out and the row parks onto a slow periodic re-drive cadence.
334
334
  const firstFailedAt = row.first_failed_at > 0 ? row.first_failed_at : now;
@@ -369,7 +369,7 @@ export class Outbox {
369
369
  }
370
370
 
371
371
  // Permanently drop a row. Only reachable for deterministic client rejections (immediately)
372
- // or unknown-class failures past maxAttempts — NEVER for transient ones (#2433). The
372
+ // or unknown-class failures past maxAttempts — NEVER for transient ones. The
373
373
  // onPoison seam lets the session outbox surface the loss in-session instead of only in
374
374
  // this FATAL host log.
375
375
  private async poisonRow(row: Row, attempts: number, reason: string, immediate: boolean): Promise<void> {
@@ -29,7 +29,7 @@ export class PendingPermissionStore {
29
29
  readonly path: string;
30
30
 
31
31
  constructor(options: { agentId: string; dir?: string }) {
32
- const dir = options.dir ?? runnerOutboxDirFromEnv() ?? join(tmpdir(), "agent-relay-outbox");
32
+ const dir = options.dir ?? runnerOutboxDirFromEnv() ?? join(tmpdir(), "humwick-outbox");
33
33
  this.path = options.dir === ":memory:" ? ":memory:" : join(dir, `pending-permissions-${safeName(options.agentId)}.sqlite`);
34
34
  try {
35
35
  if (this.path !== ":memory:") mkdirSync(dirname(this.path), { recursive: true });
@@ -32,7 +32,7 @@ export function profileAllowsHostGlobalInstructions(config: { agentProfile?: Run
32
32
  *
33
33
  * The predicate itself lives in the sdk ({@link sdkProjectSettingSourcesOn}) so the
34
34
  * effective-profile survey and the v2 cell deriver stay in step with the runner's
35
- * actual launch derivation — see #2084.
35
+ * actual launch derivation —.
36
36
  */
37
37
  export function projectSettingSourcesOn(config: { agentProfile?: RunnerSpawnConfig["agentProfile"] }): boolean {
38
38
  const profile = config.agentProfile;
@@ -46,14 +46,14 @@ export function projectSettingSources(config: { agentProfile?: RunnerSpawnConfig
46
46
  return projectSettingSourcesOn(config) ? ["user", "project"] : ["user"];
47
47
  }
48
48
 
49
- // #3387 — every runner-managed profiled launch runs in a Relay-owned home; `base:"host"` only
49
+ // every runner-managed profiled launch runs in a Relay-owned home; `base:"host"` only
50
50
  // changes which host classes an omitted Host field inherits (see hostSourcesFor). A profile-less
51
51
  // launch is a user's own wrapped session and keeps the provider's native home.
52
52
  function profileRequiresIsolatedHome(config: RunnerSpawnConfig): boolean {
53
53
  return Boolean(config.agentProfile);
54
54
  }
55
55
 
56
- // #557 — PURE: the Relay-owned provider config home path a launch WILL use, or undefined for a
56
+ // PURE: the Relay-owned provider config home path a launch WILL use, or undefined for a
57
57
  // profile-less launch (the provider's normal home). The launch assembler computes the home this way
58
58
  // to report it + build CLAUDE_CONFIG_DIR/skill/plugin paths without side effects;
59
59
  // prepare*ProfileHome creates it at the same path at spawn time.
@@ -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 — host-base launches skip the onboarding/theme bootstrap (an
81
+ // 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
@@ -91,20 +91,20 @@ const BOOTSTRAP_HOOKS = new Map<string, BootstrapHook>();
91
91
  /**
92
92
  * The ONE materialization seam for an instance-keyed provider home
93
93
  * (`<root>/<provider>/<profile>/<instanceId>`) — every adapter that creates one MUST route
94
- * through it (#2624: the OpenCode family built its home by hand, so its homes carried no
94
+ * through it (the OpenCode family built its home by hand, so its homes carried no
95
95
  * owner-marker and no tombstone reclaim, and the reaper skipped every one of them as
96
96
  * "unmarked" forever). `identity` must be exactly the path segments of `target`: the reaper
97
97
  * refuses a marker that does not describe its own directory.
98
98
  */
99
99
  export function materializeProviderHome(target: string, identity: { provider: string; profile: string; instanceId: string; agentId?: string }, mode?: number): void {
100
- // #1256 spawn-side reclaim — FIRST recover any quarantine tombstone the reaper left for
100
+ // spawn-side reclaim — FIRST recover any quarantine tombstone the reaper left for
101
101
  // this exact instanceId (atomic rename back to `target`), BEFORE creating a fresh home.
102
102
  // This makes reconnection always safe (a reconnecting/resuming agent recovers its home)
103
103
  // and lets a crash-stranded tombstone self-heal. A lost reclaim race just falls through
104
104
  // to a fresh mkdir below — never a corrupt home.
105
105
  reclaimProviderHomeTombstone(target);
106
106
  mkdirSync(target, { recursive: true, ...(mode === undefined ? {} : { mode }) });
107
- // #1256 — stamp the owner-marker so the reaper can later reclaim this home if it becomes
107
+ // stamp the owner-marker so the reaper can later reclaim this home if it becomes
108
108
  // orphaned, but only ever on THIS host (cross-host safety).
109
109
  writeProviderHomeMarker(target, identity);
110
110
  }
@@ -132,23 +132,23 @@ function prepareProviderHome(provider: SpawnProvider, config: RunnerSpawnConfig)
132
132
  export const prepareCodexProfileHome = (config: RunnerSpawnConfig) => prepareProviderHome("codex", config);
133
133
 
134
134
  /**
135
- * #2254 — every Claude launch, isolated or host-base, leaves this function with folder trust
135
+ * every Claude launch, isolated or host-base, leaves this function with folder trust
136
136
  * already granted in the config file it will read. `prepareProviderHome` returns undefined for
137
137
  * a host-base profile (and for a profile-less spawn), which is exactly the class that used to
138
138
  * be seeded nowhere and wedged on the trust dialog; `ensureClaudeWorkspaceTrust` therefore runs
139
139
  * unconditionally, targeting the shared host config when there is no isolated home.
140
140
  *
141
- * #2513 — provider-id-dynamic for the claude family: claude-b passes its own id so the
141
+ * provider-id-dynamic for the claude family: claude-b passes its own id so the
142
142
  * isolated home, bootstrap hook, and auth links resolve against `~/.claude-b` (its manifest
143
143
  * configDir), never `~/.claude`.
144
144
  */
145
145
  export const prepareClaudeProfileHome = (config: RunnerSpawnConfig, provider: SpawnProvider = "claude"): ProviderHome | undefined => {
146
146
  const home = prepareProviderHome(provider, config);
147
- // #2513 review HIGH-1 — a dedicatedHome provider's host-base launch still reads the
147
+ // review HIGH-1 — a dedicatedHome provider's host-base launch still reads the
148
148
  // provider's OWN effective home (launch assembly exports CLAUDE_CONFIG_DIR at it), so
149
149
  // folder trust must be seeded in THAT home's .claude.json, not the shared ~/.claude.json.
150
150
  const trust = ensureClaudeWorkspaceTrust(config.cwd, home?.path ?? providerHostConfigHome(provider));
151
- // A seed that did not land puts this launch straight back into the #2254 wedge — CC opens
151
+ // A seed that did not land puts this launch straight back into the wedge — CC opens
152
152
  // its trust dialog and the spawn hangs until a human answers. The failure modes are all
153
153
  // environmental (an unparseable or unwritable host config, an operator opt-out), so the fix
154
154
  // cannot self-heal; it must at least say so instead of failing silently the way the missing
@@ -160,7 +160,7 @@ export const prepareClaudeProfileHome = (config: RunnerSpawnConfig, provider: Sp
160
160
  };
161
161
 
162
162
  function bootstrapCodexFirstRun(codexHome: string, config: RunnerSpawnConfig): void {
163
- // Keep bootstrap to one config read/write while repairing auth links (#2670).
163
+ // Keep bootstrap to one config read/write while repairing auth links.
164
164
  const path = join(codexHome, "config.toml");
165
165
  const current = existsSync(path) ? readFileSync(path, "utf8") : "";
166
166
  const next = withCodexWorkspaceTrust(withTomlFeatureFlag(current, "apps", false), config);
@@ -176,7 +176,7 @@ function bootstrapClaudeFirstRun(claudeHome: string, config: RunnerSpawnConfig):
176
176
 
177
177
  BOOTSTRAP_HOOKS.set("codex", bootstrapCodexFirstRun);
178
178
  BOOTSTRAP_HOOKS.set("claude", bootstrapClaudeFirstRun);
179
- // #2513 — the claude-b provider runs the identical claude first-run bootstrap (relay
179
+ // the claude-b provider runs the identical claude first-run bootstrap (relay
180
180
  // manual + config seed) inside its own claude-b-keyed home.
181
181
  BOOTSTRAP_HOOKS.set("claude-b", bootstrapClaudeFirstRun);
182
182
  BOOTSTRAP_HOOKS.set("claude-api", bootstrapClaudeFirstRun);
@@ -190,7 +190,7 @@ export function providerSourceHome(provider: string): string {
190
190
  }
191
191
 
192
192
  /**
193
- * #2513 — the effective HOST config home a `dedicatedHome` provider (claude-b) launches
193
+ * the effective HOST config home a `dedicatedHome` provider (claude-b) launches
194
194
  * from when it has no isolated managed home, or undefined for the primary provider
195
195
  * (claude), whose host-base launches keep their historical behavior of falling back to
196
196
  * the binary's own resolution ($CLAUDE_CONFIG_DIR ?? ~/.claude). Callers that need one
@@ -209,7 +209,7 @@ function ensureClaudeConfigSeed(claudeHome: string, config: RunnerSpawnConfig):
209
209
  writeJsonAtomic(path, seed);
210
210
  return;
211
211
  }
212
- // #1368/#harden — the isolated home is instance-keyed and PERSISTS across resumes/reconnects, so a
212
+ // /#harden — the isolated home is instance-keyed and PERSISTS across resumes/reconnects, so a
213
213
  // relaunch (e.g. auto-resume after a tmux/provider exit) reuses the existing `.claude.json` and
214
214
  // never re-runs the absent-file seed above. Re-heal every prompt-gate key the seed would have
215
215
  // applied on a fresh home (onboarding, theme, bypass-permissions, workspace-trust): a resumed
@@ -309,7 +309,7 @@ export async function hydrateClaudeHostConfig(config: RunnerSpawnConfig, provide
309
309
  * Loads only the seed values and host-scope MCP declaration required by a Claude launch. This
310
310
  * shared worker-pool seam gives registration projection and synchronous launch assembly the same
311
311
  * snapshot without ever parsing the host's potentially huge config on the runner event loop.
312
- * #2513 — keyed by provider id so a claude-family provider (claude-b) reads ITS source home.
312
+ * keyed by provider id so a claude-family provider (claude-b) reads ITS source home.
313
313
  */
314
314
  export async function readClaudeHostConfig(provider: SpawnProvider = "claude"): Promise<Record<string, unknown> | undefined> {
315
315
  const hostPath = join(providerSourceHome(provider), ".claude.json");
@@ -322,10 +322,10 @@ export async function readClaudeHostSettings(provider: SpawnProvider = "claude")
322
322
  return runnerHostConfigOffload().run<{ path: string; kind: "settings" }, Record<string, unknown> | undefined>("runner-claude-host-config-read", { path: settingsPath, kind: "settings" });
323
323
  }
324
324
 
325
- // #662 — the host USER-scope MCP servers: the top-level `mcpServers` of `~/.claude.json`.
325
+ // the host USER-scope MCP servers: the top-level `mcpServers` of `~/.claude.json`.
326
326
  // These are the ambient host MCP a host-base Claude auto-loads on EVERY launch when NOT
327
327
  // strict (user scope is global across all projects — callmux/qmd/gh on this host). Since
328
- // the #662 wedge fix makes every managed launch `--strict-mcp-config` (so Claude ignores
328
+ // the wedge fix makes every managed launch `--strict-mcp-config` (so Claude ignores
329
329
  // all on-disk config and never renders the project-`.mcp.json` enable modal), an
330
330
  // `mcp.mode:"host"` profile must re-inject these explicitly into `--mcp-config` to keep
331
331
  // honoring host mode. Deliberately NOT the project-cwd `.mcp.json` (project scope — the
@@ -356,7 +356,7 @@ function linkExistingAuthItems(sourceHome: string, targetHome: string, items: st
356
356
 
357
357
  function linkExistingPath(source: string, target: string): boolean {
358
358
  if (!existsSync(source) || existsSync(target)) return false;
359
- // #2670 — existsSync follows links; a reaped auth source leaves a dangling entry behind.
359
+ // existsSync follows links; a reaped auth source leaves a dangling entry behind.
360
360
  if (lstatSync(target, { throwIfNoEntry: false })?.isSymbolicLink()) unlinkSync(target);
361
361
  symlinkSync(source, target);
362
362
  return true;