@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.
- package/agent-bin/humwick +2 -2
- package/agent-bin/humwick-browser +4 -0
- package/hooks/fff-search-redirect/fff-search-redirect.cjs +1 -1
- package/hooks/web-tools-redirect/web-tools-redirect.cjs +2 -2
- package/package.json +7 -10
- package/plugins/browser/skills/playwright-cli/SKILL.md +8 -6
- package/plugins/claude/.claude-plugin/plugin.json +3 -3
- package/plugins/claude/claude-statusline-probe.cjs +26 -16
- package/plugins/claude/hooks/gate-run-guard.provisioned.mjs +47 -17
- package/plugins/claude/hooks/gate-run-guard.sh +3 -3
- package/plugins/claude/hooks/gate-run-guard.ts +5 -5
- package/plugins/claude/hooks/kill-guard.sh +4 -4
- package/plugins/claude/hooks/kill-guard.ts +1 -1
- package/plugins/claude/hooks/permission-request.sh +1 -1
- package/plugins/claude/hooks/post-compact.sh +1 -1
- package/plugins/claude/hooks/post-tool-use.sh +3 -3
- package/plugins/claude/hooks/pre-compact.sh +2 -2
- package/plugins/claude/hooks/read-only-bash-guard.sh +4 -4
- package/plugins/claude/hooks/relay-status.sh +32 -32
- package/plugins/claude/hooks/session-end.sh +2 -2
- package/plugins/claude/hooks/session-start.sh +3 -3
- package/plugins/claude/hooks/shell-trust.ts +1 -1
- package/plugins/claude/hooks/stop-failure.sh +2 -2
- package/plugins/claude/hooks/stop.sh +6 -6
- package/plugins/claude/hooks/subagent-skill-policy.cjs +8 -6
- package/plugins/claude/hooks/subagent-stop.sh +3 -3
- package/plugins/claude/hooks/user-prompt-submit.sh +1 -1
- package/plugins/claude/hooks/wait-loop-guard.ts +3 -3
- package/plugins/claude/monitors/monitors.json +2 -2
- package/plugins/claude/monitors/relay-monitor.provisioned.mjs +96 -62
- package/plugins/claude/monitors/relay-monitor.ts +5 -5
- package/plugins/claude/skills/label/SKILL.md +3 -3
- package/plugins/claude/skills/message/SKILL.md +5 -5
- package/plugins/claude/skills/react/SKILL.md +1 -1
- package/plugins/claude/skills/read-message/SKILL.md +4 -4
- package/plugins/claude/skills/reply/SKILL.md +5 -5
- package/plugins/claude/skills/send-claimable/SKILL.md +5 -5
- package/plugins/claude/skills/slice-first/SKILL.md +5 -3
- package/plugins/claude/skills/slice-first/references/plan-recipe.md +30 -29
- package/plugins/claude/skills/status/SKILL.md +1 -1
- package/plugins/claude/skills/tags/SKILL.md +5 -5
- package/plugins/claude/skills/task/SKILL.md +10 -10
- package/plugins/claude-output-style/.claude-plugin/plugin.json +1 -1
- package/plugins/claude-output-style/output-styles/{agent-relay.md → humwick.md} +1 -1
- package/plugins/codex/skills/guide/SKILL.md +1 -1
- package/plugins/codex/skills/label/SKILL.md +3 -3
- package/plugins/codex/skills/message/SKILL.md +5 -5
- package/plugins/codex/skills/react/SKILL.md +1 -1
- package/plugins/codex/skills/read-message/SKILL.md +4 -4
- package/plugins/codex/skills/reply/SKILL.md +5 -5
- package/plugins/codex/skills/send-claimable/SKILL.md +5 -5
- package/plugins/codex/skills/slice-first/SKILL.md +5 -3
- package/plugins/codex/skills/slice-first/references/plan-recipe.md +30 -29
- package/plugins/codex/skills/status/SKILL.md +1 -1
- package/plugins/codex/skills/tags/SKILL.md +5 -5
- package/plugins/codex/skills/task/SKILL.md +11 -10
- package/src/adapter.ts +95 -92
- package/src/adapters/claude-api.ts +8 -11
- package/src/adapters/claude-context-command.ts +1 -1
- package/src/adapters/claude-credentials.ts +7 -3
- package/src/adapters/claude-delivery-lanes.ts +2 -2
- package/src/adapters/claude-delivery.ts +16 -16
- package/src/adapters/claude-effort.ts +2 -2
- package/src/adapters/claude-exit.ts +2 -2
- package/src/adapters/claude-headless-mirror.ts +18 -2
- package/src/adapters/claude-headless-refusal.ts +3 -3
- package/src/adapters/claude-headless.ts +11 -10
- package/src/adapters/claude-launch-exit.ts +1 -1
- package/src/adapters/claude-monitor-delivery-plan.ts +36 -16
- package/src/adapters/claude-permission.ts +5 -5
- package/src/adapters/claude-prompt-gates.ts +9 -9
- package/src/adapters/claude-prompt-hook.ts +2 -2
- package/src/adapters/claude-session-capture.ts +6 -6
- package/src/adapters/claude-session-probe.ts +25 -25
- package/src/adapters/claude-shutdown.ts +11 -11
- package/src/adapters/claude-status-detectors.ts +31 -31
- package/src/adapters/claude-subagents.ts +7 -7
- package/src/adapters/claude-submit-confirmation.ts +6 -6
- package/src/adapters/claude-tmux.ts +43 -43
- package/src/adapters/claude-token-usage-capture.ts +5 -5
- package/src/adapters/claude-tool-policy.ts +7 -7
- package/src/adapters/claude-transcript.ts +24 -24
- package/src/adapters/claude.ts +100 -100
- package/src/adapters/codex-agent-message-capture.ts +26 -63
- package/src/adapters/codex-app-server.ts +1 -1
- package/src/adapters/codex-client.ts +9 -9
- package/src/adapters/codex-effective-config.ts +1 -1
- package/src/adapters/codex-launch-config.ts +5 -5
- package/src/adapters/codex-rollout-context.ts +2 -2
- package/src/adapters/codex-skill-discovery.ts +1 -1
- package/src/adapters/codex-token-usage-capture.ts +16 -16
- package/src/adapters/codex-tool-output.ts +4 -4
- package/src/adapters/codex-version.ts +3 -3
- package/src/adapters/codex.ts +64 -64
- package/src/adapters/opencode-api.ts +1 -1
- package/src/adapters/opencode-context.ts +20 -22
- package/src/adapters/opencode-model-registry.ts +7 -7
- package/src/adapters/opencode-provider.ts +8 -8
- package/src/adapters/opencode-provisioning.ts +30 -0
- package/src/adapters/opencode-server-retry.ts +1 -1
- package/src/adapters/opencode-soft-steer.ts +5 -5
- package/src/adapters/opencode-spawn.ts +18 -14
- package/src/adapters/opencode-token-usage-capture.ts +12 -12
- package/src/adapters/opencode-tool-events.ts +15 -15
- package/src/adapters/opencode.ts +232 -232
- package/src/adapters/project-shell.ts +11 -11
- package/src/adapters/service-access.ts +6 -6
- package/src/adapters/tmux-offload.ts +9 -9
- package/src/adapters/tool-summary.ts +5 -5
- package/src/agent-redact.ts +1 -1
- package/src/agent-runner/commands/dispatch.ts +10 -10
- package/src/agent-runner/commands/lifecycle.ts +2 -2
- package/src/agent-runner/commands/prompt.ts +19 -19
- package/src/agent-runner/credentials.ts +5 -5
- package/src/agent-runner/inbox.ts +1 -1
- package/src/agent-runner/lifecycle-milestones.ts +3 -3
- package/src/agent-runner/lifecycle-phase.ts +2 -2
- package/src/agent-runner/liveness-exchange.ts +4 -10
- package/src/agent-runner/registration.ts +8 -8
- package/src/agent-runner/runner-context.ts +9 -14
- package/src/agent-runner/session-mirror.ts +12 -12
- package/src/agent-runner/task-claims.ts +2 -2
- package/src/agent-runner/token-usage-coverage.ts +1 -1
- package/src/agent-runner/turn-report.ts +12 -12
- package/src/api-budget-accounting.ts +3 -3
- package/src/area-memory.ts +6 -6
- package/src/artifact-path-materialize.ts +1 -1
- package/src/async-guard.ts +5 -5
- package/src/attachment-cache.ts +17 -22
- package/src/background-script-reconcile.ts +6 -6
- package/src/bounded-log.ts +1 -1
- package/src/busy-reconciler.ts +22 -22
- package/src/claim-tracker.ts +3 -3
- package/src/claude-settings.ts +8 -8
- package/src/claude-system-prompt.ts +1 -1
- package/src/claude-workspace-trust.ts +1 -1
- package/src/config.ts +62 -61
- package/src/context-boundary.ts +5 -5
- package/src/context-command.ts +3 -3
- package/src/control-server.ts +32 -32
- package/src/delivery-result.ts +2 -2
- package/src/effort-command.ts +2 -2
- package/src/empty-turn.ts +22 -14
- package/src/free-port.ts +1 -1
- package/src/gate-run-config.ts +3 -3
- package/src/host-asset-plan.ts +24 -17
- package/src/host-claude-config-worker.ts +2 -2
- package/src/host-sources.ts +2 -2
- package/src/index.ts +16 -16
- package/src/launch-assembly.ts +94 -96
- package/src/liveness.ts +15 -15
- package/src/logger.ts +3 -3
- package/src/mcp-outbox.ts +3 -3
- package/src/mcp-preflight.ts +2 -2
- package/src/mcp-source-selection.ts +2 -2
- package/src/mcp-tool-deferral.ts +1 -1
- package/src/mcp-vault-env.ts +2 -2
- package/src/message-body-config/config.ts +4 -4
- package/src/mid-turn-delivery.ts +2 -2
- package/src/native-memory-lever.ts +8 -8
- package/src/outbox.ts +15 -15
- package/src/pending-permission-store.ts +1 -1
- package/src/profile-home.ts +19 -19
- package/src/profile-projection.ts +26 -24
- package/src/project-instructions.ts +5 -5
- package/src/provider-auth-warning.ts +17 -0
- package/src/provider-double.ts +1 -1
- package/src/provider-hold.ts +3 -3
- package/src/provider-home-marker.ts +1 -1
- package/src/provider-home-tombstone.ts +1 -1
- package/src/provider-input-queue.ts +2 -2
- package/src/provider-integration.ts +15 -13
- package/src/provider-setup.ts +15 -3
- package/src/providers.ts +1 -1
- package/src/provisioning.ts +37 -40
- package/src/question-decision.ts +2 -2
- package/src/quota.ts +0 -6
- package/src/rate-limit.ts +24 -13
- package/src/refused-prompt-store.ts +2 -2
- package/src/relay-injection-events.ts +2 -2
- package/src/relay-instructions.ts +5 -5
- package/src/relay-mcp-proxy.long-turn-e2e.ts +13 -13
- package/src/relay-mcp-proxy.ts +57 -58
- package/src/relay-mcp.ts +55 -69
- package/src/reply-obligation-cache.ts +9 -9
- package/src/response-capture-report.ts +9 -9
- package/src/response-routing.ts +1 -1
- package/src/runner-core.ts +209 -222
- package/src/runner-exit.ts +1 -1
- package/src/runner-helpers.ts +10 -10
- package/src/runner-insights.ts +4 -2
- package/src/runner-mcp-proxy.ts +3 -3
- package/src/runner-spawn-config.ts +3 -3
- package/src/runtime-token-file.ts +1 -1
- package/src/runtime-token-remint.ts +1 -1
- package/src/service-access.ts +2 -2
- package/src/session-destroy.ts +1 -1
- package/src/session-insights.ts +1 -1
- package/src/session-scratch.ts +24 -37
- package/src/spawn-input.ts +6 -6
- package/src/startup-config-fetch.ts +4 -4
- package/src/subreaper.ts +3 -5
- package/src/test-run-dedup.ts +13 -13
- package/src/transcript-context.ts +2 -2
- package/src/transport-errors.ts +1 -1
- package/src/turn-opener.ts +1 -1
- package/src/turn-reconcile-event.ts +2 -2
- package/src/vault-proxy-hop.ts +2 -2
- package/src/web-tools.ts +2 -2
- package/agent-bin/agent-relay-browser +0 -10
- package/src/adapters/provider-quota-harvest.ts +0 -76
package/src/busy-reconciler.ts
CHANGED
|
@@ -8,16 +8,16 @@ const BUSY_RECONCILE_IDLE_CONFIRM = 8;
|
|
|
8
8
|
const BUSY_RECONCILE_IDLE_CONFIRM_NO_BUSY = 15;
|
|
9
9
|
const INTERRUPT_RECONCILE_DELAY_MS = 1_500;
|
|
10
10
|
const PROVIDER_TURN_CLEAR_TIMEOUT_MS = 60_000;
|
|
11
|
-
//
|
|
11
|
+
// U2 — how many consecutive reconcile ticks a live turn may be HELD (never force-cleared,
|
|
12
12
|
// because there is no positive end-evidence) before the backstop escalates a NOTIFY-ONLY
|
|
13
13
|
// watchdog. At the 4s poll this is ~20 min. The escalation NEVER cancels the turn (a 44-min gate
|
|
14
14
|
// is legitimate); it only surfaces "this turn has been held a long time" to the coordinator, so a
|
|
15
15
|
// genuinely wedged-but-active agent (a frozen `busy`, or a pane-scrape-only long tool the runner
|
|
16
16
|
// cannot prove idle) is seen instead of silently cancelled. One-shot per turn (reset on arm/disarm).
|
|
17
17
|
//
|
|
18
|
-
//
|
|
18
|
+
// INVARIANT: this interval (BUSY_RECONCILE_WATCHDOG_TICKS * BUSY_RECONCILE_POLL_MS, ~20
|
|
19
19
|
// min) must stay >= the server's STUCK_BUSY_PROVIDER_TURN_MS threshold (src/config.ts, default
|
|
20
|
-
// 15 min but operator-configurable via
|
|
20
|
+
// 15 min but operator-configurable via HUMWICK_STUCK_BUSY_PROVIDER_TURN_MS). The server-side
|
|
21
21
|
// gate in auditProviderTurnWatchdog (src/services/turn-reconcile-audit.ts) only wakes the
|
|
22
22
|
// coordinator once staleForMs (time since real last progress) reaches that threshold. If an
|
|
23
23
|
// operator raises the server threshold ABOVE this interval, a genuinely dead-from-the-start turn
|
|
@@ -34,18 +34,18 @@ interface BusyReconcilerDeps {
|
|
|
34
34
|
hasProviderTurn(): boolean;
|
|
35
35
|
canProbeActivity(): boolean;
|
|
36
36
|
probeActivity(): Promise<ProviderActivity> | undefined;
|
|
37
|
-
//
|
|
37
|
+
// P1-A: optional independent pane-busy read. `busy` vetoes a clear; `not-busy`
|
|
38
38
|
// is the positive corroboration every counted idle tick requires; anything else is unknown
|
|
39
39
|
// and holds the turn. Omitted entirely by providers with no pane to read.
|
|
40
40
|
probePaneBusy?(): Promise<PaneBusyReading> | undefined;
|
|
41
41
|
clearProviderTurn(reason: string): void;
|
|
42
|
-
//
|
|
42
|
+
// U2 — escalate a NOTIFY-ONLY watchdog for a live turn the backstop has HELD past the
|
|
43
43
|
// prolonged-hold threshold (a frozen-active `busy`, or a pane-scrape-only long tool that can
|
|
44
44
|
// never be positively proven idle — probeActivity reads `unknown`, not `idle`, so the clear
|
|
45
45
|
// paths are never reached). The runner turns this into a coordinator notification; it MUST NOT
|
|
46
46
|
// cancel the turn. Optional: providers/tests without a watchdog simply hold silently.
|
|
47
47
|
escalateWatchdog?(reason: string): void;
|
|
48
|
-
/** Every no-provider-turn edge (
|
|
48
|
+
/** Every no-provider-turn edge (a pending effort change applies here). */
|
|
49
49
|
turnCleared?(): void;
|
|
50
50
|
sessionDebug(message: string): void;
|
|
51
51
|
}
|
|
@@ -54,12 +54,12 @@ export class BusyReconciler {
|
|
|
54
54
|
private idleStreak = 0;
|
|
55
55
|
private timer?: ReturnType<typeof setInterval>;
|
|
56
56
|
private sawBusy = false;
|
|
57
|
-
//
|
|
57
|
+
// U2 — consecutive reconcile ticks this live turn has been held without ending, and the
|
|
58
58
|
// one-shot guard so the prolonged-hold watchdog notifies at most once per turn. Both reset on
|
|
59
59
|
// arm/disarm (a new turn starts a fresh hold budget).
|
|
60
60
|
private heldTicks = 0;
|
|
61
61
|
private watchdogEscalated = false;
|
|
62
|
-
//
|
|
62
|
+
// row 14 — the activity probe now runs OFF the runner's event loop (async tmux
|
|
63
63
|
// subprocess + probe reads), so a single reconcile can outlast the 4s poll interval when a
|
|
64
64
|
// tmux socket is slow. This guard drops any timer tick that fires while the previous
|
|
65
65
|
// reconcile is still in flight, so slow probes can never stack N concurrent reads on one
|
|
@@ -67,7 +67,7 @@ export class BusyReconciler {
|
|
|
67
67
|
// directly and await it to completion are unaffected — the flag is always clear by the next
|
|
68
68
|
// call.
|
|
69
69
|
private reconcileInFlight = false;
|
|
70
|
-
//
|
|
70
|
+
// round-3 HIGH — a monotonic generation, the same await-fence the turn watcher uses.
|
|
71
71
|
// Captured at the start of a reconcile and re-checked after EVERY await before any streak
|
|
72
72
|
// mutation or clearProviderTurn: a disarm / re-arm / turn clear that happens while an off-loop
|
|
73
73
|
// probe is in flight means the verdict describes a STALE turn, so it must not clear a
|
|
@@ -98,7 +98,7 @@ export class BusyReconciler {
|
|
|
98
98
|
this.watchdogEscalated = false;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
//
|
|
101
|
+
// round-3 HIGH — true when an in-flight reconcile that started at `gen` must abandon
|
|
102
102
|
// without mutating streak state or clearing: the generation moved (arm/disarm/turn clear), or
|
|
103
103
|
// the turn/process/lifecycle preconditions it verified BEFORE its await no longer hold. Cheap,
|
|
104
104
|
// synchronous, re-evaluated after each await.
|
|
@@ -123,7 +123,7 @@ export class BusyReconciler {
|
|
|
123
123
|
// durable timeline event during teardown. Catch at this boundary so an expected race cannot
|
|
124
124
|
// become Bun's process-fatal unhandled rejection; retain the error in the session log.
|
|
125
125
|
private runInBackground(): void {
|
|
126
|
-
//
|
|
126
|
+
// row 14 — skip this tick if the previous off-loop reconcile is still running.
|
|
127
127
|
if (this.reconcileInFlight) {
|
|
128
128
|
this.deps.sessionDebug("busy reconcile skipped: previous probe still in flight");
|
|
129
129
|
return;
|
|
@@ -149,7 +149,7 @@ export class BusyReconciler {
|
|
|
149
149
|
const probe = this.deps.probeActivity();
|
|
150
150
|
let activity: ProviderActivity = "unknown";
|
|
151
151
|
try { if (probe) activity = await probe; } catch { return; }
|
|
152
|
-
//
|
|
152
|
+
// round-3 HIGH: re-check after the probe await. Turn A was interrupted, its probe
|
|
153
153
|
// stalled, A ended and Turn B began — A's stale `idle` must NOT clear B. `stale(gen)` catches
|
|
154
154
|
// the disarm/re-arm/turn-clear (via generation) AND a status/turn that moved out from under us.
|
|
155
155
|
if (this.stale(gen)) return;
|
|
@@ -175,7 +175,7 @@ export class BusyReconciler {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
providerTurnCleared(): void {
|
|
178
|
-
//
|
|
178
|
+
// round-3 HIGH — a turn clear/replacement invalidates any in-flight reconcile that was
|
|
179
179
|
// judging the turn that just ended. Bump BEFORE the waiter-fan-out and the hasProviderTurn
|
|
180
180
|
// guard: this method is only invoked by the runner on a no-provider-turn edge, so it never
|
|
181
181
|
// fires during a legitimate active reconcile.
|
|
@@ -200,15 +200,15 @@ export class BusyReconciler {
|
|
|
200
200
|
this.disarm();
|
|
201
201
|
return;
|
|
202
202
|
}
|
|
203
|
-
//
|
|
203
|
+
// a probe we could not read is `unknown`, not `idle`. It breaks the streak
|
|
204
204
|
// exactly like any other non-idle reading — it must never be silently skipped past.
|
|
205
205
|
let activity: ProviderActivity;
|
|
206
206
|
try { activity = await probe; } catch { activity = "unknown"; }
|
|
207
|
-
//
|
|
207
|
+
// round-3 HIGH: re-check after the (off-loop) probe await, BEFORE touching sawBusy /
|
|
208
208
|
// idleStreak. A disarm/re-arm or turn clear while the probe was in flight means this verdict
|
|
209
209
|
// is for a stale turn — abandon rather than mutate the successor's streak.
|
|
210
210
|
if (this.stale(gen)) return;
|
|
211
|
-
//
|
|
211
|
+
// U2 — this tick observed a still-live, still-busy provider turn that did not end. A
|
|
212
212
|
// turn that is genuinely wedged-but-active never reaches a force-clear at all: a frozen
|
|
213
213
|
// foreground tool keeps reading `busy`, and a pane-scrape-only long tool reads `unknown` (not
|
|
214
214
|
// `idle`, so its streak never accumulates). Count the hold so such a turn is escalated to a
|
|
@@ -221,14 +221,14 @@ export class BusyReconciler {
|
|
|
221
221
|
this.deps.sessionDebug(`reconcile probe=${activity} sawBusy=${this.sawBusy} streak=${this.idleStreak}`);
|
|
222
222
|
return;
|
|
223
223
|
}
|
|
224
|
-
//
|
|
224
|
+
// P1-A: the probe alone does not get to end a turn. An independent pane read
|
|
225
225
|
// runs on EVERY idle tick — not just once at the force-clear moment — and the streak counts
|
|
226
|
-
// only ticks where it positively reported `not-busy`. That is the substance
|
|
226
|
+
// only ticks where it positively reported `not-busy`. That is the substance: the
|
|
227
227
|
// old counter measured "how long since I last saw busy", which a pane that cannot be read at
|
|
228
228
|
// all satisfies perfectly. It now measures accumulated positive evidence that the turn ended,
|
|
229
229
|
// and any tick that fails to produce such evidence resets it to zero.
|
|
230
230
|
const pane = await this.readPaneBusy();
|
|
231
|
-
//
|
|
231
|
+
// round-3 HIGH: re-check after the pane await too — this is the tick that can call
|
|
232
232
|
// clearProviderTurn, so a turn that was replaced during the pane read must not be cleared.
|
|
233
233
|
if (this.stale(gen)) return;
|
|
234
234
|
if (pane === "busy") {
|
|
@@ -246,10 +246,10 @@ export class BusyReconciler {
|
|
|
246
246
|
const confirm = this.sawBusy ? BUSY_RECONCILE_IDLE_CONFIRM : BUSY_RECONCILE_IDLE_CONFIRM_NO_BUSY;
|
|
247
247
|
this.deps.sessionDebug(`reconcile not-busy pane=${pane ?? "none"} sawBusy=${this.sawBusy} streak=${this.idleStreak}/${confirm}`);
|
|
248
248
|
if (this.idleStreak < confirm) return;
|
|
249
|
-
//
|
|
249
|
+
// U2 — reaching here means POSITIVE end-evidence: the activity read is `idle`, which for
|
|
250
250
|
// a probe-capable Claude session comes only from the provider's own idle assertion or a
|
|
251
251
|
// busy-verdict a real interrupt / trust-window decay turned idle — NOT from pane silence. A
|
|
252
|
-
// long foreground tool the runner cannot see now reads `unknown
|
|
252
|
+
// long foreground tool the runner cannot see now reads `unknown`,
|
|
253
253
|
// whose streak resets above, so the `no-busy-observed` force-cancel that lost the 44-min gate
|
|
254
254
|
// is no longer reachable from silence. Genuine ends still clear here, with their reason +
|
|
255
255
|
// notification (the interrupted-turn audit downstream).
|
|
@@ -261,7 +261,7 @@ export class BusyReconciler {
|
|
|
261
261
|
this.deps.clearProviderTurn(reason);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
//
|
|
264
|
+
// U2 — fire the notify-only watchdog at most once per turn. The reconciler NEVER cancels
|
|
265
265
|
// the turn on this path; it only asks the runner to tell the coordinator the turn is being held.
|
|
266
266
|
private emitWatchdog(reason: string): void {
|
|
267
267
|
if (this.watchdogEscalated) return;
|
package/src/claim-tracker.ts
CHANGED
|
@@ -17,7 +17,7 @@ interface WorkRecord {
|
|
|
17
17
|
role?: string;
|
|
18
18
|
parentId?: string;
|
|
19
19
|
metadata?: Record<string, unknown>;
|
|
20
|
-
// OS pids of the underlying process(es) this work tracks
|
|
20
|
+
// OS pids of the underlying process(es) this work tracks. When present,
|
|
21
21
|
// a periodic liveness reconcile clears the record once every pid is dead — so a
|
|
22
22
|
// tracked process killed out-of-band (no exit event) can't strand the agent busy.
|
|
23
23
|
pids?: number[];
|
|
@@ -112,7 +112,7 @@ export class ClaimTracker {
|
|
|
112
112
|
return [...this.work.values()];
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
/** True iff any active work carries pids the liveness reconcile can check
|
|
115
|
+
/** True iff any active work carries pids the liveness reconcile can check. */
|
|
116
116
|
hasLivenessTrackedWork(): boolean {
|
|
117
117
|
for (const item of this.work.values()) {
|
|
118
118
|
if (item.pids && item.pids.length > 0) return true;
|
|
@@ -121,7 +121,7 @@ export class ClaimTracker {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
|
-
* Reconcile pid-bearing work against actual process liveness
|
|
124
|
+
* Reconcile pid-bearing work against actual process liveness: drop any
|
|
125
125
|
* record whose tracked pids are ALL dead — its underlying process died out-of-band
|
|
126
126
|
* (killed/crashed/orphaned) with no exit event to clear the busy marker. Records
|
|
127
127
|
* with no pids are never touched (no liveness signal to act on). Returns the removed
|
package/src/claude-settings.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { projectClaudePermissionRules } from "./provider-integration";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
|
-
import type { ProvisioningHookSet
|
|
4
|
+
import type { ProvisioningHookSet } from "@humwick/sdk";
|
|
5
5
|
import { mergeClaudeRelayPermissions } from "./provisioning";
|
|
6
6
|
import { shellQuote } from "@humwick/sdk/shell-utils";
|
|
7
7
|
|
|
@@ -14,7 +14,7 @@ export interface ClaudeSettingsResolution {
|
|
|
14
14
|
suppressedHookNames: string[];
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// Claude Code's own defaults append "Generated with Claude Code" / Co-Authored-By.
|
|
18
18
|
// `attribution` is the current key; `includeCoAuthoredBy` is its deprecated predecessor.
|
|
19
19
|
export const CLAUDE_NO_ATTRIBUTION_SETTINGS = { attribution: { commit: "", pr: "" }, includeCoAuthoredBy: false } as const;
|
|
20
20
|
export const CLAUDE_NO_ATTRIBUTION_RULE =
|
|
@@ -31,14 +31,14 @@ export function claudeSettingsArgs(
|
|
|
31
31
|
hookNames: string[],
|
|
32
32
|
includeStatusLine: boolean,
|
|
33
33
|
nativeMemorySettings: Record<string, unknown>,
|
|
34
|
-
launch: { cwd: string; model?: string
|
|
34
|
+
launch: { cwd: string; model?: string },
|
|
35
35
|
...argLists: string[][]
|
|
36
36
|
): ClaudeSettingsResolution {
|
|
37
37
|
const relaySettings: Record<string, unknown> = {
|
|
38
38
|
...projectSettings,
|
|
39
39
|
...(Object.keys(provisionedHooks).length ? { hooks: provisionedHooks } : {}),
|
|
40
40
|
...(includeStatusLine ? relayStatusLineSettings() : {}),
|
|
41
|
-
//
|
|
41
|
+
// P5.7 — LAST, so a project `.claude/settings.json` cannot quietly re-enable a
|
|
42
42
|
// profile's native memory. (Claude's own env predicate outranks all of this either way.)
|
|
43
43
|
...nativeMemorySettings,
|
|
44
44
|
...CLAUDE_NO_ATTRIBUTION_SETTINGS,
|
|
@@ -47,14 +47,14 @@ export function claudeSettingsArgs(
|
|
|
47
47
|
const caller = extractCallerSettings(argLists, launch.cwd);
|
|
48
48
|
if (!caller) {
|
|
49
49
|
return {
|
|
50
|
-
args: Object.keys(relaySettings).length ? ["--settings", JSON.stringify(projectClaudePermissionRules(relaySettings
|
|
50
|
+
args: Object.keys(relaySettings).length ? ["--settings", JSON.stringify(projectClaudePermissionRules(relaySettings))] : [],
|
|
51
51
|
callerSettingsConsumed: false, statusLineApplied: includeStatusLine,
|
|
52
52
|
suppressedHookNames: [],
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
if (caller.settings) {
|
|
56
56
|
const merged = mergeClaudeSettings(caller.settings, relaySettings, launch.model);
|
|
57
|
-
return { args: ["--settings", JSON.stringify(projectClaudePermissionRules(merged
|
|
57
|
+
return { args: ["--settings", JSON.stringify(projectClaudePermissionRules(merged))], callerSettingsConsumed: true, statusLineApplied: includeStatusLine && merged.statusLine === relaySettings.statusLine, suppressedHookNames: [] };
|
|
58
58
|
}
|
|
59
59
|
throw new Error("Claude --settings must be a JSON object or a readable JSON settings file (idleCompaction must be disabled)");
|
|
60
60
|
}
|
|
@@ -132,7 +132,7 @@ function isHookSet(value: unknown): value is ProvisioningHookSet {
|
|
|
132
132
|
|
|
133
133
|
// Strip every `--settings <json>` / `--settings=<json>` occurrence from a provider arg list. The
|
|
134
134
|
// adapter applies this to the caller args once the assembler has folded them into its own merged
|
|
135
|
-
// `--settings` (callerSettingsConsumed), so exactly one `--settings` reaches the launch
|
|
135
|
+
// `--settings` (callerSettingsConsumed), so exactly one `--settings` reaches the launch.
|
|
136
136
|
export function stripSettingsArgs(args: string[]): string[] {
|
|
137
137
|
const result: string[] = [];
|
|
138
138
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -149,7 +149,7 @@ export function hasSettingsArg(args: string[]): boolean {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
// Claude relay status-line + readable-thinking settings, injected only when no caller
|
|
152
|
-
// --settings is already present (caller wins). Relocated from claude.ts
|
|
152
|
+
// --settings is already present (caller wins). Relocated from claude.ts.
|
|
153
153
|
export function sessionStatusLineSettingsArgs(...argLists: string[][]): string[] {
|
|
154
154
|
if (argLists.some(hasSettingsArg)) return [];
|
|
155
155
|
return ["--settings", JSON.stringify(relayStatusLineSettings())];
|
|
@@ -9,7 +9,7 @@ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
|
9
9
|
|
|
10
10
|
const APPEND_FLAGS = ["--append-system-prompt", "--append-system-prompt-file"];
|
|
11
11
|
|
|
12
|
-
//
|
|
12
|
+
// caller/default appends share the same file channel as Relay context.
|
|
13
13
|
export function claudeCallerAppends(args: string[]): { args: string[]; appends: Array<{ value: string; file: boolean }> } {
|
|
14
14
|
const remaining: string[] = [];
|
|
15
15
|
const appends: Array<{ value: string; file: boolean }> = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Claude folder-trust seeding for EVERY launch, host-base included.
|
|
2
2
|
//
|
|
3
3
|
// THE BUG: relay seeded `projects[cwd].hasTrustDialogAccepted` only into an ISOLATED
|
|
4
4
|
// `CLAUDE_CONFIG_DIR` (profile-home's `ensureClaudeConfigSeed`). Host-base profiles and
|