create-walle 0.10.2 → 0.10.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/lib/release-schema.json +2 -2
- package/lib/runtime-closure-policy.json +8 -7
- package/package.json +1 -1
- package/template/coding-task-manager/api-prompts.js +45 -7
- package/template/coding-task-manager/bin/claude-hook.js +55 -1
- package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
- package/template/coding-task-manager/bin/land.js +2069 -0
- package/template/coding-task-manager/bin/memory-census.js +4 -2
- package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
- package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
- package/template/coding-task-manager/db.js +156 -32
- package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
- package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
- package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
- package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
- package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
- package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
- package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
- package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
- package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
- package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
- package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
- package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
- package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
- package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
- package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
- package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
- package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
- package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
- package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
- package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
- package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
- package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
- package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
- package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
- package/template/coding-task-manager/lib/agent-definitions.js +19 -0
- package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
- package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
- package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
- package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
- package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
- package/template/coding-task-manager/lib/agent-presets.js +84 -1
- package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
- package/template/coding-task-manager/lib/agent-version-service.js +74 -11
- package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
- package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
- package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
- package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
- package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
- package/template/coding-task-manager/lib/api/fleet.js +118 -0
- package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
- package/template/coding-task-manager/lib/api/ingress.js +9 -1
- package/template/coding-task-manager/lib/api/landing.js +403 -0
- package/template/coding-task-manager/lib/api/machines.js +691 -2
- package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
- package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
- package/template/coding-task-manager/lib/api/session-attach.js +623 -0
- package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
- package/template/coding-task-manager/lib/api/sessions.js +77 -51
- package/template/coding-task-manager/lib/api/setup-network.js +544 -16
- package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
- package/template/coding-task-manager/lib/api/setup.js +829 -10
- package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
- package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
- package/template/coding-task-manager/lib/auth-rules.js +292 -21
- package/template/coding-task-manager/lib/background-stop.js +369 -0
- package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
- package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
- package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
- package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
- package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
- package/template/coding-task-manager/lib/build-info.js +4 -2
- package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
- package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
- package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
- package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
- package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
- package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
- package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
- package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
- package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
- package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
- package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
- package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
- package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
- package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
- package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
- package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
- package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
- package/template/coding-task-manager/lib/conversation-sync.js +355 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
- package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
- package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
- package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
- package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
- package/template/coding-task-manager/lib/db-domains.js +1 -0
- package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
- package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
- package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
- package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
- package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
- package/template/coding-task-manager/lib/feature-manifest.js +4 -0
- package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
- package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
- package/template/coding-task-manager/lib/fleet-hub.js +762 -0
- package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
- package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
- package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
- package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
- package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
- package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
- package/template/coding-task-manager/lib/fleet-update.js +798 -0
- package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
- package/template/coding-task-manager/lib/fs-watcher.js +58 -42
- package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
- package/template/coding-task-manager/lib/headless-term-service.js +84 -8
- package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
- package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
- package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
- package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
- package/template/coding-task-manager/lib/host-handoff.js +16 -19
- package/template/coding-task-manager/lib/host-stats.js +150 -3
- package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
- package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
- package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
- package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
- package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
- package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
- package/template/coding-task-manager/lib/hub-bridge.js +398 -0
- package/template/coding-task-manager/lib/idle-notify.js +491 -0
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
- package/template/coding-task-manager/lib/instance-manifest.js +5 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
- package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
- package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
- package/template/coding-task-manager/lib/landing/config.js +536 -0
- package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
- package/template/coding-task-manager/lib/landing/gate.js +360 -0
- package/template/coding-task-manager/lib/landing/git.js +344 -0
- package/template/coding-task-manager/lib/landing/lease.js +247 -0
- package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
- package/template/coding-task-manager/lib/landing/proof.js +223 -0
- package/template/coding-task-manager/lib/landing/queue.js +998 -0
- package/template/coding-task-manager/lib/landing/radar.js +489 -0
- package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
- package/template/coding-task-manager/lib/landing/state.js +263 -0
- package/template/coding-task-manager/lib/landing/stop.js +49 -0
- package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
- package/template/coding-task-manager/lib/landing/sync.js +456 -0
- package/template/coding-task-manager/lib/landing/train.js +885 -0
- package/template/coding-task-manager/lib/landing/window.js +57 -0
- package/template/coding-task-manager/lib/launch-environment.js +121 -0
- package/template/coding-task-manager/lib/launch-model-override.js +36 -10
- package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
- package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
- package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
- package/template/coding-task-manager/lib/lead-model-options.js +160 -3
- package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
- package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
- package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
- package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
- package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
- package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
- package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
- package/template/coding-task-manager/lib/machine-registry.js +750 -5
- package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
- package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
- package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
- package/template/coding-task-manager/lib/memory-join.js +337 -0
- package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
- package/template/coding-task-manager/lib/memory-sync.js +565 -0
- package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
- package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
- package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
- package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
- package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
- package/template/coding-task-manager/lib/model-availability.js +727 -0
- package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
- package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
- package/template/coding-task-manager/lib/model-id-rule.js +19 -0
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
- package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
- package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
- package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
- package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
- package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
- package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
- package/template/coding-task-manager/lib/native-history-control.js +6 -4
- package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
- package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
- package/template/coding-task-manager/lib/opencode-cli.js +480 -0
- package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
- package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
- package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
- package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
- package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
- package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
- package/template/coding-task-manager/lib/perf-summary.js +7 -0
- package/template/coding-task-manager/lib/perf-tracker.js +63 -2
- package/template/coding-task-manager/lib/project-config.js +7 -0
- package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
- package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
- package/template/coding-task-manager/lib/read-pool-client.js +89 -2
- package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
- package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
- package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
- package/template/coding-task-manager/lib/relay-client.js +57 -3
- package/template/coding-task-manager/lib/relink-audit.js +34 -5
- package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
- package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
- package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
- package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
- package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
- package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
- package/template/coding-task-manager/lib/restart-guard.js +18 -6
- package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
- package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
- package/template/coding-task-manager/lib/resume-admission.js +17 -3
- package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
- package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
- package/template/coding-task-manager/lib/runtime-contract.js +3 -1
- package/template/coding-task-manager/lib/schema-indexes.js +1 -0
- package/template/coding-task-manager/lib/session-context-locator.js +742 -0
- package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
- package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
- package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
- package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
- package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
- package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
- package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
- package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
- package/template/coding-task-manager/lib/session-create/response.js +7 -7
- package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
- package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
- package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
- package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
- package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
- package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
- package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
- package/template/coding-task-manager/lib/session-empty.js +13 -10
- package/template/coding-task-manager/lib/session-host-manager.js +60 -0
- package/template/coding-task-manager/lib/session-jobs.js +3 -1
- package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
- package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
- package/template/coding-task-manager/lib/session-park.js +738 -0
- package/template/coding-task-manager/lib/session-path-grant.js +13 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
- package/template/coding-task-manager/lib/session-transport.js +17 -0
- package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
- package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
- package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
- package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
- package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
- package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
- package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
- package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
- package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
- package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
- package/template/coding-task-manager/lib/submission-ack.js +90 -2
- package/template/coding-task-manager/lib/systemd-scope.js +115 -0
- package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
- package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
- package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
- package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
- package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
- package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
- package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
- package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
- package/template/coding-task-manager/lib/transcript-source.js +36 -4
- package/template/coding-task-manager/lib/transcript-store.js +9 -0
- package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
- package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
- package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
- package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
- package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
- package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
- package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
- package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
- package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
- package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
- package/template/coding-task-manager/lib/walle/turn.js +1 -1
- package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
- package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
- package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
- package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
- package/template/coding-task-manager/lib/walle-row-history.js +495 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
- package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
- package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
- package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
- package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
- package/template/coding-task-manager/lib/ws/misc.js +1 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
- package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
- package/template/coding-task-manager/oauth-proxy.js +112 -115
- package/template/coding-task-manager/package-lock.json +10 -94
- package/template/coding-task-manager/package.json +4 -3
- package/template/coding-task-manager/protocol/message-table.json +10 -0
- package/template/coding-task-manager/protocol/messages.js +10 -0
- package/template/coding-task-manager/protocol/ws-schema.json +20 -0
- package/template/coding-task-manager/protocol/ws-schema.md +2 -0
- package/template/coding-task-manager/public/css/app.css +170 -0
- package/template/coding-task-manager/public/css/walle-session.css +4 -0
- package/template/coding-task-manager/public/index.html +473 -243
- package/template/coding-task-manager/public/js/agent-command.js +86 -0
- package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
- package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
- package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
- package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
- package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
- package/template/coding-task-manager/public/js/background-work.js +196 -27
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
- package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
- package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
- package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
- package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
- package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
- package/template/coding-task-manager/public/js/document-review-links.js +9 -1
- package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
- package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
- package/template/coding-task-manager/public/js/message-renderer.js +4 -3
- package/template/coding-task-manager/public/js/model-picker.js +3 -1
- package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
- package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
- package/template/coding-task-manager/public/js/pasted-content.js +236 -0
- package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
- package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
- package/template/coding-task-manager/public/js/prompts.js +11 -10
- package/template/coding-task-manager/public/js/protocol.js +10 -0
- package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
- package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
- package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
- package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
- package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
- package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
- package/template/coding-task-manager/public/js/stream-view.js +6 -5
- package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
- package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
- package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
- package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
- package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
- package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
- package/template/coding-task-manager/public/js/walle.js +6 -0
- package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
- package/template/coding-task-manager/public/m/app.css +140 -0
- package/template/coding-task-manager/public/m/app.js +507 -68
- package/template/coding-task-manager/public/m/index.html +17 -0
- package/template/coding-task-manager/public/m/machines.js +838 -4
- package/template/coding-task-manager/public/m/private-api.js +31 -1
- package/template/coding-task-manager/public/usage.html +1 -0
- package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
- package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
- package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
- package/template/coding-task-manager/server.js +1950 -11679
- package/template/coding-task-manager/session-integrity.js +64 -4
- package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
- package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
- package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
- package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
- package/template/coding-task-manager/workers/session-host-process.js +5 -5
- package/template/coding-task-manager/workers/watch-worker.js +105 -0
- package/template/coding-task-manager/workers/worktree-worker.js +168 -33
- package/template/ctm-relay/lib/protocol.js +14 -1
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/shared/backup-retention.js +82 -0
- package/template/shared/conversation-admission.js +2 -0
- package/template/shared/conversation-provenance.js +3 -7
- package/template/shared/conversation-storage-v2-contract.js +5 -0
- package/template/shared/linked-worktree.js +51 -0
- package/template/shared/macos-fda-target.js +57 -0
- package/template/shared/orphan-parents.js +55 -0
- package/template/shared/release-schema.json +2 -2
- package/template/shared/storage/contract.js +3 -0
- package/template/wall-e/adapters/imessage.js +12 -0
- package/template/wall-e/agent.js +71 -4
- package/template/wall-e/api-walle.js +21 -1
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
- package/template/wall-e/brain/brain-join.js +859 -0
- package/template/wall-e/brain/brain-sync-membership.js +20 -0
- package/template/wall-e/brain/brain-sync-store.js +131 -77
- package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
- package/template/wall-e/brain/brain-sync-v2.js +578 -0
- package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
- package/template/wall-e/brain/deterministic-id.js +51 -0
- package/template/wall-e/brain/memories.js +2 -2
- package/template/wall-e/brain/migrations.js +40 -6
- package/template/wall-e/brain/model-identity-migration.js +1 -1
- package/template/wall-e/brain/owner-call-whitelist.js +23 -7
- package/template/wall-e/brain/schema.js +45 -85
- package/template/wall-e/brain.js +171 -35
- package/template/wall-e/chat.js +3 -3
- package/template/wall-e/coding/agent-shell-env.js +7 -2
- package/template/wall-e/coding/prompt-bundle.js +66 -21
- package/template/wall-e/config/main-loop-exemptions.json +2 -2
- package/template/wall-e/http/admin-api.js +37 -0
- package/template/wall-e/http/gws-api.js +4 -0
- package/template/wall-e/http/helper-rules-api.js +7 -1
- package/template/wall-e/http/model-admin.js +8 -1
- package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
- package/template/wall-e/http/model-proxy-providers.js +174 -1
- package/template/wall-e/http/model-route-health.js +157 -0
- package/template/wall-e/http/sync-api.js +278 -464
- package/template/wall-e/jobs/job-runner.js +28 -1
- package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
- package/template/wall-e/lib/ctm-data-dir.js +26 -0
- package/template/wall-e/lib/derivation-home.js +147 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
- package/template/wall-e/lib/helper-rules/grade.js +51 -8
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
- package/template/wall-e/lib/helper-rules/store.js +4 -2
- package/template/wall-e/lib/landing-mcp-tools.js +170 -0
- package/template/wall-e/lib/mcp-client-config.js +133 -14
- package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
- package/template/wall-e/lib/mcp-integration.js +58 -13
- package/template/wall-e/lib/parent-death.js +7 -1
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
- package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
- package/template/wall-e/llm/delegate-vendor-default.js +12 -5
- package/template/wall-e/llm/model-roles.js +1 -1
- package/template/wall-e/llm/native-delegate-selection.js +56 -8
- package/template/wall-e/llm/worker-delegate-args.js +72 -7
- package/template/wall-e/llm/worker-mcp-routing.js +66 -17
- package/template/wall-e/loops/brain-custom-writes.js +19 -0
- package/template/wall-e/loops/ingest.js +17 -1
- package/template/wall-e/loops/think.js +19 -4
- package/template/wall-e/mcp-contract.js +222 -6
- package/template/wall-e/mcp-protocol-contract.js +40 -5
- package/template/wall-e/mcp-server.js +128 -29
- package/template/wall-e/mcp-worker-schemas.js +5 -5
- package/template/wall-e/memory/ctm-context-client.js +85 -0
- package/template/wall-e/memory/ctm-session-context.js +9 -3
- package/template/wall-e/memory/hub-bridge-client.js +388 -0
- package/template/wall-e/memory/replica-origin.js +56 -0
- package/template/wall-e/memory/session-pool.js +135 -0
- package/template/wall-e/runtime/live-capabilities.js +8 -3
- package/template/wall-e/server.js +4 -2
- package/template/wall-e/shared/release-schema.json +2 -2
- package/template/wall-e/shared/sqlite-file-set.js +39 -0
- package/template/wall-e/shared/storage/contract.js +3 -0
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
- package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
- package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
- package/template/wall-e/tools/chrome-automation.js +6 -0
- package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
- package/template/wall-e/workers/brain-owner-worker.js +18 -4
- package/template/wall-e/workers/mcp-gateway-process.js +5 -5
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* §8 WP-2, §9 S-5.
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
+
const { moveToOwnScope } = require('./systemd-scope');
|
|
23
24
|
const path = require('node:path');
|
|
24
25
|
const crypto = require('node:crypto');
|
|
25
26
|
const { spawn } = require('node:child_process');
|
|
@@ -99,7 +100,7 @@ const PROXY_LIVENESS_MS = 10_000;
|
|
|
99
100
|
// recovery branch below, exactly as a SIGKILL of a spawned child is.
|
|
100
101
|
const ADOPTED_PID_GONE = 'ADOPTED_PID_GONE';
|
|
101
102
|
// The armed probe, or null. Module memory only: it is a live timer, and it is
|
|
102
|
-
// dropped on stop()/_resetForTest() and whenever the mode leaves 'adopted'.
|
|
103
|
+
// dropped on stop()/_resetForTest() and whenever the mode leaves 'child'/'adopted'.
|
|
103
104
|
let _livenessTimer = null;
|
|
104
105
|
// §6 test seam: the cadence a test can shrink, so AC-3a's 10 s bound is not a
|
|
105
106
|
// 10 s test. Production never writes it.
|
|
@@ -107,6 +108,9 @@ let _livenessProbeMs = PROXY_LIVENESS_MS;
|
|
|
107
108
|
// Set by stop() right before it kills the child, cleared by the child's 'exit'
|
|
108
109
|
// handler. A graceful stop must never trigger the lead-token auto-restart.
|
|
109
110
|
let _stopping = false;
|
|
111
|
+
// §5 D-1b: whether the last heartbeat renewal failed. Module memory only, so one stderr line marks each
|
|
112
|
+
// transition (ok->failed, failed->ok) rather than one per tick. Reset by _onProxyGone/stop/_resetForTest.
|
|
113
|
+
let _heartbeatFailing = false;
|
|
110
114
|
|
|
111
115
|
// WP-3 (§5 D-6): CTM-side mirror of the proxy's pick table. CTM pushes the full table
|
|
112
116
|
// on every delegate-pick mutation; start() replays it into a fresh child so the same
|
|
@@ -170,11 +174,14 @@ function isRunning() {
|
|
|
170
174
|
return _mode === 'adopted' || _mode === 'adopting';
|
|
171
175
|
}
|
|
172
176
|
|
|
173
|
-
// ── §5 D-6: liveness in
|
|
177
|
+
// ── §5 D-6/D-1: one liveness timer in BOTH modes ────────────────────────
|
|
174
178
|
// A proxy THIS CTM spawned reports its own death: the child handle has an 'exit' event. An ADOPTED proxy
|
|
175
179
|
// has no handle -- it is somebody else's process that outlived the CTM that started it -- so nothing but
|
|
176
|
-
// CTM's own probe can notice the pid going away.
|
|
177
|
-
//
|
|
180
|
+
// CTM's own probe can notice the pid going away. D-6 was adopted-only; D-1 arms the SAME single timer in
|
|
181
|
+
// both modes. Every tick is one authenticated admin read, and that read is what renews the proxy's own D-8
|
|
182
|
+
// linger lease (docs/model-proxy-linger-without-ctm-heartbeat-2026-10-27.html D-1): the adopted tick ALSO
|
|
183
|
+
// checks the pid first, and the child tick does not need to (its 'exit' event already owns that). Recovery
|
|
184
|
+
// on the other side is the same _onProxyGone() handler and the same one rate-limited restart.
|
|
178
185
|
|
|
179
186
|
function _clearLivenessProbe() {
|
|
180
187
|
if (_livenessTimer) clearTimeout(_livenessTimer);
|
|
@@ -187,27 +194,58 @@ function _setLivenessProbeMsForTest(ms) {
|
|
|
187
194
|
}
|
|
188
195
|
|
|
189
196
|
/**
|
|
190
|
-
* §5 D-
|
|
191
|
-
*
|
|
197
|
+
* §5 D-1: does `owner` -- the identity captured when the timer was armed -- still own this module? A
|
|
198
|
+
* stop(), a fresh spawn or a newer adoption reassigns the state, and the stale tick must then do nothing.
|
|
199
|
+
*/
|
|
200
|
+
function _ownsProbe(owner) {
|
|
201
|
+
return (_mode === 'child' && _child === owner) || (_mode === 'adopted' && _adopted === owner);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* §5 D-1: arm the ONE probe for the proxy currently owned -- the spawned child in 'child' mode, the
|
|
206
|
+
* adopted proxy in 'adopted' mode. Re-arming replaces the timer, so a call after a WP-2 handoff watches
|
|
207
|
+
* the SUCCESSOR's pid and not the predecessor's. No owner means no timer at all.
|
|
192
208
|
*/
|
|
193
209
|
function _armLivenessProbe({ port, dataDir }) {
|
|
194
210
|
_clearLivenessProbe();
|
|
195
|
-
|
|
196
|
-
|
|
211
|
+
const owner = _mode === 'child' ? _child : (_mode === 'adopted' ? _adopted : null);
|
|
212
|
+
if (!owner) return;
|
|
213
|
+
_livenessTimer = setTimeout(async () => {
|
|
197
214
|
_livenessTimer = null;
|
|
198
|
-
// Re-checked at fire time: a stop() or a newer adoption
|
|
199
|
-
if (
|
|
200
|
-
|
|
201
|
-
if (instanceRecord.isProcessAlive(pid)) {
|
|
202
|
-
|
|
215
|
+
// Re-checked at fire time: a stop(), a fresh spawn or a newer adoption owns the state now.
|
|
216
|
+
if (!_ownsProbe(owner)) return;
|
|
217
|
+
// §5 D-6: only the ADOPTED identity needs a pid check -- it is the one process nothing else reports on.
|
|
218
|
+
if (_mode === 'adopted' && !instanceRecord.isProcessAlive(_adopted.pid)) {
|
|
219
|
+
_onProxyGone({ code: null, signal: ADOPTED_PID_GONE, port, dataDir });
|
|
203
220
|
return;
|
|
204
221
|
}
|
|
205
|
-
|
|
222
|
+
const pid = _ownedPid();
|
|
223
|
+
// §5 D-1: the authenticated admin read IS the lease renewal; a failed read is reported, never fatal.
|
|
224
|
+
const ok = _adminSecret ? await _probeAdminSecretImpl({ port, secret: _adminSecret }) : false;
|
|
225
|
+
_noteHeartbeat({ ok, pid });
|
|
226
|
+
if (_ownsProbe(owner)) _armLivenessProbe({ port, dataDir });
|
|
206
227
|
}, _livenessProbeMs);
|
|
207
228
|
// §5 D-6: a probe is never a reason for CTM to stay alive.
|
|
208
229
|
_livenessTimer.unref();
|
|
209
230
|
}
|
|
210
231
|
|
|
232
|
+
/**
|
|
233
|
+
* §5 D-1b: report a heartbeat that stopped being answered, and one that started again -- each on its own
|
|
234
|
+
* transition only, so a long outage is one line and not one per tick. A failed renewal is NOT a death
|
|
235
|
+
* verdict: death is the child 'exit' event, or the adopted pid check above.
|
|
236
|
+
*/
|
|
237
|
+
function _noteHeartbeat({ ok, pid }) {
|
|
238
|
+
if (ok) {
|
|
239
|
+
if (!_heartbeatFailing) return;
|
|
240
|
+
_heartbeatFailing = false;
|
|
241
|
+
process.stderr.write(`[oauth-proxy-supervisor] proxy heartbeat recovered pid=${pid}\n`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (_heartbeatFailing) return;
|
|
245
|
+
_heartbeatFailing = true;
|
|
246
|
+
process.stderr.write(`[oauth-proxy-supervisor] proxy heartbeat failed pid=${pid}\n`);
|
|
247
|
+
}
|
|
248
|
+
|
|
211
249
|
/**
|
|
212
250
|
* §5 D-6: an admin call that cannot reach an ADOPTED proxy is the cheapest probe there is -- run the same
|
|
213
251
|
* test the timer runs, so a dead proxy is noticed now instead of on the next tick. Only the two codes that
|
|
@@ -377,20 +415,42 @@ async function _performUpgradeHandoff({ port }) {
|
|
|
377
415
|
handed = await requestHandoff({ port, reason: 'upgrade-pending' });
|
|
378
416
|
} catch (err) {
|
|
379
417
|
// REPORT: the old proxy is still serving; the next restart asks again.
|
|
380
|
-
|
|
418
|
+
const refusal = String((err && err.reason) || (err && err.message) || err).slice(0, 200);
|
|
419
|
+
process.stderr.write(`[oauth-proxy-supervisor] proxy handoff refused: ${refusal}\n`);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// §5 D-2 (WP-0 AC-0d): the 202 names the successor the PREDECESSOR proved it was waiting for, and only the
|
|
423
|
+
// process answering on the wire may be published as this adoption's identity or replayed into. A probe that
|
|
424
|
+
// names anybody else -- the draining predecessor still answering a connection it accepted before the handoff,
|
|
425
|
+
// or a foreign listener that took the port -- is a bounded refusal. Nothing is thrown or killed: a throw here
|
|
426
|
+
// would fall through _finishAdoption's catch into a fresh spawn over a successor already serving this port.
|
|
427
|
+
const successorHealth = await _probeHealth(port);
|
|
428
|
+
if (!successorHealth || successorHealth.pid !== handed.successorPid) {
|
|
429
|
+
const answeringPid = successorHealth && Number.isSafeInteger(successorHealth.pid) ? successorHealth.pid : null;
|
|
430
|
+
// The TYPED refusal is `_adopted.decision` plus the line below: `_finishAdoption` is the only caller and
|
|
431
|
+
// ignores a return value, so nothing is returned that could be mistaken for success. The acknowledged
|
|
432
|
+
// successor is still named TRUTHFULLY (it is the process the predecessor handed its sockets to, and the one
|
|
433
|
+
// the liveness probe must watch), but no closure identity is published, no replay is attempted, no retry is
|
|
434
|
+
// scheduled, and no handoff timing is reported (a null handoffMs reads as an adoption, never a handoff).
|
|
435
|
+
// Fail-closed: the adopted proxy keeps serving, and nothing is killed or spawned over it.
|
|
436
|
+
_adopted = {
|
|
437
|
+
..._adopted, pid: handed.successorPid, generation: handed.generation, handoffMs: null,
|
|
438
|
+
decision: 'upgrade-pending-unverified', closureHash: null,
|
|
439
|
+
};
|
|
440
|
+
process.stderr.write('[oauth-proxy-supervisor] proxy handoff unverified: successor_identity_mismatch'
|
|
441
|
+
+ ` expected_pid=${handed.successorPid} answering_pid=${answeringPid === null ? 'none' : answeringPid}\n`);
|
|
381
442
|
return;
|
|
382
443
|
}
|
|
383
444
|
// The successor loaded the code on disk, so the predecessor's closure hash is no longer this adoption's
|
|
384
445
|
// identity: status() and the restore_complete row must describe the process now answering. (WP-4 live
|
|
385
446
|
// proof, 2026-10-23: status reported the predecessor's hash after a handoff while /_health had the new one.)
|
|
386
|
-
const successorHealth = await _probeHealth(port);
|
|
387
447
|
_adopted = {
|
|
388
448
|
..._adopted,
|
|
389
449
|
pid: handed.successorPid,
|
|
390
450
|
generation: handed.generation,
|
|
391
451
|
handoffMs: handed.handoffMs,
|
|
392
452
|
decision: 'upgrade-pending',
|
|
393
|
-
closureHash: successorHealth
|
|
453
|
+
closureHash: successorHealth.closure_hash || null,
|
|
394
454
|
};
|
|
395
455
|
// The successor starts with the token table the predecessor handed over PLUS whatever CTM replays; the
|
|
396
456
|
// replay is the same idempotent call the fresh-spawn path makes, so a token cannot be double-registered.
|
|
@@ -464,6 +524,13 @@ function _spawnFresh({ port, resolvedDataDir }) {
|
|
|
464
524
|
// §5 D-1: CTM is never held open by the proxy it spawned -- the proxy outlives this process and the
|
|
465
525
|
// next CTM adopts it (D-4), so nothing here may wait on its exit.
|
|
466
526
|
_child.unref();
|
|
527
|
+
// WP-1 (S-4, session-host-cgroup-survival): on a systemd service host the proxy must leave ctm.service's cgroup
|
|
528
|
+
// or a restart reaps it. Not awaited (the proxy spawns no children); failure is REPORTED, never fatal.
|
|
529
|
+
moveToOwnScope(_child.pid, { label: 'oauth-proxy' }).then((moved) => {
|
|
530
|
+
if (!moved.moved && moved.reason !== 'not-systemd' && moved.reason !== 'disabled') {
|
|
531
|
+
process.stderr.write(`[host-scope] move failed host=oauth-proxy pid=${_child && _child.pid} reason=${moved.reason}\n`);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
467
534
|
// D-13: capture THIS spawn so a superseded child's late 'exit' (stop() -> start(), or a rapid
|
|
468
535
|
// restart) cannot null the current child's handle / admin secret out from under a fresh boot.
|
|
469
536
|
const child = _child;
|
|
@@ -477,6 +544,9 @@ function _spawnFresh({ port, resolvedDataDir }) {
|
|
|
477
544
|
// below is the authoritative signal, not this write.
|
|
478
545
|
_lastError = `admin secret handoff failed: ${err.message}`;
|
|
479
546
|
}
|
|
547
|
+
// §5 D-1a: arm the lease-renewal probe for THIS child, exactly as the adopted path arms its own. Armed
|
|
548
|
+
// after the secret write so the first tick already has a secret to authenticate with.
|
|
549
|
+
_armLivenessProbe({ port, dataDir: resolvedDataDir });
|
|
480
550
|
_startedAt = Date.now();
|
|
481
551
|
child.on('error', (err) => {
|
|
482
552
|
_lastError = err.message;
|
|
@@ -509,7 +579,11 @@ function _onProxyGone({ code, signal, port, dataDir }) {
|
|
|
509
579
|
// recovery either way; only the reaping differs, because the record a dead adopted pid left behind is
|
|
510
580
|
// stale truth that start() would otherwise have to discover by ps.
|
|
511
581
|
const adoptedPid = _mode === 'adopted' || _mode === 'adopting' ? (_adopted ? _adopted.pid : null) : null;
|
|
582
|
+
// §5 D-2: the pid the exit line names, captured before the state reset below.
|
|
583
|
+
const gonePid = _child ? _child.pid : adoptedPid;
|
|
512
584
|
_clearLivenessProbe();
|
|
585
|
+
// §5 D-1b: the next identity starts with a clean heartbeat verdict.
|
|
586
|
+
_heartbeatFailing = false;
|
|
513
587
|
if (adoptedPid !== null) {
|
|
514
588
|
process.stderr.write(`[oauth-proxy-supervisor] adopted proxy pid=${adoptedPid} gone\n`);
|
|
515
589
|
instanceRecord.unlinkInstanceRecord({ dataDir });
|
|
@@ -526,16 +600,21 @@ function _onProxyGone({ code, signal, port, dataDir }) {
|
|
|
526
600
|
// The dead child's in-memory token table is gone; any revoke that was still
|
|
527
601
|
// pending against it no longer has anything to reap.
|
|
528
602
|
_pendingLeadRevokes.clear();
|
|
529
|
-
// WP-0 (§6.2): an unexpected exit (signal, or a non-zero code) with live
|
|
530
|
-
// lead tokens must bring the proxy back so those tokens keep working. A
|
|
531
|
-
// graceful stop() opts out via _stopping; a crash-loop is rate-limited.
|
|
532
|
-
const unexpected = !!signal || code !== 0;
|
|
533
603
|
const wasStopping = _stopping;
|
|
534
604
|
_stopping = false;
|
|
535
605
|
// §9 S-5: the child records every SIGTERM exit, including the one a deliberate stop() sent. A stop
|
|
536
606
|
// is not a restart, so its record must not become the next start()'s "previous exit".
|
|
537
607
|
if (wasStopping) clearExitRecord({ dataDir });
|
|
538
|
-
|
|
608
|
+
// §5 D-2: with D-1 keeping the lease renewed, a linger under a live CTM is already a bug -- so a clean
|
|
609
|
+
// code-0 exit nobody asked for is reported as what it is (and recovered below like any other exit).
|
|
610
|
+
if (!wasStopping && code === 0 && !signal) {
|
|
611
|
+
_lastError = 'exited code=0 unrequested';
|
|
612
|
+
process.stderr.write(`[oauth-proxy-supervisor] proxy pid=${gonePid} exited code=0 without stop()\n`);
|
|
613
|
+
}
|
|
614
|
+
// WP-0 (§6.2) + §5 D-2: ANY exit stop() did not ask for -- clean or not -- with live lead tokens must
|
|
615
|
+
// bring the proxy back so those tokens keep working. A graceful stop() opts out via _stopping; a
|
|
616
|
+
// crash-loop is rate-limited.
|
|
617
|
+
if (!wasStopping && _leadTokens.size > 0) {
|
|
539
618
|
if (Date.now() - _lastLeadAutoRestartAt >= LEAD_RESTART_MIN_INTERVAL_MS) {
|
|
540
619
|
_lastLeadAutoRestartAt = Date.now();
|
|
541
620
|
// WP-1 §5 D-3: the restart is bound to the directory the DEAD child was actually running with,
|
|
@@ -552,6 +631,8 @@ function stop() {
|
|
|
552
631
|
const mode = _mode;
|
|
553
632
|
// §5 D-6: whatever happens below, this CTM is no longer watching that pid.
|
|
554
633
|
_clearLivenessProbe();
|
|
634
|
+
// §5 D-1b: a stopped CTM has no heartbeat verdict to carry into the next start().
|
|
635
|
+
_heartbeatFailing = false;
|
|
555
636
|
if (!isRunning()) {
|
|
556
637
|
_adminSecret = null;
|
|
557
638
|
_activeChildDataDir = null;
|
|
@@ -615,11 +696,10 @@ async function status({ port = DEFAULT_PORT } = {}) {
|
|
|
615
696
|
}
|
|
616
697
|
let health = null;
|
|
617
698
|
try {
|
|
618
|
-
|
|
619
|
-
signal: AbortSignal.timeout(2000),
|
|
620
|
-
});
|
|
621
|
-
if (resp.ok) health = await resp.json();
|
|
699
|
+
health = await _controlHealth(port, { signal: AbortSignal.timeout(2000) });
|
|
622
700
|
} catch (err) {
|
|
701
|
+
// §5 D-1: unchanged meaning -- only a network/protocol failure lands here; an unsuccessful status is a
|
|
702
|
+
// null health that leaves `_lastError` alone, and the helper releases its body either way.
|
|
623
703
|
_lastError = `health probe failed: ${err.message}`;
|
|
624
704
|
}
|
|
625
705
|
// Never include the admin secret here — status() is a diagnostics surface
|
|
@@ -695,11 +775,41 @@ function hasLiveSurvivor({ port = DEFAULT_PORT, dataDir } = {}) {
|
|
|
695
775
|
return !!record && record.port === port && instanceRecord.isProxyProcess(record.pid);
|
|
696
776
|
}
|
|
697
777
|
|
|
778
|
+
// §5 D-1 (WP-0 AC-0b, docs/native-owner-restart-handoff-2026-10-26.html): every supervisor CONTROL request is
|
|
779
|
+
// one-use. Fetch's `keepalive:false` is unrelated; the HTTP `Connection: close` header is what undici honours
|
|
780
|
+
// by giving the request its own closed-when-done connection. Without it the pool can hand a later control
|
|
781
|
+
// request the socket opened against the PREDECESSOR, which stops ACCEPTING on a handoff but keeps answering
|
|
782
|
+
// connections it already accepted (`closeIdleConnections()` cannot close one still serving the handoff
|
|
783
|
+
// response). INFERENCE, not packet-level observation: that reuse is how the native-owner replay lands in the
|
|
784
|
+
// draining process while the successor holding the port never learns the owner -- what the live 00:47:11Z
|
|
785
|
+
// `native_lead_listener_closed` + 401 `native_owner_unknown` sequence looks like outside, reproduced in
|
|
786
|
+
// `.scratch/native-owner/socket-handoff.cjs`. Lifecycle traffic only: no dispatcher, flag or retry.
|
|
787
|
+
const CONTROL_HEADERS = Object.freeze({ connection: 'close' });
|
|
788
|
+
|
|
789
|
+
// §5 D-1: release the body of a control response this call is not going to read, so neither a reader nor
|
|
790
|
+
// its socket outlives the call. Already-consumed bodies and 204/304 (`body` null) are simply nothing to do.
|
|
791
|
+
async function _releaseControlResponse(resp) {
|
|
792
|
+
if (!resp || !resp.body || resp.bodyUsed) return;
|
|
793
|
+
try { await resp.body.cancel(); } catch { /* expected: consumed, already cancelled, or the peer is gone */ }
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// §5 D-1: the `/_health` control request shared by the two callers wanting its parsed body (`_probeHealth`,
|
|
797
|
+
// `status()`). A non-ok status answers `null`; a dead proxy or malformed body THROWS, so each caller keeps its
|
|
798
|
+
// own meaning for that failure (a refused adoption, or `status()`'s `_lastError`).
|
|
799
|
+
async function _controlHealth(port, init) {
|
|
800
|
+
let resp = null;
|
|
801
|
+
try {
|
|
802
|
+
resp = await fetch(`http://127.0.0.1:${port}/_health`, { headers: CONTROL_HEADERS, ...init });
|
|
803
|
+
return resp.ok ? await resp.json() : null;
|
|
804
|
+
} finally {
|
|
805
|
+
await _releaseControlResponse(resp);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
698
809
|
/** §5 D-4 step 4: the health probe the adoption decision reads, with its own 2 s budget. */
|
|
699
810
|
async function _probeHealth(port, timeoutMs = 2000) {
|
|
700
811
|
try {
|
|
701
|
-
|
|
702
|
-
return resp.ok ? await resp.json() : null;
|
|
812
|
+
return await _controlHealth(port, { signal: AbortSignal.timeout(timeoutMs) });
|
|
703
813
|
} catch (err) {
|
|
704
814
|
// expected: an unreachable proxy is a refused adoption, never a thrown boot
|
|
705
815
|
void err;
|
|
@@ -711,9 +821,10 @@ async function _probeHealth(port, timeoutMs = 2000) {
|
|
|
711
821
|
async function _probeAdminSecret({ port, secret, timeoutMs = 2000 }) {
|
|
712
822
|
try {
|
|
713
823
|
const resp = await fetch(`http://127.0.0.1:${port}/_admin/lead-worker-picks`, {
|
|
714
|
-
headers: { [ADMIN_HEADER]: secret },
|
|
824
|
+
headers: { ...CONTROL_HEADERS, [ADMIN_HEADER]: secret },
|
|
715
825
|
signal: AbortSignal.timeout(timeoutMs),
|
|
716
826
|
});
|
|
827
|
+
await _releaseControlResponse(resp);
|
|
717
828
|
return resp.ok;
|
|
718
829
|
} catch (err) {
|
|
719
830
|
// expected: an unreachable proxy cannot confirm the secret; the caller falls back to a spawn
|
|
@@ -722,6 +833,14 @@ async function _probeAdminSecret({ port, secret, timeoutMs = 2000 }) {
|
|
|
722
833
|
}
|
|
723
834
|
}
|
|
724
835
|
|
|
836
|
+
// §6 test seam: the D-1 renewal request itself. Injectable so a case can count heartbeats without touching
|
|
837
|
+
// the proxy. Production never calls the setter; _resetForTest restores it.
|
|
838
|
+
let _probeAdminSecretImpl = _probeAdminSecret;
|
|
839
|
+
|
|
840
|
+
function _setProbeAdminSecretForTest(fn) {
|
|
841
|
+
_probeAdminSecretImpl = typeof fn === 'function' ? fn : _probeAdminSecret;
|
|
842
|
+
}
|
|
843
|
+
|
|
725
844
|
// ── D-8 readiness ────────────────────────────────────────────────────────
|
|
726
845
|
// Polls /_health every ~100ms until it answers ok or the deadline passes.
|
|
727
846
|
// A single fetch is not enough here: during the child's cold start (just
|
|
@@ -757,8 +876,10 @@ async function _pollHealth({ port = DEFAULT_PORT, timeoutMs = 2000, signal } = {
|
|
|
757
876
|
const probeTimeout = Math.max(1, Math.min(500, remaining));
|
|
758
877
|
try {
|
|
759
878
|
const resp = await fetch(`http://127.0.0.1:${port}/_health`, {
|
|
879
|
+
headers: CONTROL_HEADERS,
|
|
760
880
|
signal: signal ? AbortSignal.any([AbortSignal.timeout(probeTimeout), signal]) : AbortSignal.timeout(probeTimeout),
|
|
761
881
|
});
|
|
882
|
+
await _releaseControlResponse(resp);
|
|
762
883
|
if (resp.ok) return true;
|
|
763
884
|
} catch {
|
|
764
885
|
// expected: connection refused during cold start, or the probe's own
|
|
@@ -787,6 +908,7 @@ async function _adminRequest({ port = DEFAULT_PORT, method, path: adminPath, bod
|
|
|
787
908
|
resp = await fetch(`http://127.0.0.1:${port}${adminPath}`, {
|
|
788
909
|
method,
|
|
789
910
|
headers: {
|
|
911
|
+
...CONTROL_HEADERS,
|
|
790
912
|
'Content-Type': 'application/json',
|
|
791
913
|
[ADMIN_HEADER]: _adminSecret,
|
|
792
914
|
},
|
|
@@ -802,6 +924,7 @@ async function _adminRequest({ port = DEFAULT_PORT, method, path: adminPath, bod
|
|
|
802
924
|
if (returnHttpErrors) {
|
|
803
925
|
let errorBody = null;
|
|
804
926
|
try { errorBody = await resp.json(); } catch { /* expected: an empty or non-JSON rejection */ }
|
|
927
|
+
await _releaseControlResponse(resp);
|
|
805
928
|
return errorBody && typeof errorBody === 'object'
|
|
806
929
|
? { ...errorBody, http_status: resp.status }
|
|
807
930
|
: { error: 'admin_request_failed', http_status: resp.status };
|
|
@@ -814,13 +937,18 @@ async function _adminRequest({ port = DEFAULT_PORT, method, path: adminPath, bod
|
|
|
814
937
|
// expected: a non-JSON error body (e.g. plain 401 text) — the status-based
|
|
815
938
|
// reason above is enough.
|
|
816
939
|
}
|
|
940
|
+
await _releaseControlResponse(resp);
|
|
817
941
|
throw new ProxyAdminError('admin_request_failed', reason);
|
|
818
942
|
}
|
|
819
943
|
const len = resp.headers.get('content-length');
|
|
820
|
-
if (resp.status === 204 || len === '0')
|
|
944
|
+
if (resp.status === 204 || len === '0') {
|
|
945
|
+
await _releaseControlResponse(resp);
|
|
946
|
+
return null;
|
|
947
|
+
}
|
|
821
948
|
try {
|
|
822
949
|
return await resp.json();
|
|
823
950
|
} catch {
|
|
951
|
+
await _releaseControlResponse(resp);
|
|
824
952
|
return null;
|
|
825
953
|
}
|
|
826
954
|
}
|
|
@@ -1035,7 +1163,7 @@ function _leadEntryKey(entry) {
|
|
|
1035
1163
|
nativeCertFingerprint: native ? (entry.nativeCertFingerprint || null) : null,
|
|
1036
1164
|
// The public settings locator is identity for the same reason: the same token may not silently start
|
|
1037
1165
|
// pointing at a different reserved directory.
|
|
1038
|
-
nativeSettingsRef: native ? (entry.nativeSettingsRef || null) : null,
|
|
1166
|
+
nativeSettingsRef: native ? (entry.nativeSettingsRef || null) : null, usageLog: entry.usageLog || null, // WP-9 L-2: the usage mark is identity
|
|
1039
1167
|
});
|
|
1040
1168
|
}
|
|
1041
1169
|
|
|
@@ -1057,14 +1185,14 @@ async function _flushPendingLeadRevokes({ port = DEFAULT_PORT } = {}) {
|
|
|
1057
1185
|
|
|
1058
1186
|
function _normalizeLeadRegistration({ ctmSessionId, aliases, bindings, processGeneration, transitionId,
|
|
1059
1187
|
purpose = 'routed-primary', delegateScope = false, harness, providerThreadId, nativeTransport,
|
|
1060
|
-
nativeCertFingerprint, nativeSettingsRef } = {}) {
|
|
1188
|
+
nativeCertFingerprint, nativeSettingsRef, usageLog } = {}) {
|
|
1061
1189
|
if (typeof ctmSessionId !== 'string' || !SAFE_LEAD_OWNER_ID.test(ctmSessionId)
|
|
1062
1190
|
|| !Array.isArray(aliases) || aliases.length === 0 || aliases.length > 64
|
|
1063
1191
|
|| aliases.some((alias) => !_safeLeadDeploymentId(alias))
|
|
1064
1192
|
|| new Set(aliases).size !== aliases.length
|
|
1065
1193
|
|| !Number.isSafeInteger(processGeneration) || processGeneration < 1
|
|
1066
1194
|
|| typeof delegateScope !== 'boolean') return null;
|
|
1067
|
-
if (purpose !== 'routed-primary' && purpose !== 'native-claude-passthrough') return null;
|
|
1195
|
+
if (purpose !== 'routed-primary' && purpose !== 'native-claude-passthrough') return null; if (usageLog != null && (usageLog !== 'dsh' || purpose !== 'routed-primary')) return null; // WP-9 L-2 (D-19): dsh usage mark, routed leads only
|
|
1068
1196
|
if (nativeTransport != null && !LEAD_NATIVE_TRANSPORTS.includes(nativeTransport)) return null;
|
|
1069
1197
|
if (nativeCertFingerprint != null
|
|
1070
1198
|
&& (typeof nativeCertFingerprint !== 'string' || !LEAD_NATIVE_CERT_FINGERPRINT_RE.test(nativeCertFingerprint))) return null;
|
|
@@ -1116,7 +1244,7 @@ function _normalizeLeadRegistration({ ctmSessionId, aliases, bindings, processGe
|
|
|
1116
1244
|
if (providerThreadId != null && (typeof providerThreadId !== 'string' || !SAFE_LEAD_OWNER_ID.test(providerThreadId))) return null;
|
|
1117
1245
|
return { ctmSessionId, aliases: [...aliases], bindings: normalizedBindings, processGeneration,
|
|
1118
1246
|
purpose, delegateScope, ...(normalizedHarness ? { harness: normalizedHarness } : {}), ...(providerThreadId ? { providerThreadId } : {}),
|
|
1119
|
-
...(transitionId != null ? { transitionId } : {}) };
|
|
1247
|
+
...(transitionId != null ? { transitionId } : {}), ...(usageLog ? { usageLog } : {}) };
|
|
1120
1248
|
}
|
|
1121
1249
|
|
|
1122
1250
|
async function registerLeadToken(registration = {}) {
|
|
@@ -1332,14 +1460,14 @@ async function probeRoute(alias, { timeoutMs = 2000, port = DEFAULT_PORT, signal
|
|
|
1332
1460
|
// Generation readiness is stronger than probeRoute() reachability: it sends one fixed,
|
|
1333
1461
|
// minimal inference through the provider's configured wire and returns the proxy's
|
|
1334
1462
|
// normalized receipt. Admission release remains a caller responsibility.
|
|
1335
|
-
async function probeRouteGeneration(alias, { model, timeoutMs = 30_000, port = DEFAULT_PORT } = {}) {
|
|
1463
|
+
async function probeRouteGeneration(alias, { model, timeoutMs = 30_000, port = DEFAULT_PORT, face } = {}) {
|
|
1336
1464
|
const requestedTimeout = Number(timeoutMs);
|
|
1337
1465
|
const cappedTimeout = Math.max(1, Math.min(Number.isFinite(requestedTimeout) && requestedTimeout > 0 ? requestedTimeout : 30_000, 30_000));
|
|
1338
1466
|
return _adminRequest({
|
|
1339
1467
|
port,
|
|
1340
1468
|
method: 'POST',
|
|
1341
1469
|
path: `/_admin/routes/${encodeURIComponent(alias)}/generation-probe`,
|
|
1342
|
-
body: { model, timeoutMs: cappedTimeout },
|
|
1470
|
+
body: { model, timeoutMs: cappedTimeout, ...(typeof face === 'string' ? { face } : {}) },
|
|
1343
1471
|
timeoutMs: cappedTimeout + 1000,
|
|
1344
1472
|
returnHttpErrors: true,
|
|
1345
1473
|
});
|
|
@@ -1364,8 +1492,10 @@ function _resetForTest() {
|
|
|
1364
1492
|
_pendingLeadRevokes.clear();
|
|
1365
1493
|
_leadWorkerPicks = [];
|
|
1366
1494
|
_hashClosureFiles = hashClosureFiles;
|
|
1495
|
+
_probeAdminSecretImpl = _probeAdminSecret;
|
|
1367
1496
|
_clearLivenessProbe();
|
|
1368
1497
|
_livenessProbeMs = PROXY_LIVENESS_MS;
|
|
1498
|
+
_heartbeatFailing = false;
|
|
1369
1499
|
}
|
|
1370
1500
|
|
|
1371
1501
|
module.exports = {
|
|
@@ -1411,6 +1541,13 @@ module.exports = {
|
|
|
1411
1541
|
// §5 D-6/§6: shrink the adopted-mode probe cadence so a liveness case does not take 10 s (and so
|
|
1412
1542
|
// AC-3a's own bound can be checked against production's constant, which is exported beside it).
|
|
1413
1543
|
_setLivenessProbeMsForTest,
|
|
1544
|
+
// §5 D-1/D-1b (§6): the armed timer (read-only) and the renewal request the probe sends, so a case can
|
|
1545
|
+
// assert one timer is ever armed and count heartbeats without touching the proxy. Production never
|
|
1546
|
+
// calls the setter; the real implementation is exported beside it so a wrapper can call through.
|
|
1547
|
+
get _livenessTimer() { return _livenessTimer; },
|
|
1548
|
+
get _heartbeatFailing() { return _heartbeatFailing; },
|
|
1549
|
+
_probeAdminSecret,
|
|
1550
|
+
_setProbeAdminSecretForTest,
|
|
1414
1551
|
// §5 D-7/§6 (AC-2f): make the disk-side closure hash disagree, so the adoption decision reads
|
|
1415
1552
|
// `upgrade-pending` and the handoff path runs, without editing source. Pass null to restore.
|
|
1416
1553
|
_setHashClosureFilesForTest,
|
|
@@ -13,6 +13,7 @@ function workerError(payload) {
|
|
|
13
13
|
function createOnlineBackupRunner(options = {}) {
|
|
14
14
|
const getDbPath = options.getDbPath;
|
|
15
15
|
const getBackupDir = options.getBackupDir;
|
|
16
|
+
const getRetentionDays = options.getRetentionDays;
|
|
16
17
|
const WorkerClass = options.WorkerClass || Worker;
|
|
17
18
|
const workerPath = options.workerPath || path.join(__dirname, '..', 'workers', 'online-backup-worker.js');
|
|
18
19
|
const timeoutMs = Math.max(1000, Number(options.timeoutMs || 15 * 60 * 1000));
|
|
@@ -46,6 +47,7 @@ function createOnlineBackupRunner(options = {}) {
|
|
|
46
47
|
dbPath,
|
|
47
48
|
backupDir,
|
|
48
49
|
label: String(meta.label || 'manual'),
|
|
50
|
+
retentionDays: typeof getRetentionDays === 'function' ? Number(getRetentionDays()) : undefined,
|
|
49
51
|
},
|
|
50
52
|
env: { ...process.env },
|
|
51
53
|
});
|