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,616 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-4 of docs/deepseek-harness-acp-agent-2026-10-28.html (§6.5 status mapping, §5 D-7, §9 S-32/S-33/S-35).
|
|
4
|
+
//
|
|
5
|
+
// The prompt/cancel/approval lane for a conv-only ACP session (today the DeepSeek Harness, `dsh`).
|
|
6
|
+
// Such a session has no PTY, so the terminal submission path cannot own it: this lane takes the
|
|
7
|
+
// turn instead, and everything that is NOT an ACP session falls straight through to the function it
|
|
8
|
+
// wraps, with identical arguments (§9 S-32 — the wraps are same-line seams in server.js).
|
|
9
|
+
//
|
|
10
|
+
// A turn, in order (§6.5):
|
|
11
|
+
// 1. the user row is appended to the CTM-owned transcript (lib/acp/dsh-transcript.js) — the
|
|
12
|
+
// transcript is appended to BEFORE the wire write so Conv can never show a prompt the agent
|
|
13
|
+
// was not yet given;
|
|
14
|
+
// 2. status `received` (the client renders it `accepted`);
|
|
15
|
+
// 3. `session/prompt` goes to the child — the ACP client writes it synchronously;
|
|
16
|
+
// 4. status `durable_user_message_seen` (rendered `sent`) — the request is on the wire;
|
|
17
|
+
// 5. the delivery RETURNS here, and the turn settles in the BACKGROUND (runSettle) when the prompt
|
|
18
|
+
// promise settles: the transcript's open chunk group is flushed and the chip closes. A JSON-RPC
|
|
19
|
+
// error is reported `failed` with the bridge's own message ("Insufficient Balance") and becomes
|
|
20
|
+
// a `dsh_turn_failed` transcript row (assistant-shaped since WP-7d, so Conv renders it); a
|
|
21
|
+
// cancelled turn settles `blocked`. Anything that needs the turn's END awaits
|
|
22
|
+
// whenTurnSettled(sessionId).
|
|
23
|
+
// The delivery must not wait for step 5: lib/root-delivery-runtime.js holds the delivery permit
|
|
24
|
+
// until `deliverTerminal` resolves, and a dsh turn can run for many minutes — so its contract
|
|
25
|
+
// ("delivered = the write was confirmed") is honoured by returning at step 4.
|
|
26
|
+
// A second prompt while one is in flight is refused with `dsh_turn_in_flight` by BOTH the preflight
|
|
27
|
+
// wrap and the delivery guard (two preflights can pass before either delivery starts; the bridge
|
|
28
|
+
// admits ONE in-flight prompt per session).
|
|
29
|
+
//
|
|
30
|
+
// Approvals (D-7): a `session/request_permission` becomes a runtime approval whose metadata carries
|
|
31
|
+
// the already-received `tool_call`'s title/input, is answered by the approval executor through the
|
|
32
|
+
// wrapped `isHookPending`/`resolveHook` seams (S-35) and resolves the ACP server request with the
|
|
33
|
+
// ACP-provided `optionId` for the chosen kind. "Answered exactly once" (P-4) is owned by
|
|
34
|
+
// lib/acp/acp-client.js — on cancel/child exit it answers pending permissions `cancelled` itself —
|
|
35
|
+
// so this lane only has to settle its OWN promise and mark the runtime approval `expired` (T-10).
|
|
36
|
+
//
|
|
37
|
+
// Everything outside this module is a dep, so a unit test drives the lane with a fake ACP client,
|
|
38
|
+
// a fake runtime and fake status/approval sinks (D-14, H-7). Nothing here writes a file, spawns a
|
|
39
|
+
// process or invents a WebSocket frame: statuses go through the SAME storeStatus/receipt channel the
|
|
40
|
+
// terminal path uses, and the session chip is fed by the server's own turn-open/turn-close helpers.
|
|
41
|
+
|
|
42
|
+
const { isAcpSession } = require('../session-transport');
|
|
43
|
+
const { getDataDir } = require('../data-dir');
|
|
44
|
+
|
|
45
|
+
// ACP permission option kinds (protocol v1) → the CTM runtime-approval decision vocabulary
|
|
46
|
+
// (docs §5 D-7). `allow_always` maps to the project-scoped allow, both reject kinds to `deny`.
|
|
47
|
+
const ACP_KIND_TO_DECISION = Object.freeze({
|
|
48
|
+
allow_once: 'allow_once',
|
|
49
|
+
allow_always: 'allow_always_project',
|
|
50
|
+
reject_once: 'deny',
|
|
51
|
+
reject_always: 'deny',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const TURN_IN_FLIGHT_MESSAGE = 'A turn is already running on this DeepSeek Harness session.';
|
|
55
|
+
const NOT_RUNNING_MESSAGE = 'The DeepSeek Harness process for this session is not running.';
|
|
56
|
+
const TURN_CANCELLED_MESSAGE = 'The turn was cancelled.';
|
|
57
|
+
const MAX_PROMPT_CHARS = 20000;
|
|
58
|
+
|
|
59
|
+
// WP-11 (D-20) refusals. `dsh_image_unsupported` is the capability verdict (the child never
|
|
60
|
+
// advertised `promptCapabilities.image`); `dsh_image_unreadable` is the store verdict (the bytes the
|
|
61
|
+
// prompt named could not be read). Both are refused BEFORE anything is written to the wire or the
|
|
62
|
+
// transcript, mirroring the existing `dsh_not_running` door.
|
|
63
|
+
const IMAGE_UNSUPPORTED_CODE = 'dsh_image_unsupported';
|
|
64
|
+
const IMAGE_UNSUPPORTED_MESSAGE =
|
|
65
|
+
'This DeepSeek Harness session cannot accept images: the agent did not advertise image prompt support.';
|
|
66
|
+
const IMAGE_UNREADABLE_CODE = 'dsh_image_unreadable';
|
|
67
|
+
const IMAGE_UNREADABLE_MESSAGE = 'An image attached to this prompt could not be read.';
|
|
68
|
+
|
|
69
|
+
// The image extensions CTM's upload store serves (`/api/images/file/<name>`); an attachment with an
|
|
70
|
+
// explicit `image/*` media type is an image regardless of its name.
|
|
71
|
+
const IMAGE_EXT_RE = /\.(?:png|jpe?g|gif|webp|bmp|avif)$/i;
|
|
72
|
+
const MIME_BY_EXT = Object.freeze({
|
|
73
|
+
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif',
|
|
74
|
+
'.webp': 'image/webp', '.bmp': 'image/bmp', '.avif': 'image/avif',
|
|
75
|
+
});
|
|
76
|
+
const nodePath = require('node:path');
|
|
77
|
+
const fsPromises = require('node:fs').promises;
|
|
78
|
+
|
|
79
|
+
// The image attachments a submission names, normalized to the fields the store resolver needs. Non
|
|
80
|
+
// images are dropped: the terminal path already filters its own attachment list, and a dsh prompt
|
|
81
|
+
// carries only images (D-20).
|
|
82
|
+
function collectImageRefs(attachments) {
|
|
83
|
+
const refs = [];
|
|
84
|
+
for (const att of Array.isArray(attachments) ? attachments : []) {
|
|
85
|
+
if (!att || typeof att !== 'object' || Array.isArray(att)) continue;
|
|
86
|
+
const mimeType = String(att.mimeType || att.mediaType || att.mime_type || att.media_type || '').toLowerCase();
|
|
87
|
+
const name = String(att.filename || att.path || att.file_path || att.url || '');
|
|
88
|
+
if (!mimeType.startsWith('image/') && !IMAGE_EXT_RE.test(name.replace(/[?#].*$/, ''))) continue;
|
|
89
|
+
refs.push({
|
|
90
|
+
label: String(att.label || ''),
|
|
91
|
+
filename: String(att.filename || ''),
|
|
92
|
+
url: String(att.url || ''),
|
|
93
|
+
path: String(att.path || att.file_path || ''),
|
|
94
|
+
id: Number(att.id || 0) || null,
|
|
95
|
+
mimeType,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return refs;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// The ONE production source of image bytes: CTM's upload store, `<dataDir>/images`, which is exactly
|
|
102
|
+
// what `/api/images/file/<name>` serves and what a session-image manifest's `target` symlink resolves
|
|
103
|
+
// into (lib/session-image-refs.js `_manifestLinkServedName`). A reference is therefore reduced to the
|
|
104
|
+
// basename CTM itself would serve, and the read is async — never a sync fs call on the main loop.
|
|
105
|
+
function defaultReadImageData(ref) {
|
|
106
|
+
const raw = String(ref.path || ref.url || ref.filename || '');
|
|
107
|
+
const decoded = (() => {
|
|
108
|
+
try { return decodeURIComponent(raw); } catch { return raw; }
|
|
109
|
+
})();
|
|
110
|
+
const name = nodePath.basename(decoded.replace(/[?#].*$/, ''));
|
|
111
|
+
if (!name || name === '.' || name === '..') return Promise.resolve(null);
|
|
112
|
+
const imagesDir = nodePath.resolve(getDataDir(), 'images');
|
|
113
|
+
const filePath = nodePath.join(imagesDir, name);
|
|
114
|
+
if (nodePath.dirname(filePath) !== imagesDir) return Promise.resolve(null);
|
|
115
|
+
return fsPromises.readFile(filePath).then(
|
|
116
|
+
(bytes) => (bytes && bytes.length
|
|
117
|
+
? { mimeType: ref.mimeType || MIME_BY_EXT[nodePath.extname(name).toLowerCase()] || 'image/png',
|
|
118
|
+
data: bytes.toString('base64') }
|
|
119
|
+
: null),
|
|
120
|
+
// expected: a missing/unreadable file is reported to the caller as an unreadable image, not a throw.
|
|
121
|
+
() => null,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function decisionForAcpKind(kind) {
|
|
126
|
+
return ACP_KIND_TO_DECISION[String(kind || '')] || '';
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// The ACP-provided optionId for the chosen decision. `allow` prefers the one-shot allow and falls
|
|
130
|
+
// back to the project-scoped allow; `deny` takes the first reject kind. No match means the bridge
|
|
131
|
+
// offered nothing this decision can be expressed as, and the request is answered `cancelled`.
|
|
132
|
+
//
|
|
133
|
+
// NOTE the resolution SHAPE: lib/acp/acp-client.js hands the resolved value straight to
|
|
134
|
+
// `result: { outcome }`, so what this lane resolves must be the ACP outcome itself —
|
|
135
|
+
// `{ outcome: 'selected', optionId }`, never a pre-wrapped `{ outcome: { … } }`, which its
|
|
136
|
+
// normaliseOutcome() would read as a non-string and silently downgrade to `cancelled`.
|
|
137
|
+
function optionIdForDecision(options, allow) {
|
|
138
|
+
const wanted = allow ? ['allow_once', 'allow_always_project'] : ['deny'];
|
|
139
|
+
for (const decision of wanted) {
|
|
140
|
+
const match = options.find((option) => option.decision === decision);
|
|
141
|
+
if (match && match.optionId) return match.optionId;
|
|
142
|
+
}
|
|
143
|
+
return '';
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// A bounded, human-readable summary of the tool call's input — the approval card's command line.
|
|
147
|
+
// The raw input object is never handed to the recorder (it is cleaned there as well).
|
|
148
|
+
function summarizeInput(input, title) {
|
|
149
|
+
if (typeof input.command === 'string' && input.command) return input.command.slice(0, MAX_PROMPT_CHARS);
|
|
150
|
+
try {
|
|
151
|
+
return JSON.stringify(input || {}).slice(0, MAX_PROMPT_CHARS) || title;
|
|
152
|
+
} catch (error) {
|
|
153
|
+
// expected: a circular or exotic rawInput is not worth failing an approval over.
|
|
154
|
+
void error;
|
|
155
|
+
return title;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @param {object} deps
|
|
161
|
+
* @param {(ctmSessionId: string) => object|null} [deps.getSession]
|
|
162
|
+
* @param {(ctmSessionId: string) => {acpSessionId, client}|null} [deps.getRuntime] // dshRuntime.get
|
|
163
|
+
* @param {(sessionId, messageId, remoteStatus, details) => any} [deps.storeStatus] // _storeRemoteSubmissionStatus
|
|
164
|
+
* @param {(input: object) => any} [deps.recordRuntimeApprovalRequested]
|
|
165
|
+
* @param {(approvalId: string, input: object) => any} [deps.resolveRuntimeApproval]
|
|
166
|
+
* @param {(session: object) => void} [deps.markTurnOpen]
|
|
167
|
+
* @param {(session: object, blocking: boolean) => void} [deps.markWaiting]
|
|
168
|
+
* @param {(session: object) => void} [deps.markTurnClosed]
|
|
169
|
+
* @param {(session: object) => void} [deps.requestWake] // WP-5: start a deferred (asleep) dsh session
|
|
170
|
+
* @param {(ref: object) => Promise<{mimeType: string, data: string}|null>} [deps.readImageData]
|
|
171
|
+
* WP-11: the ONE async byte source for an image attachment (default: CTM's `<dataDir>/images`
|
|
172
|
+
* upload store). A null answer refuses the prompt with `dsh_image_unreadable`.
|
|
173
|
+
* @param {() => number} [deps.now]
|
|
174
|
+
* @param {(entry: {level: string, msg: string}) => void} [deps.log]
|
|
175
|
+
*/
|
|
176
|
+
function createDshPromptLane(deps = {}) {
|
|
177
|
+
const getSession = typeof deps.getSession === 'function' ? deps.getSession : () => null;
|
|
178
|
+
const getRuntime = typeof deps.getRuntime === 'function' ? deps.getRuntime : () => null;
|
|
179
|
+
const storeStatus = typeof deps.storeStatus === 'function' ? deps.storeStatus : () => null;
|
|
180
|
+
const recordRuntimeApprovalRequested = typeof deps.recordRuntimeApprovalRequested === 'function'
|
|
181
|
+
? deps.recordRuntimeApprovalRequested : () => null;
|
|
182
|
+
const resolveRuntimeApproval = typeof deps.resolveRuntimeApproval === 'function'
|
|
183
|
+
? deps.resolveRuntimeApproval : () => null;
|
|
184
|
+
const markTurnOpen = typeof deps.markTurnOpen === 'function' ? deps.markTurnOpen : () => {};
|
|
185
|
+
const markWaiting = typeof deps.markWaiting === 'function' ? deps.markWaiting : () => {};
|
|
186
|
+
const markTurnClosed = typeof deps.markTurnClosed === 'function' ? deps.markTurnClosed : () => {};
|
|
187
|
+
const requestWake = typeof deps.requestWake === 'function' ? deps.requestWake : () => {};
|
|
188
|
+
// WP-8 step 3 (§9b M-16): the completed-turn observation writer (lib/session-create/dsh-session.js
|
|
189
|
+
// `observeDshCompletedTurn`). Optional: a harness without the model-state runtime simply skips it.
|
|
190
|
+
const observeCompletedTurn = typeof deps.observeCompletedTurn === 'function' ? deps.observeCompletedTurn : () => {};
|
|
191
|
+
// WP-11: an injected byte reader keeps the lane testable without touching a real store; the default
|
|
192
|
+
// is CTM's own upload store (see defaultReadImageData above).
|
|
193
|
+
const readImageData = typeof deps.readImageData === 'function' ? deps.readImageData : defaultReadImageData;
|
|
194
|
+
const now = typeof deps.now === 'function' ? deps.now : Date.now;
|
|
195
|
+
const log = typeof deps.log === 'function' ? deps.log : () => {};
|
|
196
|
+
|
|
197
|
+
const turns = new Map(); // ctmSessionId → in-flight turn record
|
|
198
|
+
const settles = new Map(); // ctmSessionId → the in-flight turn's background-settle promise
|
|
199
|
+
const permissions = new Map(); // ctmSessionId → Array<pending permission record>
|
|
200
|
+
const toolCalls = new Map(); // ctmSessionId → the latest `tool_call` update
|
|
201
|
+
|
|
202
|
+
function warn(msg) {
|
|
203
|
+
try { log({ level: 'warn', msg }); } catch (error) { void error; } // expected: a broken log sink is never fatal
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function emitStatus(sessionId, messageId, status, details) {
|
|
207
|
+
if (!messageId) return;
|
|
208
|
+
try {
|
|
209
|
+
storeStatus(sessionId, messageId, status, { ...details, source: details.source || 'dsh' });
|
|
210
|
+
} catch (error) {
|
|
211
|
+
warn(`dsh-prompt-lane: status ${status} failed (${error && error.message})`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function safeCall(fn, label, ...args) {
|
|
216
|
+
try { return fn(...args); } catch (error) {
|
|
217
|
+
warn(`dsh-prompt-lane: ${label} failed (${error && error.message})`);
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function pendingList(sessionId) {
|
|
223
|
+
return permissions.get(sessionId) || [];
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function dropPermission(sessionId, record) {
|
|
227
|
+
const list = pendingList(sessionId);
|
|
228
|
+
const at = list.indexOf(record);
|
|
229
|
+
if (at >= 0) list.splice(at, 1);
|
|
230
|
+
if (!list.length) permissions.delete(sessionId);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// --- tool_call tracking (§9 S-37: the runtime forwards every session/update here) ------------
|
|
234
|
+
|
|
235
|
+
/** One ACP `session/update` for a session this lane owns. Tracks the latest tool call. */
|
|
236
|
+
function onUpdate(ctmSessionId, update) {
|
|
237
|
+
if (!ctmSessionId || !update || typeof update !== 'object') return;
|
|
238
|
+
if (update.sessionUpdate === 'tool_call' && update.toolCallId) {
|
|
239
|
+
toolCalls.set(ctmSessionId, update);
|
|
240
|
+
}
|
|
241
|
+
const turn = turns.get(ctmSessionId);
|
|
242
|
+
if (turn) turn.sawUpdate = true;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// --- prompt lane (§9 S-32) -------------------------------------------------------------------
|
|
246
|
+
|
|
247
|
+
// The ONE refusal shape for "this session already has a turn in flight". The preflight wrap and
|
|
248
|
+
// the delivery guard below both use it, so the two doors cannot describe the same state
|
|
249
|
+
// differently (AC-4e).
|
|
250
|
+
function turnInFlightBlocker() {
|
|
251
|
+
return {
|
|
252
|
+
ok: false,
|
|
253
|
+
error: 'dsh_turn_in_flight',
|
|
254
|
+
reason: 'dsh_turn_in_flight',
|
|
255
|
+
retryable: true,
|
|
256
|
+
message: TURN_IN_FLIGHT_MESSAGE,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// WP-5 (D-5/D-9, AC-5c): this session's child is gone (it died, or CTM restarted) and it is an
|
|
261
|
+
// ordinary deferred placeholder again. Ask for the wake and answer with the ONE in-set transient
|
|
262
|
+
// blocker, exactly like every other asleep session — the prompt is not silently dropped.
|
|
263
|
+
function asleepBlocker(session) {
|
|
264
|
+
safeCall(requestWake, 'requestWake', session);
|
|
265
|
+
return {
|
|
266
|
+
ok: false,
|
|
267
|
+
error: 'session_resume_not_ready',
|
|
268
|
+
reason: 'dsh_restore_starting',
|
|
269
|
+
retryable: true,
|
|
270
|
+
message: 'The DeepSeek Harness session is restarting; this message will be delivered when it is ready.',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Wrap the root prompt flow's synchronous preflight: ACP sessions refuse a second turn. */
|
|
275
|
+
function wrapPreflight(existing) {
|
|
276
|
+
return function preflight(...args) {
|
|
277
|
+
const [sessionId, session] = args;
|
|
278
|
+
if (!isAcpSession(session)) return existing(...args);
|
|
279
|
+
if (session && session._restoreDeferred) return asleepBlocker(session);
|
|
280
|
+
const turn = turns.get(sessionId);
|
|
281
|
+
if (turn && turn.inFlight) return turnInFlightBlocker();
|
|
282
|
+
return null;
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// The background half of one turn. It must never throw (its caller catches anyway) and it is
|
|
287
|
+
// idempotent about releasing the seat, so a child exit that already cleared the turn is harmless.
|
|
288
|
+
function runSettle(session, turn, stopReason, failure) {
|
|
289
|
+
const sessionId = turn.sessionId;
|
|
290
|
+
const source = turn.source;
|
|
291
|
+
turn.inFlight = false;
|
|
292
|
+
if (turns.get(sessionId) === turn) turns.delete(sessionId);
|
|
293
|
+
if (settles.get(sessionId) === turn.settled) settles.delete(sessionId);
|
|
294
|
+
const transcript = session && session._dshTranscript;
|
|
295
|
+
safeCall(() => transcript?.flush(), 'flush');
|
|
296
|
+
settlePermissions(sessionId, 'cancelled');
|
|
297
|
+
safeCall(() => markTurnClosed(session), 'markTurnClosed');
|
|
298
|
+
|
|
299
|
+
if (failure) {
|
|
300
|
+
const message = (failure && failure.message) || 'DeepSeek Harness turn failed';
|
|
301
|
+
if (failure.code === 'acp_turn_failed') {
|
|
302
|
+
safeCall(() => transcript?.appendTurnFailed(message), 'appendTurnFailed');
|
|
303
|
+
}
|
|
304
|
+
emitStatus(sessionId, turn.receiptId, 'failed', { reason: 'dsh_turn_failed', message, source });
|
|
305
|
+
turn.outcome = { ok: false, status: 'failed', code: 'dsh_turn_failed', error: 'dsh_turn_failed',
|
|
306
|
+
retryable: false, message };
|
|
307
|
+
return turn.outcome;
|
|
308
|
+
}
|
|
309
|
+
if (turn.cancelled || stopReason === 'cancelled') {
|
|
310
|
+
emitStatus(sessionId, turn.receiptId, 'blocked',
|
|
311
|
+
{ reason: 'dsh_turn_cancelled', message: TURN_CANCELLED_MESSAGE, source });
|
|
312
|
+
turn.outcome = { ok: false, status: 'blocked', code: 'dsh_turn_cancelled', error: 'dsh_turn_cancelled',
|
|
313
|
+
retryable: false, message: TURN_CANCELLED_MESSAGE };
|
|
314
|
+
return turn.outcome;
|
|
315
|
+
}
|
|
316
|
+
// WP-8 step 3 (§9b M-16, D-13): a COMPLETED turn is the second half of the model evidence — the
|
|
317
|
+
// bridge's `configOptions` show what the session ran, and the turn proves it actually ran. The
|
|
318
|
+
// model-state runtime owns the write (source `dsh:turn`); this lane only reports the edge, exactly
|
|
319
|
+
// once, and a failed observation write can never turn a completed turn into a failed one.
|
|
320
|
+
safeCall(() => observeCompletedTurn(session, configOptionsFor(sessionId)), 'observeCompletedTurn');
|
|
321
|
+
turn.outcome = { ok: true, status: 'sent', signal: 'durable_row', source };
|
|
322
|
+
return turn.outcome;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// §6.5 + §9 S-32. The delivery contract the root flow enforces is "delivered = the write was
|
|
326
|
+
// confirmed" (lib/root-delivery-runtime.js awaits this, then re-checks the delivery lease and the
|
|
327
|
+
// permit stays issued until it returns). A dsh turn can run for many minutes, so this returns as
|
|
328
|
+
// soon as `session/prompt` is on the wire and the turn settles in the BACKGROUND through
|
|
329
|
+
// runSettle — otherwise a long turn would report root_delivery_expired and pin the permit.
|
|
330
|
+
async function deliverAcp(session, args) {
|
|
331
|
+
const sessionId = session.id;
|
|
332
|
+
// Two preflights can pass before either delivery starts (§9 S-32), so the door is guarded here
|
|
333
|
+
// too: refuse exactly like the preflight wrap and send nothing.
|
|
334
|
+
if (turns.get(sessionId)?.inFlight) return turnInFlightBlocker();
|
|
335
|
+
// Two preflights can pass before either delivery starts (§9 S-32), and a wake can lose the race
|
|
336
|
+
// with a crash — so the door checks the asleep state too, and still sends nothing.
|
|
337
|
+
if (session._restoreDeferred) return asleepBlocker(session);
|
|
338
|
+
const receiptId = String(args.submissionId || args.parentReceiptId || '');
|
|
339
|
+
const source = String(args.source || 'dsh');
|
|
340
|
+
const runtime = getRuntime(sessionId);
|
|
341
|
+
if (!runtime || typeof runtime.client?.prompt !== 'function') {
|
|
342
|
+
return { ok: false, status: 'failed', code: 'dsh_not_running', error: 'dsh_not_running',
|
|
343
|
+
retryable: false, message: NOT_RUNNING_MESSAGE };
|
|
344
|
+
}
|
|
345
|
+
const transcript = session._dshTranscript;
|
|
346
|
+
const text = String(args.text ?? '');
|
|
347
|
+
// WP-11 (D-20): the images this submission names ride the submission's OWN `attachments` field
|
|
348
|
+
// (the same field lib/root-prompt-admission.js captures and lib/root-delivery-runtime.js hands to
|
|
349
|
+
// `deliverTerminal`). The capability door is checked FIRST, so an unsupported prompt writes
|
|
350
|
+
// nothing to the wire and nothing to the transcript (AC-11b).
|
|
351
|
+
const imageRefs = collectImageRefs(args.attachments);
|
|
352
|
+
if (imageRefs.length && runtime.imageInput !== true) {
|
|
353
|
+
return { ok: false, status: 'failed', code: IMAGE_UNSUPPORTED_CODE, error: IMAGE_UNSUPPORTED_CODE,
|
|
354
|
+
retryable: false, message: IMAGE_UNSUPPORTED_MESSAGE };
|
|
355
|
+
}
|
|
356
|
+
let images = [];
|
|
357
|
+
let blocks = null;
|
|
358
|
+
if (imageRefs.length) {
|
|
359
|
+
// Off the main loop: the bytes come from the async upload-store read (never sync fs), and an
|
|
360
|
+
// image CTM cannot read refuses the whole prompt rather than sending a prompt that quietly
|
|
361
|
+
// dropped it.
|
|
362
|
+
try {
|
|
363
|
+
images = (await Promise.all(imageRefs.map((ref) => Promise.resolve(readImageData(ref))))).filter(Boolean);
|
|
364
|
+
} catch (error) {
|
|
365
|
+
warn(`dsh-prompt-lane: image read failed (${error && error.message})`);
|
|
366
|
+
images = [];
|
|
367
|
+
}
|
|
368
|
+
if (images.length !== imageRefs.length) {
|
|
369
|
+
return { ok: false, status: 'failed', code: IMAGE_UNREADABLE_CODE, error: IMAGE_UNREADABLE_CODE,
|
|
370
|
+
retryable: false, message: IMAGE_UNREADABLE_MESSAGE };
|
|
371
|
+
}
|
|
372
|
+
// ACP content blocks: the text block first, then one block per image — the shape
|
|
373
|
+
// lib/acp/acp-client.js `prompt({ blocks })` already writes.
|
|
374
|
+
blocks = [{ type: 'text', text },
|
|
375
|
+
...images.map((image) => ({ type: 'image', mimeType: image.mimeType || 'image/png', data: image.data }))];
|
|
376
|
+
}
|
|
377
|
+
const turn = {
|
|
378
|
+
inFlight: true, cancelled: false, childExited: false, startedAt: now(), sawUpdate: false,
|
|
379
|
+
sessionId, receiptId, source, settled: null, outcome: null,
|
|
380
|
+
};
|
|
381
|
+
turns.set(sessionId, turn);
|
|
382
|
+
safeCall(() => transcript?.appendUserPrompt({ text, clientMessageId: receiptId || null, images }),
|
|
383
|
+
'appendUserPrompt');
|
|
384
|
+
emitStatus(sessionId, receiptId, 'received', { source });
|
|
385
|
+
safeCall(() => markTurnOpen(session), 'markTurnOpen');
|
|
386
|
+
|
|
387
|
+
let promptPromise;
|
|
388
|
+
try {
|
|
389
|
+
// A text-only prompt is passed EXACTLY as before (`{sessionId, text}` — no `blocks` key), so the
|
|
390
|
+
// bytes on the wire for every existing dsh prompt are unchanged (AC-11c).
|
|
391
|
+
promptPromise = blocks
|
|
392
|
+
? runtime.client.prompt({ sessionId: runtime.acpSessionId, text, blocks })
|
|
393
|
+
: runtime.client.prompt({ sessionId: runtime.acpSessionId, text });
|
|
394
|
+
} catch (error) {
|
|
395
|
+
// A synchronous throw means nothing reached the wire: keep the immediate failure result.
|
|
396
|
+
turns.delete(sessionId);
|
|
397
|
+
safeCall(() => markTurnClosed(session), 'markTurnClosed');
|
|
398
|
+
const message = (error && error.message) || NOT_RUNNING_MESSAGE;
|
|
399
|
+
safeCall(() => transcript?.appendTurnFailed(message), 'appendTurnFailed');
|
|
400
|
+
emitStatus(sessionId, receiptId, 'failed', { reason: 'dsh_turn_failed', message });
|
|
401
|
+
return { ok: false, status: 'failed', code: 'dsh_turn_failed', error: 'dsh_turn_failed',
|
|
402
|
+
retryable: false, message };
|
|
403
|
+
}
|
|
404
|
+
// The ACP client writes `session/prompt` synchronously inside prompt(), so the request is on the
|
|
405
|
+
// wire by the time the call returns and the durable signal is truthful here (§6.5).
|
|
406
|
+
emitStatus(sessionId, receiptId, 'durable_user_message_seen', { reason: 'dsh_prompt_written', source });
|
|
407
|
+
|
|
408
|
+
const settleOnce = (stopReason, failure) => {
|
|
409
|
+
try { return runSettle(session, turn, stopReason, failure); }
|
|
410
|
+
catch (error) {
|
|
411
|
+
warn(`dsh-prompt-lane: turn settle failed (${error && error.message})`);
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
// Both arms route through settleOnce, so this promise cannot reject — no unhandled rejection can
|
|
416
|
+
// ever come out of a dsh turn (T-10).
|
|
417
|
+
turn.settled = Promise.resolve(promptPromise).then(
|
|
418
|
+
(result) => settleOnce(String((result && result.stopReason) || ''), null),
|
|
419
|
+
(error) => settleOnce('', error),
|
|
420
|
+
);
|
|
421
|
+
settles.set(sessionId, turn.settled);
|
|
422
|
+
return { ok: true, status: 'sent', signal: 'durable_row', source };
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Wrap the root prompt flow's terminal deliverer: ACP sessions take the prompt themselves. */
|
|
426
|
+
function wrapDeliver(existing) {
|
|
427
|
+
return function deliverTerminal(...args) {
|
|
428
|
+
const submission = args[0] || {};
|
|
429
|
+
const session = getSession(submission.sessionId) || submission.target?.session || null;
|
|
430
|
+
if (!isAcpSession(session)) return existing(...args);
|
|
431
|
+
return deliverAcp(session, submission);
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Resolves once the in-flight turn's background settle has finished (with the settle outcome), or
|
|
437
|
+
* immediately with `null` when no turn is in flight. Test/WP-5 seam: the delivery itself no longer
|
|
438
|
+
* waits for the turn, so anything asserting the turn's END has to await this.
|
|
439
|
+
*/
|
|
440
|
+
function whenTurnSettled(sessionId) {
|
|
441
|
+
const pending = sessionId ? settles.get(sessionId) : null;
|
|
442
|
+
if (!pending) return Promise.resolve(null);
|
|
443
|
+
return pending.then(
|
|
444
|
+
(outcome) => outcome || null,
|
|
445
|
+
(error) => { warn(`dsh-prompt-lane: turn settle rejected (${error && error.message})`); return null; },
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// --- cancel (§9 S-33) ------------------------------------------------------------------------
|
|
450
|
+
|
|
451
|
+
/** Stop an in-flight ACP turn. Anything else (including an idle ACP session) uses the fallback. */
|
|
452
|
+
function interruptOr(session, fallback) {
|
|
453
|
+
if (!isAcpSession(session)) return fallback;
|
|
454
|
+
const sessionId = session && session.id;
|
|
455
|
+
const turn = sessionId ? turns.get(sessionId) : null;
|
|
456
|
+
if (!turn || !turn.inFlight) return fallback;
|
|
457
|
+
const runtime = getRuntime(sessionId);
|
|
458
|
+
if (!runtime || typeof runtime.client?.cancel !== 'function') return fallback;
|
|
459
|
+
turn.cancelled = true;
|
|
460
|
+
try {
|
|
461
|
+
// The client answers this session's pending permissions `cancelled` itself (P-4); the lane
|
|
462
|
+
// then settles its own promises, so a permission is still answered exactly once.
|
|
463
|
+
runtime.client.cancel({ sessionId: runtime.acpSessionId });
|
|
464
|
+
} catch (error) {
|
|
465
|
+
warn(`dsh-prompt-lane: session/cancel failed (${error && error.message})`);
|
|
466
|
+
turn.cancelled = false;
|
|
467
|
+
return fallback;
|
|
468
|
+
}
|
|
469
|
+
settlePermissions(sessionId, 'cancelled');
|
|
470
|
+
return { ok: true };
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// --- approvals (D-7, §9 S-35, T-10) ----------------------------------------------------------
|
|
474
|
+
|
|
475
|
+
/** One `session/request_permission`: register a runtime approval, park until a decision. */
|
|
476
|
+
function onRequestPermission(ctmSessionId, params = {}) {
|
|
477
|
+
const session = getSession(ctmSessionId);
|
|
478
|
+
const options = Array.isArray(params.options) ? params.options : [];
|
|
479
|
+
const toolCallId = String(params.toolCall?.toolCallId || '');
|
|
480
|
+
const tracked = toolCalls.get(ctmSessionId);
|
|
481
|
+
const tool = tracked && (!toolCallId || String(tracked.toolCallId || '') === toolCallId)
|
|
482
|
+
? tracked
|
|
483
|
+
: (params.toolCall && typeof params.toolCall === 'object' ? params.toolCall : {});
|
|
484
|
+
const title = String(tool.title || tool.name || tool.kind || 'Tool call');
|
|
485
|
+
const rawInput = tool.rawInput && typeof tool.rawInput === 'object' ? tool.rawInput : {};
|
|
486
|
+
const approvalOptions = options.map((option) => ({
|
|
487
|
+
optionId: String(option?.optionId || ''),
|
|
488
|
+
label: String(option?.name || ''),
|
|
489
|
+
decision: decisionForAcpKind(option?.kind),
|
|
490
|
+
}));
|
|
491
|
+
// `hook:` is the prefix lib/runtime-approval-executor.js routes to the isHookPending/resolveHook
|
|
492
|
+
// seam — the seam the server wraps for ACP sessions (S-35).
|
|
493
|
+
const approvalId = `hook:dsh:${ctmSessionId}:${toolCallId || 'permission'}`;
|
|
494
|
+
const record = { approvalId, ctmSessionId, toolCallId, options: approvalOptions, settled: false, resolve: null };
|
|
495
|
+
const pending = new Promise((resolve) => { record.resolve = resolve; });
|
|
496
|
+
const list = pendingList(ctmSessionId);
|
|
497
|
+
list.push(record);
|
|
498
|
+
permissions.set(ctmSessionId, list);
|
|
499
|
+
safeCall(recordRuntimeApprovalRequested, 'recordRuntimeApprovalRequested', {
|
|
500
|
+
approvalId,
|
|
501
|
+
ctmSessionId,
|
|
502
|
+
adapter: 'dsh',
|
|
503
|
+
source: 'dsh-acp',
|
|
504
|
+
turnId: turns.get(ctmSessionId)?.turnId || '',
|
|
505
|
+
toolCallId,
|
|
506
|
+
toolName: title,
|
|
507
|
+
prompt: summarizeInput(rawInput, title),
|
|
508
|
+
approvalOptions,
|
|
509
|
+
metadata: { toolCallId },
|
|
510
|
+
});
|
|
511
|
+
safeCall(() => markWaiting(session, true), 'markWaiting');
|
|
512
|
+
return pending;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** Is an ACP permission pending for this session? (The executor's isHookPending seam, S-35.) */
|
|
516
|
+
function isPending(sessionId) {
|
|
517
|
+
return pendingList(sessionId).some((record) => !record.settled);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Answers the ACP request with the optionId the bridge itself offered for this decision.
|
|
521
|
+
function answerPermission(record, allow) {
|
|
522
|
+
if (record.settled) return false;
|
|
523
|
+
record.settled = true;
|
|
524
|
+
dropPermission(record.ctmSessionId, record);
|
|
525
|
+
const optionId = optionIdForDecision(record.options, allow);
|
|
526
|
+
record.resolve(optionId ? { outcome: 'selected', optionId } : { outcome: 'cancelled' });
|
|
527
|
+
safeCall(() => markWaiting(getSession(record.ctmSessionId), false), 'markWaiting');
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/** The executor's resolveHook seam (S-35): resolve a pending ACP permission. */
|
|
532
|
+
function resolvePermission(sessionId, decision, source, approvalId) {
|
|
533
|
+
const list = pendingList(sessionId).filter((record) => !record.settled);
|
|
534
|
+
if (!list.length) return false;
|
|
535
|
+
const record = (approvalId && list.find((entry) => entry.approvalId === approvalId)) || list[0];
|
|
536
|
+
const allow = String(decision || '').toLowerCase() === 'allow';
|
|
537
|
+
void source; // the executor persists the decision through resolveRuntimeApproval itself
|
|
538
|
+
return answerPermission(record, allow);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Every pending permission answers `cancelled` exactly once and its runtime approval resolves
|
|
542
|
+
// `expired` (T-10). Idempotent: a settled record is never touched again.
|
|
543
|
+
function settlePermissions(sessionId, outcome) {
|
|
544
|
+
let settled = 0;
|
|
545
|
+
for (const record of [...pendingList(sessionId)]) {
|
|
546
|
+
if (record.settled) continue;
|
|
547
|
+
record.settled = true;
|
|
548
|
+
dropPermission(sessionId, record);
|
|
549
|
+
record.resolve({ outcome });
|
|
550
|
+
safeCall(resolveRuntimeApproval, 'resolveRuntimeApproval', record.approvalId, {
|
|
551
|
+
ctmSessionId: sessionId,
|
|
552
|
+
status: 'expired',
|
|
553
|
+
decidedBy: 'dsh-session',
|
|
554
|
+
metadata: { toolCallId: record.toolCallId },
|
|
555
|
+
});
|
|
556
|
+
settled += 1;
|
|
557
|
+
}
|
|
558
|
+
return settled;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/** The ACP child is gone (stop, cancel-after-exit, or a crash): nothing may stay parked. */
|
|
562
|
+
function onChildExit(ctmSessionId) {
|
|
563
|
+
const turn = turns.get(ctmSessionId);
|
|
564
|
+
if (turn) {
|
|
565
|
+
turn.inFlight = false;
|
|
566
|
+
turn.childExited = true;
|
|
567
|
+
turns.delete(ctmSessionId);
|
|
568
|
+
}
|
|
569
|
+
const settled = settlePermissions(ctmSessionId, 'cancelled');
|
|
570
|
+
toolCalls.delete(ctmSessionId);
|
|
571
|
+
return settled;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
function turnState(sessionId) {
|
|
575
|
+
const turn = turns.get(sessionId);
|
|
576
|
+
return turn ? { inFlight: !!turn.inFlight, cancelled: !!turn.cancelled } : null;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// WP-8 step 3 (§6.7): the read-only half of `turnState` for callers that only need the yes/no — the
|
|
580
|
+
// ACP runtime refuses a config-option write while a prompt is in flight (never queues it), and it
|
|
581
|
+
// asks through this one predicate. Anything but an explicit `true` reads as "no turn".
|
|
582
|
+
function isTurnInFlight(sessionId) {
|
|
583
|
+
return turns.get(sessionId)?.inFlight === true;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// The bridge's own `configOptions` for a live ACP child — what the session is ACTUALLY running. A
|
|
587
|
+
// gone child (the runtime entry is dropped on exit) reads as null, never as a stale list.
|
|
588
|
+
function configOptionsFor(sessionId) {
|
|
589
|
+
const runtime = getRuntime(sessionId);
|
|
590
|
+
return runtime && Array.isArray(runtime.configOptions) ? runtime.configOptions : null;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
return {
|
|
594
|
+
wrapPreflight,
|
|
595
|
+
wrapDeliver,
|
|
596
|
+
interruptOr,
|
|
597
|
+
onUpdate,
|
|
598
|
+
onRequestPermission,
|
|
599
|
+
isPending,
|
|
600
|
+
resolvePermission,
|
|
601
|
+
onChildExit,
|
|
602
|
+
turnState,
|
|
603
|
+
isTurnInFlight,
|
|
604
|
+
whenTurnSettled,
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
module.exports = {
|
|
609
|
+
createDshPromptLane,
|
|
610
|
+
ACP_KIND_TO_DECISION,
|
|
611
|
+
TURN_IN_FLIGHT_MESSAGE,
|
|
612
|
+
IMAGE_UNSUPPORTED_CODE,
|
|
613
|
+
IMAGE_UNSUPPORTED_MESSAGE,
|
|
614
|
+
IMAGE_UNREADABLE_CODE,
|
|
615
|
+
IMAGE_UNREADABLE_MESSAGE,
|
|
616
|
+
};
|