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
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-1 (docs/park-draft-truth-from-screen-2026-10-26.html §5 D-1/D-2/D-3) — the park decision's
|
|
4
|
+
// draft truth is the agent's own composer row, read from the server's headless mirror, not the
|
|
5
|
+
// browser's keystroke accounting. `lifecycle-draft` presence never produces a `draft` protection
|
|
6
|
+
// any more (that phantom refused parks and lead model switches on an empty composer).
|
|
7
|
+
//
|
|
8
|
+
// The verdict reuses `composerState` (lib/terminal-composer.js) unchanged: one glyph rule for the
|
|
9
|
+
// phone path and the park path alike (D-2). The verdict carries only a length, never the text.
|
|
10
|
+
|
|
11
|
+
const { composerState } = require('./terminal-composer');
|
|
12
|
+
|
|
13
|
+
/** @typedef {'text'|'empty'|'unknown'} ComposerDraftState */
|
|
14
|
+
/** @typedef {'composer-text'|'composer-empty'|'rows-unavailable'|'no-composer-row'|'rows-error'} ComposerDraftReason */
|
|
15
|
+
/** @typedef {{ state: ComposerDraftState, reason: ComposerDraftReason, chars: number, at: number }} ComposerDraftVerdict */
|
|
16
|
+
|
|
17
|
+
// Same bound as server.js's Submit-current-input probe (~16548).
|
|
18
|
+
const PARK_COMPOSER_READ_TIMEOUT_MS = 900;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Pure. `rows === null|undefined` (not a row list) is unreadable; a row list with no composer row
|
|
22
|
+
* is unreadable for a different reason. Only visible, non-dim composer text is a draft.
|
|
23
|
+
* @param {Array<{text: string, wrapped: boolean, dim: boolean}>|null|undefined} rows
|
|
24
|
+
* @param {number} [now]
|
|
25
|
+
* @returns {ComposerDraftVerdict}
|
|
26
|
+
*/
|
|
27
|
+
function composerDraftVerdict(rows, now = Date.now()) {
|
|
28
|
+
if (!Array.isArray(rows)) return { state: 'unknown', reason: 'rows-unavailable', chars: 0, at: now };
|
|
29
|
+
const composer = composerState(rows);
|
|
30
|
+
if (composer.row === -1) return { state: 'unknown', reason: 'no-composer-row', chars: 0, at: now };
|
|
31
|
+
if (composer.empty) return { state: 'empty', reason: 'composer-empty', chars: 0, at: now };
|
|
32
|
+
return { state: 'text', reason: 'composer-text', chars: composer.text.length, at: now };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Never throws. Flushes the mirror's feed first (so text typed in the last milliseconds is in the
|
|
37
|
+
* rows) and reads them through the caller's bounded reader. Any failure — flush, worker, timeout —
|
|
38
|
+
* is the single `unknown` state, never a phantom draft.
|
|
39
|
+
* @param {{id?: string, _flushHeadlessFeed?: Function}|null|undefined} session
|
|
40
|
+
* @param {{getRows?: (sessionId: string, timeoutMs: number) => Promise<Array|null>, timeoutMs?: number, now?: () => number}} [options]
|
|
41
|
+
* @returns {Promise<ComposerDraftVerdict>}
|
|
42
|
+
*/
|
|
43
|
+
async function readComposerDraft(session, { getRows, timeoutMs = PARK_COMPOSER_READ_TIMEOUT_MS, now = Date.now } = {}) {
|
|
44
|
+
try {
|
|
45
|
+
if (session && typeof session._flushHeadlessFeed === 'function') session._flushHeadlessFeed();
|
|
46
|
+
const rows = await getRows(session && session.id, timeoutMs);
|
|
47
|
+
return composerDraftVerdict(rows, now());
|
|
48
|
+
} catch {
|
|
49
|
+
// HANDLE: an unreadable screen is 'unknown' (D-4) — automatic parks wait, manual parks proceed.
|
|
50
|
+
return { state: 'unknown', reason: 'rows-error', chars: 0, at: now() };
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module.exports = { composerDraftVerdict, readComposerDraft, PARK_COMPOSER_READ_TIMEOUT_MS };
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
// already acts on (lib/session-restore.js). No flags.
|
|
10
10
|
|
|
11
11
|
const CLAUDE_RESUME_FORMS = new Set(['--resume', '-r', '--continue', '-c']);
|
|
12
|
+
// OpenCode 1.x's own resume selectors (docs/opencode-lead-and-delegate-model-selection-2026-10-28.html
|
|
13
|
+
// §9 S-7, R-2). A stored argv that already names a conversation is NOT a fresh launch: relaunching it
|
|
14
|
+
// with `--model` would be ignored by TUI 1.x (the last user message wins, §5 R-4), so it is refused.
|
|
15
|
+
const OPENCODE_RESUME_FORMS = new Set(['--session', '-s', '--continue', '-c']);
|
|
12
16
|
|
|
13
17
|
/**
|
|
14
18
|
* The launch args a fresh relaunch runs, or null when today's resume path must stand.
|
|
@@ -21,6 +25,13 @@ function freshRelaunchArgs({ agentType, storedTask, sessionCmd, sessionId, resum
|
|
|
21
25
|
const args = storedTask.args.slice();
|
|
22
26
|
if (agentType === 'codex') {
|
|
23
27
|
if (args[0] === 'resume') return null;
|
|
28
|
+
} else if (agentType === 'opencode') {
|
|
29
|
+
// No `--session-id` injection for OpenCode: CTM cannot mint an OpenCode session id on 1.x
|
|
30
|
+
// (probe P-10), so the stored args are copied EXACTLY.
|
|
31
|
+
for (const arg of args) {
|
|
32
|
+
const text = String(arg);
|
|
33
|
+
if (OPENCODE_RESUME_FORMS.has(text) || text.startsWith('--session=')) return null;
|
|
34
|
+
}
|
|
24
35
|
} else {
|
|
25
36
|
for (const arg of args) {
|
|
26
37
|
if (CLAUDE_RESUME_FORMS.has(arg)) return null;
|
|
@@ -35,17 +46,41 @@ function freshRelaunchArgs({ agentType, storedTask, sessionCmd, sessionId, resum
|
|
|
35
46
|
/**
|
|
36
47
|
* Whether park should relaunch fresh: the off-thread ladder says 'fresh' when nothing exists to
|
|
37
48
|
* resume. False for any other provider; for Claude an empty jsonlPath is nothing to look up.
|
|
38
|
-
*
|
|
49
|
+
* OpenCode 1.x has no ladder to consult at all: it creates its session on the first prompt (probe
|
|
50
|
+
* P-9), so "nothing to resume" is exactly "no captured resume id".
|
|
51
|
+
* @param {{ agentType: string, ctmSessionId: string, jsonlPath: string, resumeId?: string,
|
|
39
52
|
* resolveRung: (input: { ctmSessionId: string, provider: string, jsonlPath: string }) => Promise<{ rung: string }> }} input
|
|
40
53
|
* @returns {Promise<boolean>}
|
|
41
54
|
*/
|
|
42
|
-
async function parkFindsNothingToResume({ agentType, ctmSessionId, jsonlPath, resolveRung }) {
|
|
55
|
+
async function parkFindsNothingToResume({ agentType, ctmSessionId, jsonlPath, resumeId, resolveRung }) {
|
|
56
|
+
if (agentType === 'opencode') return !resumeId;
|
|
43
57
|
if (agentType !== 'claude' && agentType !== 'codex') return false;
|
|
44
58
|
if (agentType === 'claude' && !jsonlPath) return false;
|
|
45
59
|
const result = await resolveRung({ ctmSessionId, provider: agentType, jsonlPath: jsonlPath || '' });
|
|
46
60
|
return result?.rung === 'fresh';
|
|
47
61
|
}
|
|
48
62
|
|
|
63
|
+
/**
|
|
64
|
+
* D-5 in ONE place: the resume-evidence flag and the jsonlPath the ladder is asked about, derived
|
|
65
|
+
* from the prepared transcript/codex rollout. Shared with lib/lead-switch-history-mode.js, which
|
|
66
|
+
* must never grow a second copy of this rule (WP-0/§6 "one definition").
|
|
67
|
+
* @param {{ agentType: string, transcript?: object|null, codexRolloutPath?: string }} input
|
|
68
|
+
* @returns {{ resumeEvidence: boolean, jsonlPath: string }}
|
|
69
|
+
*/
|
|
70
|
+
function freshEvidenceInputs({ agentType, transcript, codexRolloutPath }) {
|
|
71
|
+
// A transcript/rollout file on disk means there is something to resume (and Claude refuses a
|
|
72
|
+
// `--session-id` whose .jsonl exists), so the ladder is consulted only when none exists.
|
|
73
|
+
// OpenCode has neither: its "something to resume" question is answered from the captured resume
|
|
74
|
+
// id alone (see parkFindsNothingToResume), so a null/undefined transcript is NOT evidence here.
|
|
75
|
+
const resumeEvidence = agentType === 'opencode'
|
|
76
|
+
? false
|
|
77
|
+
: agentType === 'codex' ? !!codexRolloutPath : !!(transcript && transcript.missing === false);
|
|
78
|
+
const jsonlPath = agentType === 'codex'
|
|
79
|
+
? (codexRolloutPath || '')
|
|
80
|
+
: (transcript && (transcript.filePath || (Array.isArray(transcript.candidates) ? transcript.candidates[0] : '')));
|
|
81
|
+
return { resumeEvidence, jsonlPath: jsonlPath || '' };
|
|
82
|
+
}
|
|
83
|
+
|
|
49
84
|
/**
|
|
50
85
|
* Compose D-5 (jsonlPath from the transcript/codex rollout), the ladder check, and the fresh args.
|
|
51
86
|
* Never throws: a ladder or DB error is reported through `diagnostic` and yields null.
|
|
@@ -57,13 +92,9 @@ async function parkFindsNothingToResume({ agentType, ctmSessionId, jsonlPath, re
|
|
|
57
92
|
*/
|
|
58
93
|
async function planFreshRelaunch({ session, agentType, resumeId, transcript, codexRolloutPath, storedTask, resolveRung, diagnostic }) {
|
|
59
94
|
try {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
const jsonlPath = agentType === 'codex'
|
|
64
|
-
? (codexRolloutPath || '')
|
|
65
|
-
: (transcript && (transcript.filePath || (Array.isArray(transcript.candidates) ? transcript.candidates[0] : '')));
|
|
66
|
-
const nothingToResume = await parkFindsNothingToResume({ agentType, ctmSessionId: session.id, jsonlPath, resolveRung });
|
|
95
|
+
const { resumeEvidence, jsonlPath } = freshEvidenceInputs({ agentType, transcript, codexRolloutPath });
|
|
96
|
+
if (resumeEvidence) return null;
|
|
97
|
+
const nothingToResume = await parkFindsNothingToResume({ agentType, ctmSessionId: session.id, jsonlPath, resumeId, resolveRung });
|
|
67
98
|
if (!nothingToResume) return null;
|
|
68
99
|
return freshRelaunchArgs({ agentType, storedTask, sessionCmd: session.cmd || '', sessionId: session.id, resumeId });
|
|
69
100
|
} catch (err) {
|
|
@@ -73,4 +104,4 @@ async function planFreshRelaunch({ session, agentType, resumeId, transcript, cod
|
|
|
73
104
|
}
|
|
74
105
|
}
|
|
75
106
|
|
|
76
|
-
module.exports = { freshRelaunchArgs, parkFindsNothingToResume, planFreshRelaunch };
|
|
107
|
+
module.exports = { freshRelaunchArgs, parkFindsNothingToResume, freshEvidenceInputs, planFreshRelaunch };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Phase trace for one synchronous scan run (WP-0 / M-3, measurement only —
|
|
4
|
+
// docs/hub-local-cpu-memory-burn-2026-10-31.html §7). Used by session-integrity.js
|
|
5
|
+
// (detectMismatches) and lib/relink-audit.js (auditRelink): on the hub the
|
|
6
|
+
// sessionIntegrityDetect op outlives its caller's timeout and the result is discarded, so the
|
|
7
|
+
// `[session-integrity] phases {...}` line each scan logs at its end is the only record.
|
|
8
|
+
//
|
|
9
|
+
// Gated by CTM_PERF_ATTRIBUTION (on by default; '0'/'false'/'no'/'off' → createPerfTrace()
|
|
10
|
+
// returns null and callers record nothing). Cost: one performance.now() per lap. Memory is
|
|
11
|
+
// bounded by the caller's fixed set of phase/counter names, never by row count.
|
|
12
|
+
|
|
13
|
+
const { boolFlag } = require('./env-flags');
|
|
14
|
+
|
|
15
|
+
const NOOP_LAP = () => {};
|
|
16
|
+
|
|
17
|
+
function perfNow() {
|
|
18
|
+
return performance.now();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createPerfTrace() {
|
|
22
|
+
if (!boolFlag('CTM_PERF_ATTRIBUTION', true)) return null;
|
|
23
|
+
const start = perfNow();
|
|
24
|
+
const trace = { t0: start, t: start, phases: Object.create(null), counters: Object.create(null) };
|
|
25
|
+
// lap(name, n): closes the open segment and charges it to `name`, then opens the next one —
|
|
26
|
+
// so the laps of a run partition its wall time and sum(phases.ms) == totalMs.
|
|
27
|
+
trace.lap = (name, n = 1) => {
|
|
28
|
+
const now = perfNow();
|
|
29
|
+
const phase = trace.phases[name] || (trace.phases[name] = { ms: 0, n: 0 });
|
|
30
|
+
phase.ms += now - trace.t;
|
|
31
|
+
phase.n += n;
|
|
32
|
+
trace.t = now;
|
|
33
|
+
};
|
|
34
|
+
// count(name, ms, n): an overlapping sub-measurement of a call already inside a lap
|
|
35
|
+
// (e.g. findCodexSessionFiles). Kept apart so it can never distort the phase sum.
|
|
36
|
+
trace.count = (name, ms, n = 1) => {
|
|
37
|
+
const counter = trace.counters[name] || (trace.counters[name] = { ms: 0, n: 0 });
|
|
38
|
+
counter.ms += ms;
|
|
39
|
+
counter.n += n;
|
|
40
|
+
};
|
|
41
|
+
// timed(name, fn): runs fn and records it under counters[name].
|
|
42
|
+
trace.timed = (name, fn) => {
|
|
43
|
+
const started = perfNow();
|
|
44
|
+
try {
|
|
45
|
+
return fn();
|
|
46
|
+
} finally {
|
|
47
|
+
trace.count(name, perfNow() - started, 1);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
return trace;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function _round(value) {
|
|
54
|
+
return Math.round(value * 10) / 10;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function _roundMap(map) {
|
|
58
|
+
const out = {};
|
|
59
|
+
for (const [name, entry] of Object.entries(map)) out[name] = { ms: _round(entry.ms), n: entry.n };
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function perfPhasesJson(scope, trace) {
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
scope,
|
|
66
|
+
totalMs: _round(perfNow() - trace.t0),
|
|
67
|
+
phases: _roundMap(trace.phases),
|
|
68
|
+
counters: _roundMap(trace.counters),
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = { NOOP_LAP, createPerfTrace, perfPhasesJson };
|
|
@@ -194,6 +194,13 @@ function buildPerfSummary(input = {}) {
|
|
|
194
194
|
syncIo,
|
|
195
195
|
wal: input.wal || null,
|
|
196
196
|
workers: { dbOwner, readPool },
|
|
197
|
+
// WP-0 M-1 (§7): CPU per main-thread timer, { [namedInterval]: { count, userMs, systemMs } }.
|
|
198
|
+
// Empty object when CTM_PERF_ATTRIBUTION=0 or no named timer has ticked yet.
|
|
199
|
+
mainTimers: { cpuByTimer: input.mainTimers?.cpuByTimer || {} },
|
|
200
|
+
// WP-0 M-2 (§3.2/§7): per-reason session-list broadcast counters, { [reason]: { calls,
|
|
201
|
+
// suppressed, coalesced, flushes, serialized, elided } } — see lib/broadcast-reason-stats.js.
|
|
202
|
+
// Empty object when CTM_PERF_ATTRIBUTION=0.
|
|
203
|
+
broadcast: { byReason: input.broadcast?.byReason || {} },
|
|
197
204
|
insertChunkHoldMs: dbOwner?.insertChunkHoldMs || null,
|
|
198
205
|
writeLock: input.writeLock || null,
|
|
199
206
|
mainWriteEscapes: input.mainWriteEscapes || null,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { AsyncLocalStorage } = require('node:async_hooks');
|
|
4
4
|
const path = require('node:path');
|
|
5
|
+
const { boolFlag } = require('./env-flags');
|
|
5
6
|
|
|
6
7
|
// Tiny shared module for tagging the current synchronous operation. The
|
|
7
8
|
// always-on event-loop lag detector reads `getOp()` to identify what was
|
|
@@ -296,6 +297,11 @@ function _hostCores() {
|
|
|
296
297
|
|
|
297
298
|
function buildEventLoopBlockEvidence(previous = {}, current = {}, options = {}) {
|
|
298
299
|
const blockedMs = Math.max(1, Number(options.blockedMs) || 1);
|
|
300
|
+
// WP-2 (design §5 D-6 / §9 S-5..S-7): the watchdog worker's own measured suspension
|
|
301
|
+
// overlap. It is the one observation a suspended process cannot fake — the worker thread
|
|
302
|
+
// keeps ticking on its own scheduler while the whole process is frozen — so when most of
|
|
303
|
+
// the block is suspension, that is the label, not an inference from CPU or run queue.
|
|
304
|
+
const suspendedMs = Math.max(0, Number(options.suspendedMs) || 0);
|
|
299
305
|
const mainThreadCpuMs = Math.max(0, Number(options.mainThreadCpuDeltaMs ?? options.cpuDeltaMs) || 0);
|
|
300
306
|
const processCpuMs = Math.max(0, Number(options.processCpuDeltaMs ?? options.cpuDeltaMs) || 0);
|
|
301
307
|
let memory = options.memory;
|
|
@@ -369,6 +375,13 @@ function buildEventLoopBlockEvidence(previous = {}, current = {}, options = {})
|
|
|
369
375
|
else if (mainThreadCpuPct >= 50) signal = 'main_cpu';
|
|
370
376
|
else if (loadPerCore !== null && loadPerCore >= _OVERSUBSCRIBED_LOAD_PER_CORE) signal = 'host-oversubscribed';
|
|
371
377
|
|
|
378
|
+
// WP-2 (D-6): the watchdog's measured suspension beats every inferential host signal. A
|
|
379
|
+
// system sleep or task_suspend freezes the whole process, so CPU, sync-I/O and run-queue
|
|
380
|
+
// evidence all read "nothing ran" and the honest label is the suspension itself. The
|
|
381
|
+
// 1000 ms floor keeps a short tick stall from being restated as machine sleep, and the
|
|
382
|
+
// 50% majority keeps a suspension that merely overlapped a real block from relabelling it.
|
|
383
|
+
if (blockedMs >= 1000 && suspendedMs >= 0.5 * blockedMs) signal = 'process-suspended';
|
|
384
|
+
|
|
372
385
|
return {
|
|
373
386
|
signal,
|
|
374
387
|
// D-2: append the sampler's last per-worker/zstd numbers (null/absent provider adds nothing) so
|
|
@@ -405,6 +418,8 @@ function buildEventLoopBlockEvidence(previous = {}, current = {}, options = {})
|
|
|
405
418
|
offCpuMs,
|
|
406
419
|
offCpuUnexplainedMs,
|
|
407
420
|
offCpuUnexplainedPct,
|
|
421
|
+
// WP-2: the measured suspension this verdict was made from (0 when nothing was measured).
|
|
422
|
+
suspendedMs,
|
|
408
423
|
hostFreeBytes,
|
|
409
424
|
hostTotalBytes,
|
|
410
425
|
freePagesPct,
|
|
@@ -866,11 +881,57 @@ function _callerOwner() {
|
|
|
866
881
|
return 'unknown';
|
|
867
882
|
}
|
|
868
883
|
|
|
884
|
+
// WP-0 M-1 (docs/hub-local-cpu-memory-burn-2026-10-31.html §7): per-timer CPU attribution for
|
|
885
|
+
// the main-thread intervals, so a boot-time CPU burn in the 3 s / 30 s / 60 s sweeps can be
|
|
886
|
+
// named instead of guessed. Same gate as the read-pool side (CTM_PERF_ATTRIBUTION, on in
|
|
887
|
+
// source): when off, nothing is sampled and getTimerCpuStats() is an empty object.
|
|
888
|
+
const _timerCpu = new Map(); // name -> { count, userUs, systemUs }; bounded by the named timers
|
|
889
|
+
const _perfAttributionOn = () => boolFlag('CTM_PERF_ATTRIBUTION', true);
|
|
890
|
+
const _threadCpu = typeof process.threadCpuUsage === 'function'
|
|
891
|
+
? () => process.threadCpuUsage()
|
|
892
|
+
: () => ({ user: 0, system: 0 });
|
|
893
|
+
|
|
894
|
+
// Only the SYNCHRONOUS part of a tick is measured: the sample is taken around the fn.apply()
|
|
895
|
+
// call and computed in `finally`, so a callback that returns a promise reports the CPU its
|
|
896
|
+
// synchronous prefix spent and nothing that happens after it returns. Nothing is awaited here --
|
|
897
|
+
// the timer's own behaviour (return value, thrown error, cadence) is unchanged.
|
|
898
|
+
function _timedIntervalCallback(key, fn) {
|
|
899
|
+
return function timedIntervalTick(...args) {
|
|
900
|
+
if (!_perfAttributionOn()) return fn.apply(this, args);
|
|
901
|
+
const cpu0 = _threadCpu();
|
|
902
|
+
try {
|
|
903
|
+
return fn.apply(this, args);
|
|
904
|
+
} finally {
|
|
905
|
+
const cpu = _threadCpu();
|
|
906
|
+
const totals = _timerCpu.get(key) || { count: 0, userUs: 0, systemUs: 0 };
|
|
907
|
+
totals.count += 1;
|
|
908
|
+
totals.userUs += Math.max(0, cpu.user - cpu0.user);
|
|
909
|
+
totals.systemUs += Math.max(0, cpu.system - cpu0.system);
|
|
910
|
+
_timerCpu.set(key, totals);
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// { [timer]: { count, userMs, systemMs } } -- ms rounded to 0.1, summed from µs so repeated
|
|
916
|
+
// reads cannot drift. Read by perf-summary (mainTimers.cpuByTimer).
|
|
917
|
+
function getTimerCpuStats() {
|
|
918
|
+
if (!_perfAttributionOn()) return {};
|
|
919
|
+
const out = {};
|
|
920
|
+
for (const [name, totals] of _timerCpu) {
|
|
921
|
+
out[name] = {
|
|
922
|
+
count: totals.count,
|
|
923
|
+
userMs: Math.round((totals.userUs / 1000) * 10) / 10,
|
|
924
|
+
systemMs: Math.round((totals.systemUs / 1000) * 10) / 10,
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
return out;
|
|
928
|
+
}
|
|
929
|
+
|
|
869
930
|
function namedInterval(name, fn, ms, ...args) {
|
|
870
931
|
if (typeof fn !== 'function') throw new TypeError('namedInterval requires a function');
|
|
871
932
|
const key = String(name || 'timer');
|
|
872
933
|
_namedIntervalRegistry.set(key, { name: key, ms, owner: _callerOwner(), registeredAt: Date.now() });
|
|
873
|
-
return setInterval(wrap(key, fn), ms, ...args);
|
|
934
|
+
return setInterval(_timedIntervalCallback(key, wrap(key, fn)), ms, ...args);
|
|
874
935
|
}
|
|
875
936
|
|
|
876
937
|
// Exposed for GET /api/diagnostics/main-watchdog (AC-5b) and tests. A registration-time
|
|
@@ -1030,4 +1091,4 @@ function loadPerCore() {
|
|
|
1030
1091
|
} catch { return null; }
|
|
1031
1092
|
}
|
|
1032
1093
|
|
|
1033
|
-
module.exports = { eventLoopBlockMs, getOp, getActiveOpName, getAttributionState, getRecentSpans, getRecentEventLoopBlocks, eventLoopBlockOverlap, _EVENT_LOOP_BLOCK_RING_MAX, recordCompletedSpan, recordExternalSpan, recordSyncIoCall, recordMainDbCall, recordEventLoopBlock, recordEventLoopLagSample, eventLoopLagProfileSuffix, getEventLoopStats, captureEventLoopEvidenceBaseline, buildEventLoopBlockEvidence, shouldReportLag, wrap, wrapAsync, namedInterval, listNamedIntervals, runSync, runSyncProbed, findRecentSynchronousBlockEvidence, isSuspectedSleepBlock, isOffCpuSpan, loadPerCore, setMemoryExtrasProvider, hostCores: _hostCores, OVERSUBSCRIBED_LOAD_PER_CORE: _OVERSUBSCRIBED_LOAD_PER_CORE, SLEEP_BLOCK_MS: _SLEEP_BLOCK_MS, FREEZE_PROBE_MS, perfLogsEnabled, shouldLogPerf, PERF_CRITICAL_MS, isWorkerThread: _isWorkerThread, MAINLOOP_DESCHED_LOAD, MAINLOOP_DESCHED_INVOLCTX, runOutsideAttributionForTests };
|
|
1094
|
+
module.exports = { eventLoopBlockMs, getOp, getActiveOpName, getAttributionState, getRecentSpans, getRecentEventLoopBlocks, eventLoopBlockOverlap, _EVENT_LOOP_BLOCK_RING_MAX, recordCompletedSpan, recordExternalSpan, recordSyncIoCall, recordMainDbCall, recordEventLoopBlock, recordEventLoopLagSample, eventLoopLagProfileSuffix, getEventLoopStats, captureEventLoopEvidenceBaseline, buildEventLoopBlockEvidence, shouldReportLag, wrap, wrapAsync, namedInterval, listNamedIntervals, getTimerCpuStats, runSync, runSyncProbed, findRecentSynchronousBlockEvidence, isSuspectedSleepBlock, isOffCpuSpan, loadPerCore, setMemoryExtrasProvider, hostCores: _hostCores, OVERSUBSCRIBED_LOAD_PER_CORE: _OVERSUBSCRIBED_LOAD_PER_CORE, SLEEP_BLOCK_MS: _SLEEP_BLOCK_MS, FREEZE_PROBE_MS, perfLogsEnabled, shouldLogPerf, PERF_CRITICAL_MS, isWorkerThread: _isWorkerThread, MAINLOOP_DESCHED_LOAD, MAINLOOP_DESCHED_INVOLCTX, runOutsideAttributionForTests };
|
|
@@ -114,6 +114,13 @@ function _normalize(data) {
|
|
|
114
114
|
}
|
|
115
115
|
if (Object.keys(worker).length) out.worker = worker;
|
|
116
116
|
}
|
|
117
|
+
// WP-0 (local-landing-queue-multi-session-integration-2026-10-26.html §5 D-1, §6.1): the
|
|
118
|
+
// landing queue's configuration object. _normalize only passes a plain object through — the
|
|
119
|
+
// landing validator (lib/landing/config.js) owns its contents, including the rejection of
|
|
120
|
+
// unknown keys, so nothing is whitelisted or rewritten here. Never merged with the keys above.
|
|
121
|
+
if (data.landing && typeof data.landing === 'object' && !Array.isArray(data.landing)) {
|
|
122
|
+
out.landing = data.landing;
|
|
123
|
+
}
|
|
117
124
|
return out;
|
|
118
125
|
}
|
|
119
126
|
|
|
@@ -41,6 +41,13 @@ function purgeConversationV2(db, sessionId, sourceIds, eventKeys, nowMs = Date.n
|
|
|
41
41
|
.map((row) => row.stable_key);
|
|
42
42
|
let deleted = 0;
|
|
43
43
|
let canonicalChanges = 0;
|
|
44
|
+
// WP-5 (shared-memory-every-machine §5 D-3, §6.8): a purge must stay addressable on the wire —
|
|
45
|
+
// stamp a tombstone (deleted=1, fresh local seq) for every purged key BEFORE the row goes, so
|
|
46
|
+
// the conversation clock feed can tell a peer to delete it too. No outbox row: the delete feed
|
|
47
|
+
// (conversation_projection_deletes_v2, below) is the local Wall-E subscriber's channel.
|
|
48
|
+
if (stableKeys.length && _tableExists(db, 'conversation_item_clock')) {
|
|
49
|
+
require('./conversation-item-clock').stampConversationTombstonesV2(db, { sessionId, stableKeys, nowMs });
|
|
50
|
+
}
|
|
44
51
|
// WP-0 (one-transcript-ingestor §6.2, D-6b): the deletes below remove the purged
|
|
45
52
|
// keys' outbox rows, so the change feed must FIRST learn exactly which stable
|
|
46
53
|
// keys are going away — same transaction, before the deletes, best-effort when
|
|
@@ -99,4 +106,48 @@ function purgeConversationV2(db, sessionId, sourceIds, eventKeys, nowMs = Date.n
|
|
|
99
106
|
return deleted;
|
|
100
107
|
}
|
|
101
108
|
|
|
102
|
-
|
|
109
|
+
// WP-5 §6.8 (shared-memory-every-machine-2026-10-31.html §5 D-3): the replica RECEIVER's delete —
|
|
110
|
+
// the same work purgeConversationV2 does per key, but scoped to an explicit stable-key list the sync
|
|
111
|
+
// feed handed over (a peer's tombstone). One transaction, and the caller (`db.transaction` around it)
|
|
112
|
+
// may already be inside one, so this uses `.immediate()` like the purge path. It lives here rather
|
|
113
|
+
// than in lib/conversation-item-clock.js because it IS a writer of the conversation item tables, and
|
|
114
|
+
// this module is already the pinned writer (tests/conversation-store-v2.test.js's writer gate).
|
|
115
|
+
function deleteConversationItemsByStableKeyV2(db, { sessionId, stableKeys = [], nowMs = Date.now() } = {}) {
|
|
116
|
+
const requested = [...new Set((Array.isArray(stableKeys) ? stableKeys : []).map((k) => String(k)).filter(Boolean))];
|
|
117
|
+
if (!requested.length) return 0;
|
|
118
|
+
return db.transaction(() => {
|
|
119
|
+
// Only keys this store actually still holds count: a re-offered tombstone (or one for an item
|
|
120
|
+
// this node never had) must leave NO second projection-delete row — the subscriber's delete feed
|
|
121
|
+
// is a log, and replaying a delete into it would grow it without bound.
|
|
122
|
+
const marks = _marks(requested);
|
|
123
|
+
const present = new Set(db.prepare(`SELECT stable_key FROM conversation_text_items_v2
|
|
124
|
+
WHERE session_id=? AND stable_key IN (${marks})`).all(sessionId, ...requested).map((r) => r.stable_key));
|
|
125
|
+
if (_tableExists(db, 'conversation_item_placement_v2')) {
|
|
126
|
+
for (const row of db.prepare(`SELECT stable_key FROM conversation_item_placement_v2
|
|
127
|
+
WHERE session_id=? AND stable_key IN (${marks})`).all(sessionId, ...requested)) {
|
|
128
|
+
present.add(row.stable_key);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const keys = requested.filter((key) => present.has(key));
|
|
132
|
+
if (!keys.length) return 0;
|
|
133
|
+
const mark = _marks(keys);
|
|
134
|
+
let deleted = 0;
|
|
135
|
+
if (_tableExists(db, 'conversation_projection_deletes_v2')) {
|
|
136
|
+
recordProjectionDeletes(db, { sessionId, stableKeys: keys, nowMs });
|
|
137
|
+
}
|
|
138
|
+
if (_tableExists(db, 'conversation_projection_outbox_v2')) {
|
|
139
|
+
deleted += Number(db.prepare(`DELETE FROM conversation_projection_outbox_v2
|
|
140
|
+
WHERE session_id=? AND stable_key IN (${mark})`).run(sessionId, ...keys).changes || 0);
|
|
141
|
+
}
|
|
142
|
+
if (_tableExists(db, 'conversation_item_placement_v2')) {
|
|
143
|
+
deleted += Number(db.prepare(`DELETE FROM conversation_item_placement_v2
|
|
144
|
+
WHERE session_id=? AND stable_key IN (${mark})`).run(sessionId, ...keys).changes || 0);
|
|
145
|
+
}
|
|
146
|
+
deleted += Number(db.prepare(`DELETE FROM conversation_text_items_v2
|
|
147
|
+
WHERE session_id=? AND stable_key IN (${mark})`).run(sessionId, ...keys).changes || 0);
|
|
148
|
+
rebuildTurnIndexForSessions(db, [sessionId], { nowMs });
|
|
149
|
+
return deleted;
|
|
150
|
+
}).immediate();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = { purgeConversationV2, deleteConversationItemsByStableKeyV2 };
|
|
@@ -134,6 +134,10 @@ class ProviderLoginBroker {
|
|
|
134
134
|
// WP-1: the login tab is a real CTM terminal session, created through the
|
|
135
135
|
// server's own prepared-create entry point (server.js wires both in).
|
|
136
136
|
this.createSession = options.createSession || null;
|
|
137
|
+
// WP-1 (D-2): has the session restore finished? Until it has, a persisted open flow whose
|
|
138
|
+
// session is not in the registry may simply not be restored yet, and settling it then would
|
|
139
|
+
// kill a live sign-in. server.js wires `() => _restoreCompletedAt > 0`.
|
|
140
|
+
this.sessionsRestored = options.sessionsRestored || (() => true);
|
|
137
141
|
this.getSession = options.getSession || ((sessionId) => {
|
|
138
142
|
try {
|
|
139
143
|
return require('../server-state').getSession(sessionId) || null;
|
|
@@ -316,9 +320,13 @@ class ProviderLoginBroker {
|
|
|
316
320
|
// stat is information only — on macOS Claude keeps its credential in the Keychain and
|
|
317
321
|
// Codex may keep it in the keyring, so a present/absent file proves nothing.
|
|
318
322
|
async getState() {
|
|
323
|
+
const accounts = await this._probeAccounts();
|
|
324
|
+
// WP-1 (D-1): a restart ADOPTS an open flow's tab, but the exit watcher and the capture
|
|
325
|
+
// lived only in memory — reconcile them before answering, so THIS read reflects a settle
|
|
326
|
+
// the reconcile just made (the card's 2 s poll is the only reader a stuck flow has).
|
|
327
|
+
this._reconcileOpenFlows(accounts);
|
|
319
328
|
const state = this._readState();
|
|
320
329
|
const browserUrls = this._latestBrowserUrls();
|
|
321
|
-
const accounts = await this._probeAccounts();
|
|
322
330
|
const providers = {};
|
|
323
331
|
for (const id of Object.keys(DEFAULT_PROVIDERS)) {
|
|
324
332
|
const provider = this._provider(id);
|
|
@@ -369,6 +377,68 @@ class ProviderLoginBroker {
|
|
|
369
377
|
}
|
|
370
378
|
}
|
|
371
379
|
|
|
380
|
+
// WP-1 (D-1): the ONE state transition that ends a flow — the exit watcher and the
|
|
381
|
+
// login-state reconcile both come here. `status` overrides the exit-code derivation for a
|
|
382
|
+
// tab the restore can no longer find (its account probe decides). Pure with respect to the
|
|
383
|
+
// in-memory maps: the caller owns the latch and the watcher/capture disposal.
|
|
384
|
+
_settleFlow(provider, sessionId, { exitCode = null, signal = '', error = '', status = null } = {}) {
|
|
385
|
+
const next = this._readState();
|
|
386
|
+
const current = next[provider.id]?.flow;
|
|
387
|
+
// Superseded (a newer flow for this provider) or already final: nothing to say.
|
|
388
|
+
if (!current || current.sessionId !== sessionId) return;
|
|
389
|
+
if (current.status === 'completed' || current.status === 'failed') return;
|
|
390
|
+
const code = typeof exitCode === 'number' ? exitCode : null;
|
|
391
|
+
current.status = status || (code === 0 ? 'completed' : 'failed');
|
|
392
|
+
current.exitCode = code;
|
|
393
|
+
current.signal = signal || '';
|
|
394
|
+
// An empty error keeps whatever the flow already carried (the exit path says nothing new).
|
|
395
|
+
if (error) current.error = error;
|
|
396
|
+
current.exitedAt = _nowIso();
|
|
397
|
+
current.updatedAt = current.exitedAt;
|
|
398
|
+
next[provider.id] = { flow: current, status: current.status };
|
|
399
|
+
this._writeState(next);
|
|
400
|
+
this._invalidate(provider.agentId);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// WP-1 (D-1..D-3): the persisted open flows are reconciled against the live session
|
|
404
|
+
// registry on every login-state read, because a restart ADOPTS a login tab (its PTY host
|
|
405
|
+
// survives) while the watcher/capture that end the flow were attached only inside start().
|
|
406
|
+
// Idempotent: a flow already watched and captured attaches nothing more.
|
|
407
|
+
_reconcileOpenFlows(accounts) {
|
|
408
|
+
const state = this._readState();
|
|
409
|
+
for (const id of Object.keys(DEFAULT_PROVIDERS)) {
|
|
410
|
+
const saved = state[id];
|
|
411
|
+
const flow = saved && saved.flow;
|
|
412
|
+
if (!flow || !OPEN_FLOW_STATUSES.includes(flow.status) || !flow.sessionId) continue;
|
|
413
|
+
const provider = this._provider(id);
|
|
414
|
+
const sessionId = flow.sessionId;
|
|
415
|
+
const session = this.getSession ? this.getSession(sessionId) : null;
|
|
416
|
+
if (loginTabAlive(session)) {
|
|
417
|
+
if (!this.subscriptions.has(sessionId)) this._watchLoginTab(provider, session, sessionId);
|
|
418
|
+
if (!this.captures.has(sessionId)) this._attachCapture(provider, session, flow);
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
// The tab is gone: its own exit stamp (when the host still holds it) is the truth.
|
|
422
|
+
if (loginTabExited(session)) {
|
|
423
|
+
this._settleFlow(provider, sessionId, {
|
|
424
|
+
exitCode: loginTabExitCode(session),
|
|
425
|
+
signal: (session && session._exitSignal) || '',
|
|
426
|
+
});
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
// No session at all: only a FINISHED restore may read that as "the tab is gone" —
|
|
430
|
+
// before it, the session simply may not be restored yet and the flow must stay open.
|
|
431
|
+
if (!session && this.sessionsRestored()) {
|
|
432
|
+
const account = provider.agentId ? (accounts || {})[provider.agentId] : null;
|
|
433
|
+
this._settleFlow(provider, sessionId, {
|
|
434
|
+
exitCode: null,
|
|
435
|
+
error: 'login_tab_gone',
|
|
436
|
+
status: account && account.signedIn === true ? 'completed' : 'failed',
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
372
442
|
// Records the exit outcome once the tab is gone, and drops the cached probe so
|
|
373
443
|
// the next login-state read re-runs `claude auth status` / `codex login status`.
|
|
374
444
|
_watchLoginTab(provider, session, sessionId) {
|
|
@@ -382,20 +452,7 @@ class ProviderLoginBroker {
|
|
|
382
452
|
if (typeof capture.dispose === 'function') capture.dispose();
|
|
383
453
|
this.captures.delete(sessionId);
|
|
384
454
|
}
|
|
385
|
-
|
|
386
|
-
const current = next[provider.id]?.flow;
|
|
387
|
-
// Superseded (a newer flow for this provider) or already final: nothing to say.
|
|
388
|
-
if (!current || current.sessionId !== sessionId) return;
|
|
389
|
-
if (current.status === 'completed' || current.status === 'failed') return;
|
|
390
|
-
const code = typeof exitCode === 'number' ? exitCode : null;
|
|
391
|
-
current.status = code === 0 ? 'completed' : 'failed';
|
|
392
|
-
current.exitCode = code;
|
|
393
|
-
current.signal = signal || '';
|
|
394
|
-
current.exitedAt = _nowIso();
|
|
395
|
-
current.updatedAt = current.exitedAt;
|
|
396
|
-
next[provider.id] = { flow: current, status: current.status };
|
|
397
|
-
this._writeState(next);
|
|
398
|
-
this._invalidate(provider.agentId);
|
|
455
|
+
this._settleFlow(provider, sessionId, { exitCode, signal });
|
|
399
456
|
};
|
|
400
457
|
const stamp = () => settle({ exitCode: loginTabExitCode(session), signal: (session && session._exitSignal) || '' });
|
|
401
458
|
// A tab that died between createSession() and this line would never reach a fresh
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// A login shell that `exec`s the resolved CLI keeps the agent type `shell` and
|
|
24
24
|
// hands the CLI the login argv byte-exact.
|
|
25
25
|
|
|
26
|
+
const os = require('os');
|
|
26
27
|
const path = require('path');
|
|
27
28
|
|
|
28
29
|
const BROWSER_SHIM_PATH = path.resolve(__dirname, '..', '..', 'bin', 'open-url-headless.sh');
|
|
@@ -74,9 +75,16 @@ function loginTabArgs(spec, cliPath) {
|
|
|
74
75
|
return ['-l', '-c', loginTabExecLine(spec, cliPath)];
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
// SHELL is often unset for a service-launched CTM (and is in the hermetic test env); then the
|
|
79
|
+
// user's login shell comes from the passwd record, never a hard-coded /bin/zsh -- which does not
|
|
80
|
+
// exist on a default Ubuntu host, where the tab died with exit 1 and no output (design
|
|
81
|
+
// nightly-linux-host-portability-2026-10-27 U-7). /bin/zsh stays the last resort (macOS default).
|
|
82
|
+
function loginTabShell(env = process.env, { userShell = () => os.userInfo().shell } = {}) {
|
|
78
83
|
const shell = String((env && env.SHELL) || '').trim();
|
|
79
|
-
|
|
84
|
+
if (shell) return shell;
|
|
85
|
+
let account = '';
|
|
86
|
+
try { account = String(userShell() || '').trim(); } catch { /* expected: no passwd entry (some containers) -- fall through */ }
|
|
87
|
+
return account || '/bin/zsh';
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
function loginTabEnv({ env = process.env, providerId, urlSink }) {
|