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,302 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-8 step 3 of docs/deepseek-harness-acp-agent-2026-10-28.html (§6.7, §9b M-15/M-16; D-12/D-13).
|
|
4
|
+
//
|
|
5
|
+
// The live model/effort switch for a DeepSeek Harness (`dsh`) lead tab. dsh is an ACP child, not a
|
|
6
|
+
// PTY, so the journaled Claude/Codex machine (owner tuple + provider thread + history handoff) does
|
|
7
|
+
// not apply and neither does OpenCode's park/relaunch argv dance: the bridge exposes the SAME
|
|
8
|
+
// `configOptions` list `session/new` returned, and the ACP primitive
|
|
9
|
+
// `session/set_config_option { sessionId, configId, value }` is the switch (D-12). Two routes:
|
|
10
|
+
//
|
|
11
|
+
// SAME route (or no route named) -> ONE `session/set_config_option` on `configId:'model'` (and/or
|
|
12
|
+
// the bridge-declared effort option). The reply's `configOptions` IS the confirmation, so the
|
|
13
|
+
// request settles `applied` when its `model` option reads back the pick (D-13: never argv, never
|
|
14
|
+
// `session.model_id` alone).
|
|
15
|
+
//
|
|
16
|
+
// DIFFERENT route -> the child holds one route's patch and one session token, so nothing can be
|
|
17
|
+
// patched in place: the child is STOPPED (intentionally) and the existing restore path starts a
|
|
18
|
+
// fresh one on the NEW route, resuming the SAME ACP session id (`session/resume`). The new route's
|
|
19
|
+
// token is minted by `prepareDshRoute`, the old one is released by the runtime's one-shot
|
|
20
|
+
// `onStopped` hook, and the durable record follows so a later CTM restart resumes on it.
|
|
21
|
+
//
|
|
22
|
+
// What it deliberately does NOT do:
|
|
23
|
+
// - it never queues a write behind an open turn: the bridge admits ONE in-flight prompt per
|
|
24
|
+
// session, so a pick made while the harness is answering is refused `dsh_turn_in_flight`;
|
|
25
|
+
// - it never hand-builds an option value: the opaque value comes from the entry's own
|
|
26
|
+
// `configOptions`, and a pick the bridge does not offer is refused `dsh_option_unavailable`;
|
|
27
|
+
// - it never writes a token anywhere but the child's env (D-11): the live `_dshRoute` is
|
|
28
|
+
// non-enumerable and in-memory only, and nothing here logs or persists it (AC-8c-5).
|
|
29
|
+
//
|
|
30
|
+
// The public request/get/cancel surface is OpenCode's, byte for byte (`publicSessionModelRequest`),
|
|
31
|
+
// so the existing client picker renders a dsh switch without a second code path.
|
|
32
|
+
|
|
33
|
+
const crypto = require('node:crypto');
|
|
34
|
+
const { publicSessionModelRequest } = require('../session-model-action-preconditions');
|
|
35
|
+
|
|
36
|
+
const SESSION_NOT_FOUND = 'session_not_found';
|
|
37
|
+
// One entry per session while its pick is being applied; a second request for the same tab is
|
|
38
|
+
// refused with `lead_switch_in_flight` (never queued), exactly like OpenCode's.
|
|
39
|
+
const FLIGHT_KEY = 'relaunching';
|
|
40
|
+
const APPLIED_STATE = 'applied';
|
|
41
|
+
// The request kinds this controller answers. `launch_model` is what the shared picker already sends
|
|
42
|
+
// for an OpenCode tab; `switch_model` is accepted as the same pick under its other name, and an
|
|
43
|
+
// ABSENT kind is accepted so an older client keeps working.
|
|
44
|
+
const ACCEPTED_KINDS = new Set(['launch_model', 'switch_model']);
|
|
45
|
+
const MAX_MODEL_ID_LENGTH = 200;
|
|
46
|
+
const MAX_ROUTE_ID_LENGTH = 200;
|
|
47
|
+
const MAX_CLIENT_REQUEST_ID_LENGTH = 128;
|
|
48
|
+
const MAX_EFFORT_LENGTH = 32;
|
|
49
|
+
|
|
50
|
+
// The sentence each refusal carries, so every client shows a reason instead of a bare HTTP status.
|
|
51
|
+
const REFUSAL_MESSAGES = Object.freeze({
|
|
52
|
+
invalid_request_kind: 'This DeepSeek Harness tab can only switch models and effort; reopen the model picker and try again.',
|
|
53
|
+
invalid_model_id: 'That model was not usable. Reopen the model picker and try again.',
|
|
54
|
+
invalid_route_id: 'The gateway route this pick carried was not usable. Reopen the model picker and try again.',
|
|
55
|
+
invalid_effort: 'That effort level was not usable. Reopen the model picker and try again.',
|
|
56
|
+
invalid_request: 'This model pick was incomplete. Reopen the model picker and try again.',
|
|
57
|
+
invalid_scope: 'This DeepSeek Harness tab can only switch its own session.',
|
|
58
|
+
model_owner_changed: 'This DeepSeek Harness tab restarted since the picker opened. Reopen the picker and try again.',
|
|
59
|
+
lead_switch_in_flight: 'A model switch for this tab is already running.',
|
|
60
|
+
not_live: 'The DeepSeek Harness process for this tab is not running.',
|
|
61
|
+
dsh_turn_in_flight: 'DeepSeek Harness is answering right now. Pick again when the turn ends.',
|
|
62
|
+
dsh_option_unavailable: 'This DeepSeek Harness session does not offer that option.',
|
|
63
|
+
observed_model_mismatch: 'DeepSeek Harness did not switch to that model.',
|
|
64
|
+
dsh_start_failed: 'DeepSeek Harness did not restart on the new route.',
|
|
65
|
+
lead_switch_not_cancellable: 'There is no pending model switch to cancel.',
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
function refusal(status, code, extra = {}) {
|
|
69
|
+
const message = REFUSAL_MESSAGES[code];
|
|
70
|
+
return { ok: false, status, code, ...(message ? { message } : {}), ...extra };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {object} deps
|
|
75
|
+
* @param {(id: string) => ({ agent: string|null, live?: boolean, processGeneration?: number }|null)} deps.getSessionInfo
|
|
76
|
+
* @param {(id: string) => (object|null)} deps.getSession the live session object
|
|
77
|
+
* @param {object} deps.dshRuntime lib/acp/dsh-session-runtime.js
|
|
78
|
+
* @param {object} deps.dshSession lib/session-create/dsh-session.js
|
|
79
|
+
* @param {(frame: object) => void} deps.broadcast
|
|
80
|
+
* @param {(id: string, kind: string, detail: object) => void} [deps.diagnostic]
|
|
81
|
+
* @param {() => number} [deps.now]
|
|
82
|
+
* @param {() => string} [deps.newId]
|
|
83
|
+
*/
|
|
84
|
+
function createDshLaunchModel({
|
|
85
|
+
getSessionInfo, getSession, dshRuntime, dshSession,
|
|
86
|
+
broadcast, diagnostic = null,
|
|
87
|
+
now = Date.now, newId = () => crypto.randomUUID(),
|
|
88
|
+
} = {}) {
|
|
89
|
+
// One entry per session: a later request for the same tab REPLACES the previous one unless it is
|
|
90
|
+
// still being applied, so the map is bounded by the number of live dsh tabs.
|
|
91
|
+
const entries = new Map();
|
|
92
|
+
|
|
93
|
+
function frame(entry) {
|
|
94
|
+
return { type: 'lead-model-request', request: publicSessionModelRequest(entry.req) };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function report(entry) {
|
|
98
|
+
if (typeof diagnostic !== 'function') return;
|
|
99
|
+
try {
|
|
100
|
+
diagnostic(entry.req.ctm_session_id, `dsh-launch-model-${entry.req.state}`, {
|
|
101
|
+
client_request_id: entry.req.client_request_id, model_id: entry.req.model_id,
|
|
102
|
+
reason: entry.req.reason, detail: entry.req.detail,
|
|
103
|
+
});
|
|
104
|
+
} catch { /* expected: a diagnostic sink failure must not change the switch verdict */ }
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// A refusal that PRE-DATES any child action: nothing was changed, so the placeholder entry must not
|
|
108
|
+
// survive as a request the client would later read back as its own.
|
|
109
|
+
function withdraw(entry) {
|
|
110
|
+
if (entry && entries.get(entry.req.ctm_session_id) === entry) entries.delete(entry.req.ctm_session_id);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function settleEntry(entry, state, reason, detail) {
|
|
114
|
+
entry.req.state = state;
|
|
115
|
+
entry.req.phase = state;
|
|
116
|
+
entry.req.reason = reason || null;
|
|
117
|
+
entry.req.detail = String(detail || '').slice(0, 200);
|
|
118
|
+
entry.req.cancellable = false;
|
|
119
|
+
entry.req.settled_at = now();
|
|
120
|
+
report(entry);
|
|
121
|
+
broadcast(frame(entry));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// The option list the bridge is CURRENTLY advertising for this session: the live runtime entry is
|
|
125
|
+
// the only truth (it is replaced by every `config_option_update`), with the request-time entry as
|
|
126
|
+
// the fallback when the child is gone.
|
|
127
|
+
function configOptionsFor(id) {
|
|
128
|
+
const live = typeof dshRuntime?.get === 'function' ? dshRuntime.get(id) : null;
|
|
129
|
+
return (live && Array.isArray(live.configOptions)) ? live.configOptions : null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function turnInFlight(id) {
|
|
133
|
+
return typeof dshRuntime?.isTurnInFlight === 'function' && dshRuntime.isTurnInFlight(id) === true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The SAME-route half: rewrite the model and/or the effort option in place. Each write is one
|
|
138
|
+
* `session/set_config_option`, and the pick is confirmed from the list the bridge answered with.
|
|
139
|
+
* @returns {Promise<{ok: true}|{ok: false, code: string, message: string}>}
|
|
140
|
+
*/
|
|
141
|
+
async function applyInPlace(id, { modelId, effortProvided, effort }) {
|
|
142
|
+
const options = configOptionsFor(id);
|
|
143
|
+
let written = false;
|
|
144
|
+
if (modelId) {
|
|
145
|
+
const modelOption = dshSession.findModelOption(options);
|
|
146
|
+
const value = modelOption ? dshSession.configValueForModelId(modelOption, modelId) : null;
|
|
147
|
+
if (!value) return { ok: false, code: 'dsh_option_unavailable', message: REFUSAL_MESSAGES.dsh_option_unavailable };
|
|
148
|
+
const result = await dshRuntime.setModel(id, { value });
|
|
149
|
+
if (!result || !result.ok) return { ok: false, code: result?.code || 'dsh_option_unavailable', message: REFUSAL_MESSAGES[result?.code] || REFUSAL_MESSAGES.dsh_option_unavailable };
|
|
150
|
+
written = true;
|
|
151
|
+
// D-13: the confirmation is the bridge's own answer, never the value we asked for.
|
|
152
|
+
const observed = dshSession.modelIdFromConfigOptions(result.configOptions);
|
|
153
|
+
if (observed !== modelId) {
|
|
154
|
+
return { ok: false, code: 'observed_model_mismatch', message: REFUSAL_MESSAGES.observed_model_mismatch };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (effortProvided) {
|
|
158
|
+
const effortOption = dshSession.findEffortOption(configOptionsFor(id) || options);
|
|
159
|
+
const value = effortOption ? dshSession.configValueForOptionLevel(effortOption, effort) : null;
|
|
160
|
+
// The EMPTY level means "the model's own default". A bridge that declares no such entry is not
|
|
161
|
+
// an error for that pick (it is already the state), but any OTHER level the bridge does not
|
|
162
|
+
// offer is a refusal, never a hand-built write.
|
|
163
|
+
if (effortOption && !value && effort !== '') {
|
|
164
|
+
return { ok: false, code: 'dsh_option_unavailable', message: REFUSAL_MESSAGES.dsh_option_unavailable };
|
|
165
|
+
}
|
|
166
|
+
if (effortOption && value) {
|
|
167
|
+
const result = await dshRuntime.setEffort(id, effort, { configId: effortOption.id, value });
|
|
168
|
+
if (!result || !result.ok) return { ok: false, code: result?.code || 'dsh_option_unavailable', message: REFUSAL_MESSAGES[result?.code] || REFUSAL_MESSAGES.dsh_option_unavailable };
|
|
169
|
+
written = true;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// A pick that carried neither a model nor an effort is a malformed request, not a success.
|
|
173
|
+
// (`request` already refuses that shape; this keeps the invariant local to the writer.)
|
|
174
|
+
if (!written && !modelId && effort !== '') return { ok: false, code: 'invalid_request', message: REFUSAL_MESSAGES.invalid_request };
|
|
175
|
+
return { ok: true };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* A dsh model/effort pick. Validations run first and the entry is installed SYNCHRONOUSLY once the
|
|
180
|
+
* cheap refusals are out of the way, so two concurrent picks can never both reach the child.
|
|
181
|
+
* @returns {Promise<{ ok:true, request: object }|{ ok:false, status:number, code:string, message?:string }>}
|
|
182
|
+
*/
|
|
183
|
+
async function request(sessionId, body) {
|
|
184
|
+
const id = String(sessionId || '');
|
|
185
|
+
const info = getSessionInfo(id);
|
|
186
|
+
// This controller is only ever reached for a dsh tab; anything else is the runtime's routing bug
|
|
187
|
+
// and the honest answer is the same 404 the router would have produced.
|
|
188
|
+
if (!info || info.agent !== 'dsh') return refusal(404, SESSION_NOT_FOUND);
|
|
189
|
+
const input = body && typeof body === 'object' && !Array.isArray(body) ? body : {};
|
|
190
|
+
// D-12: a dsh pick is in-place; a default-scope write is not something this tab offers.
|
|
191
|
+
if (input.scope === 'session+default') return refusal(400, 'invalid_scope');
|
|
192
|
+
if (input.scope !== 'session') return refusal(400, 'invalid_scope');
|
|
193
|
+
if (input.request_kind != null && !ACCEPTED_KINDS.has(String(input.request_kind))) {
|
|
194
|
+
return refusal(400, 'invalid_request_kind');
|
|
195
|
+
}
|
|
196
|
+
const modelId = typeof input.model_id === 'string' ? input.model_id : '';
|
|
197
|
+
if (modelId.length > MAX_MODEL_ID_LENGTH) return refusal(400, 'invalid_model_id');
|
|
198
|
+
const routeId = typeof input.route_id === 'string' ? input.route_id : '';
|
|
199
|
+
if (routeId.length > MAX_ROUTE_ID_LENGTH) return refusal(400, 'invalid_route_id');
|
|
200
|
+
const effortProvided = typeof input.effort === 'string';
|
|
201
|
+
const effort = effortProvided ? input.effort : null;
|
|
202
|
+
if (effortProvided && effort.length > MAX_EFFORT_LENGTH) return refusal(400, 'invalid_effort');
|
|
203
|
+
const clientRequestId = input.client_request_id;
|
|
204
|
+
if (typeof clientRequestId !== 'string' || !clientRequestId.length
|
|
205
|
+
|| clientRequestId.length > MAX_CLIENT_REQUEST_ID_LENGTH) {
|
|
206
|
+
return refusal(400, 'invalid_request');
|
|
207
|
+
}
|
|
208
|
+
if (!modelId && !effortProvided) return refusal(400, 'invalid_model_id');
|
|
209
|
+
const session = typeof getSession === 'function' ? getSession(id) : null;
|
|
210
|
+
if (!session) return refusal(404, SESSION_NOT_FOUND);
|
|
211
|
+
// A parked/childless tab has no ACP child to write to; the honest answer is `not_live`.
|
|
212
|
+
if (typeof dshRuntime?.isRunning !== 'function' || !dshRuntime.isRunning(id) || session._restoreDeferred === true) {
|
|
213
|
+
return refusal(409, 'not_live');
|
|
214
|
+
}
|
|
215
|
+
// R-3's CAS token, read the same way OpenCode reads it: absent = satisfied.
|
|
216
|
+
if (String(input.expected_process_generation ?? '') !== '' && String(input.expected_process_generation) !== String(info.processGeneration)) {
|
|
217
|
+
return refusal(409, 'model_owner_changed');
|
|
218
|
+
}
|
|
219
|
+
// Idempotent replay of the SAME request, or a pick already being applied.
|
|
220
|
+
const existing = entries.get(id);
|
|
221
|
+
if (existing && existing.req.client_request_id === clientRequestId) {
|
|
222
|
+
return { ok: true, request: publicSessionModelRequest(existing.req) };
|
|
223
|
+
}
|
|
224
|
+
if (existing && existing.req.state === FLIGHT_KEY) return refusal(409, 'lead_switch_in_flight');
|
|
225
|
+
// The bridge admits ONE in-flight prompt per session, so a write now would be refused by the
|
|
226
|
+
// child anyway; refuse it here, with the same code, BEFORE installing an entry (nothing queued).
|
|
227
|
+
if (turnInFlight(id)) return refusal(409, 'dsh_turn_in_flight');
|
|
228
|
+
|
|
229
|
+
const entry = {
|
|
230
|
+
req: {
|
|
231
|
+
id: newId(), ctm_session_id: id, client_request_id: clientRequestId, agent: 'dsh',
|
|
232
|
+
model_id: modelId, effort: effortProvided ? effort : null, effort_only: !modelId, scope: 'session',
|
|
233
|
+
...(routeId ? { route_id: routeId } : {}),
|
|
234
|
+
state: FLIGHT_KEY, phase: FLIGHT_KEY, reason: null, detail: '', cancellable: false,
|
|
235
|
+
requested_at: now(), relaunched_at: null, settled_at: null,
|
|
236
|
+
observed_model: null, observed_effort: null, observed_source: null,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
// Installed SYNCHRONOUSLY, before any await: a second request arriving in the same tick sees it
|
|
240
|
+
// (and is told `lead_switch_in_flight`). NOT broadcast yet — a refusal below withdraws it quietly.
|
|
241
|
+
entries.set(id, entry);
|
|
242
|
+
|
|
243
|
+
// D-12: the route the child is ACTUALLY on, held in memory only (non-enumerable, never persisted).
|
|
244
|
+
const currentAlias = (session._dshRoute && session._dshRoute.alias) || null;
|
|
245
|
+
const crossRoute = !!routeId && routeId !== currentAlias;
|
|
246
|
+
let result;
|
|
247
|
+
try {
|
|
248
|
+
result = crossRoute
|
|
249
|
+
? await dshSession.relaunchDshSession(session, { routeAlias: routeId, model: modelId || null })
|
|
250
|
+
: await applyInPlace(id, { modelId, effortProvided, effort });
|
|
251
|
+
} catch (error) {
|
|
252
|
+
// A throw here is a bug in one of the two paths, and the honest ending is a failed request
|
|
253
|
+
// rather than an entry that stays `relaunching` forever (which would block this tab).
|
|
254
|
+
result = { ok: false, code: 'dsh_start_failed', message: (error && error.message) || REFUSAL_MESSAGES.dsh_start_failed };
|
|
255
|
+
}
|
|
256
|
+
if (entries.get(id) !== entry) return refusal(409, 'lead_switch_in_flight');
|
|
257
|
+
if (!result || !result.ok) {
|
|
258
|
+
const code = (result && result.code) || 'dsh_option_unavailable';
|
|
259
|
+
settleEntry(entry, 'failed', code, (result && result.message) || REFUSAL_MESSAGES[code] || '');
|
|
260
|
+
// A malformed request is the caller's fault (400); anything the BRIDGE refused — a busy turn, an
|
|
261
|
+
// option it does not offer, a restart that did not come up — is a state conflict (409).
|
|
262
|
+
const malformed = code === 'invalid_request' || code === 'invalid_model_id' || code === 'invalid_effort';
|
|
263
|
+
return refusal(malformed ? 400 : 409, code, { request: publicSessionModelRequest(entry.req) });
|
|
264
|
+
}
|
|
265
|
+
const observed = dshSession.modelIdFromConfigOptions(configOptionsFor(id));
|
|
266
|
+
entry.req.observed_model = observed || null;
|
|
267
|
+
entry.req.observed_source = 'dsh:config-option';
|
|
268
|
+
entry.req.observed_effort = dshSession.effortFromConfigOptions(configOptionsFor(id)) || null;
|
|
269
|
+
if (crossRoute) entry.req.relaunched_at = now();
|
|
270
|
+
// The durable route record is the dsh startup task relaunchDshSession just rewrote
|
|
271
|
+
// (persistDshRouteAlias); the lead-route store is claude/codex-only and is not used for dsh.
|
|
272
|
+
settleEntry(entry, APPLIED_STATE, null, '');
|
|
273
|
+
return { ok: true, request: publicSessionModelRequest(entry.req) };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** The public request for this tab, or null. dsh settles from the RPC reply, so nothing polls. */
|
|
277
|
+
function get(sessionId) {
|
|
278
|
+
const entry = entries.get(String(sessionId || ''));
|
|
279
|
+
return entry ? publicSessionModelRequest(entry.req) : null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Cancelling an unconfirmed switch abandons the REQUEST; the child keeps whatever it already applied. */
|
|
283
|
+
function cancel(sessionId) {
|
|
284
|
+
const entry = entries.get(String(sessionId || ''));
|
|
285
|
+
if (!entry || entry.req.state !== FLIGHT_KEY) {
|
|
286
|
+
return refusal(409, 'lead_switch_not_cancellable');
|
|
287
|
+
}
|
|
288
|
+
settleEntry(entry, 'cancelled', null, '');
|
|
289
|
+
return { ok: true, request: publicSessionModelRequest(entry.req) };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* A model observation for this tab arrived. Nothing to do: a dsh pick is confirmed from the
|
|
294
|
+
* `session/set_config_option` reply itself (D-13), so there is no `awaiting_turn` state to settle.
|
|
295
|
+
* Kept because the runtime calls it on every status edge for every controller it routes.
|
|
296
|
+
*/
|
|
297
|
+
function notifyObservation() {}
|
|
298
|
+
|
|
299
|
+
return { request, get, cancel, notifyObservation };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
module.exports = { createDshLaunchModel, DSH_LAUNCH_REFUSAL_MESSAGES: REFUSAL_MESSAGES };
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-10 step A (docs/deepseek-harness-acp-agent-2026-10-28.html §5 C-6, §6.6 D-16, §9b P-1/P-2,
|
|
4
|
+
// §10 T-21/T-27; OQ-12's MCP half).
|
|
5
|
+
//
|
|
6
|
+
// CTM's ONE normalized MCP server shape (lib/mcp-annotations.js `parseJsonMcpServers`:
|
|
7
|
+
// `{name, command, args, env, url, type}`) -> the ACP `mcpServers` entries a dsh (`--profile acp`)
|
|
8
|
+
// child accepts on `session/new` / `session/resume` (lib/acp/acp-client.js takes them already).
|
|
9
|
+
//
|
|
10
|
+
// dsh validates the list itself before it publishes the tools (the rules below were read out of the
|
|
11
|
+
// packed 0.2.1-rc.2 build's `resolveMcpConfigs`; the OQ-12 step-1 measurement is recorded in the
|
|
12
|
+
// WP-10 report):
|
|
13
|
+
//
|
|
14
|
+
// * a stdio entry is one WITHOUT a `type` key, and its `command` MUST be absolute --
|
|
15
|
+
// `if (!("type" in server)) { if (!isAbsolute(server.command)) throw new AcpMcpConfigError(
|
|
16
|
+
// \`mcpServers[${index}].command must be an absolute path\`) }`;
|
|
17
|
+
// * `http` is the only other accepted `type`; any other transport (including `sse`) throws
|
|
18
|
+
// `mcpServers[i] transport <type> is not supported`;
|
|
19
|
+
// * `env`/`headers` are ordered `[{name, value}]` and a repeated name throws;
|
|
20
|
+
// * the list is unique after dsh's own name normalization.
|
|
21
|
+
//
|
|
22
|
+
// A declaration dsh would refuse is DROPPED here with ONE log line instead of failing the whole
|
|
23
|
+
// session start: one unusable server must not cost the session its other tools. Every log line names
|
|
24
|
+
// the SERVER and the REASON only -- never an env or header VALUE, so a credential can never reach
|
|
25
|
+
// CTM's logs from this module.
|
|
26
|
+
//
|
|
27
|
+
// PURE: no fs, no child_process, no env reads (main-thread lint scans lib/** and this module runs on
|
|
28
|
+
// the interactive create/restore path). The caller passes the token in; the entries carry it.
|
|
29
|
+
|
|
30
|
+
const path = require('node:path');
|
|
31
|
+
|
|
32
|
+
// dsh's own name contract: VALID_SERVER_NAME (a longer/invalid name is normalized by dsh, NOT
|
|
33
|
+
// fatal) plus the fatal control-character rule from normalizeServerName.
|
|
34
|
+
const CONTROL_CHARS_RE = /[\u0000-\u001f\u007f]/;
|
|
35
|
+
|
|
36
|
+
const STDIO_TYPE = 'stdio';
|
|
37
|
+
const HTTP_TYPE = 'http';
|
|
38
|
+
const SSE_TYPE = 'sse';
|
|
39
|
+
|
|
40
|
+
const WALL_E_SERVER_NAME = 'wall-e';
|
|
41
|
+
const CTM_SESSION_ID_ENV = 'CTM_SESSION_ID';
|
|
42
|
+
const WALL_E_API_TOKEN_ENV = 'WALL_E_API_TOKEN';
|
|
43
|
+
|
|
44
|
+
function logLine(log, message) {
|
|
45
|
+
if (typeof log !== 'function') return;
|
|
46
|
+
try {
|
|
47
|
+
log(message);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
// expected: a broken log sink must never cost a session its MCP servers.
|
|
50
|
+
void error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// An array of specs, or CTM's name-keyed object (parseJsonMcpServers's shape) -> [{key, spec}].
|
|
55
|
+
function entriesOf(servers) {
|
|
56
|
+
if (Array.isArray(servers)) return servers.map((spec) => ({ key: '', spec }));
|
|
57
|
+
if (servers && typeof servers === 'object') {
|
|
58
|
+
return Object.entries(servers).map(([key, spec]) => ({ key, spec }));
|
|
59
|
+
}
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The entry's name: its own `name` when set, else the object key it was filed under.
|
|
64
|
+
function serverNameOf(entry) {
|
|
65
|
+
const spec = entry && entry.spec && typeof entry.spec === 'object' ? entry.spec : {};
|
|
66
|
+
const named = typeof spec.name === 'string' && spec.name.trim() ? spec.name : '';
|
|
67
|
+
return (named || String((entry && entry.key) || '')).trim();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// An object map (`{KEY: 'value'}` -- CTM's normalized shape) or an ordered ACP `[{name, value}]`
|
|
71
|
+
// list -> ACP's ordered entries. The first occurrence of a name wins (dsh throws on a repeat);
|
|
72
|
+
// a non-string value is stringified rather than dropped.
|
|
73
|
+
function toNameValueEntries(source) {
|
|
74
|
+
const out = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const push = (name, value) => {
|
|
77
|
+
if (typeof name !== 'string' || !name || seen.has(name)) return;
|
|
78
|
+
seen.add(name);
|
|
79
|
+
out.push({ name, value: typeof value === 'string' ? value : String(value == null ? '' : value) });
|
|
80
|
+
};
|
|
81
|
+
if (Array.isArray(source)) {
|
|
82
|
+
for (const item of source) {
|
|
83
|
+
if (item && typeof item === 'object') push(item.name, item.value);
|
|
84
|
+
}
|
|
85
|
+
} else if (source && typeof source === 'object') {
|
|
86
|
+
for (const [name, value] of Object.entries(source)) push(name, value);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ONE normalized spec -> ONE ACP entry, or a refusal reason (never a value).
|
|
92
|
+
function convertOne(name, spec) {
|
|
93
|
+
const type = typeof spec.type === 'string' ? spec.type.trim().toLowerCase() : '';
|
|
94
|
+
const url = typeof spec.url === 'string' ? spec.url.trim() : '';
|
|
95
|
+
const command = typeof spec.command === 'string' ? spec.command.trim() : '';
|
|
96
|
+
// dsh's own branch: no `type` key means stdio. A config that spells `type: 'stdio'` (the Claude
|
|
97
|
+
// shape in ~/.claude.json) means the same thing here and is normalized to the type-less form.
|
|
98
|
+
if (type === '' || type === STDIO_TYPE) {
|
|
99
|
+
if (url && !command) return { ok: false, reason: 'no command (a url without type "http" cannot be forwarded)' };
|
|
100
|
+
if (!command) return { ok: false, reason: 'no command' };
|
|
101
|
+
if (!path.isAbsolute(command)) return { ok: false, reason: 'command is not an absolute path' };
|
|
102
|
+
return {
|
|
103
|
+
ok: true,
|
|
104
|
+
// NO `type` key: dsh's stdio branch is the ABSENCE of `type`, and an explicit 'stdio' would
|
|
105
|
+
// trip its "transport stdio is not supported" refusal.
|
|
106
|
+
entry: { name, command, args: Array.isArray(spec.args) ? spec.args.map(String) : [], env: toNameValueEntries(spec.env) },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
if (type === HTTP_TYPE) {
|
|
110
|
+
if (!url) return { ok: false, reason: 'no url' };
|
|
111
|
+
return { ok: true, entry: { type: HTTP_TYPE, name, url, headers: toNameValueEntries(spec.headers) } };
|
|
112
|
+
}
|
|
113
|
+
if (type === SSE_TYPE) return { ok: false, reason: 'sse transport is not supported by dsh' };
|
|
114
|
+
return { ok: false, reason: `transport ${type} is not supported by dsh` };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* CTM's normalized MCP servers -> the ACP `mcpServers` list for `session/new`/`session/resume`.
|
|
119
|
+
*
|
|
120
|
+
* ORDER IS PRESERVED (array order, or the object's own key order) and the FIRST of any duplicate
|
|
121
|
+
* name wins. Every dropped declaration is reported once, by name and reason.
|
|
122
|
+
*
|
|
123
|
+
* @param {object|Array<object>} servers name-keyed map or array of `{name, command, args, env, url, type}`
|
|
124
|
+
* @param {{log?: (message: string) => void}} [options]
|
|
125
|
+
* @returns {Array<object>} ACP entries: stdio `{name, command, args, env}` / http `{type:'http', name, url, headers}`
|
|
126
|
+
*/
|
|
127
|
+
function toAcpMcpServers(servers, { log } = {}) {
|
|
128
|
+
const out = [];
|
|
129
|
+
const seen = new Set();
|
|
130
|
+
for (const item of entriesOf(servers)) {
|
|
131
|
+
const spec = item && item.spec && typeof item.spec === 'object' ? item.spec : {};
|
|
132
|
+
const name = serverNameOf(item);
|
|
133
|
+
if (!name) {
|
|
134
|
+
logLine(log, 'dsh-mcp: dropping an MCP server with no name');
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (CONTROL_CHARS_RE.test(name)) {
|
|
138
|
+
logLine(log, 'dsh-mcp: dropping an MCP server whose name contains control characters');
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (seen.has(name)) {
|
|
142
|
+
logLine(log, `dsh-mcp: dropping duplicate MCP server "${name}" (first one wins)`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const converted = convertOne(name, spec);
|
|
146
|
+
if (!converted.ok) {
|
|
147
|
+
logLine(log, `dsh-mcp: dropping MCP server "${name}": ${converted.reason}`);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
seen.add(name);
|
|
151
|
+
out.push(converted.entry);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Stamp the Wall-E MCP stdio entry with the caller identity its stdio proxy authenticates with
|
|
158
|
+
* (`wall-e/lib/stdio-proxy-env.js`'s STDIO_PROXY_CALLER_ENV: `CTM_SESSION_ID`, `WALL_E_API_TOKEN`).
|
|
159
|
+
*
|
|
160
|
+
* The values are placed in the entry's `env`, i.e. they travel ONLY inside the ACP
|
|
161
|
+
* `session/new`/`session/resume` JSON-RPC request on the child's stdin -- never on argv, never in a
|
|
162
|
+
* file, never in CTM's own child env, never in a log line.
|
|
163
|
+
*
|
|
164
|
+
* Values for the SAME two keys are replaced; an empty value is not written at all (a stale value
|
|
165
|
+
* already in the user's own config is left alone rather than blanked to '').
|
|
166
|
+
*
|
|
167
|
+
* @param {Array<object>} entries the list `toAcpMcpServers` returned
|
|
168
|
+
* @param {{ctmSessionId?: string, walleToken?: string}} caller
|
|
169
|
+
* @returns {Array<object>} a NEW list; every entry that is not the stdio `wall-e` server is untouched
|
|
170
|
+
*/
|
|
171
|
+
function withWalleCaller(entries, { ctmSessionId = '', walleToken = '' } = {}) {
|
|
172
|
+
const list = Array.isArray(entries) ? entries : [];
|
|
173
|
+
return list.map((entry) => {
|
|
174
|
+
if (!entry || typeof entry !== 'object' || entry.type || entry.name !== WALL_E_SERVER_NAME) return entry;
|
|
175
|
+
const env = Array.isArray(entry.env) ? [...entry.env] : [];
|
|
176
|
+
const set = (name, value) => {
|
|
177
|
+
if (!value) return;
|
|
178
|
+
const at = env.findIndex((item) => item && item.name === name);
|
|
179
|
+
if (at >= 0) env[at] = { name, value };
|
|
180
|
+
else env.push({ name, value });
|
|
181
|
+
};
|
|
182
|
+
set(CTM_SESSION_ID_ENV, String(ctmSessionId || ''));
|
|
183
|
+
set(WALL_E_API_TOKEN_ENV, String(walleToken || ''));
|
|
184
|
+
return { ...entry, env };
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
module.exports = {
|
|
189
|
+
toAcpMcpServers,
|
|
190
|
+
withWalleCaller,
|
|
191
|
+
WALL_E_SERVER_NAME,
|
|
192
|
+
CTM_SESSION_ID_ENV,
|
|
193
|
+
WALL_E_API_TOKEN_ENV,
|
|
194
|
+
};
|