create-walle 0.10.1 → 0.10.2
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 +4 -0
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +6 -4
- package/package.json +1 -1
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +55 -17
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +1 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +2 -2
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +4 -2
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +902 -239
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +6 -4
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
|
@@ -16,10 +16,11 @@ const {
|
|
|
16
16
|
} = require('./lifecycle-wake-experiment');
|
|
17
17
|
const projectConfig = require('./project-config');
|
|
18
18
|
const { resolveResumeCwdFallback } = require('./resume-cwd');
|
|
19
|
-
const { validateResumeTarget, withTrashLocation } = require('./resume-preflight');
|
|
19
|
+
const { validateResumeTarget, withTrashLocation, findClaudeResumeTranscript, transcriptHasConversation } = require('./resume-preflight');
|
|
20
20
|
const { findTrashedTranscript } = require('./session-transcript-trash');
|
|
21
21
|
const sessionHistory = require('./session-history');
|
|
22
22
|
const { extractResumeTarget, getCodexThreadResumeCwdInfo, locateCodexRollout } = sessionHistory;
|
|
23
|
+
const { ensureClaudeResumeTarget } = require('./launch-model-override');
|
|
23
24
|
const walleMcpAutoConfig = require('./walle-mcp-auto-config');
|
|
24
25
|
const { ensureWalleMcpForAgentSession } = walleMcpAutoConfig;
|
|
25
26
|
const {
|
|
@@ -228,7 +229,15 @@ async function prepareLaunchPlan(spec = {}, progressPort = parentPort) {
|
|
|
228
229
|
cwd = fallback.cwd || cwd;
|
|
229
230
|
|
|
230
231
|
let agentType = agentTypeForCommand(cmd);
|
|
231
|
-
|
|
232
|
+
// WP-0 D-2: for the PRIVATE Claude model-target operation below, the recorded source argv must reach
|
|
233
|
+
// the native-history classification UNTOUCHED. resolveResumeAlias is a naive
|
|
234
|
+
// `indexOf('--resume')` + metadata rewrite, and an argument that merely SPELLS `--resume` while being
|
|
235
|
+
// another option's operand (e.g. `--append-system-prompt --resume`) would be rewritten before the
|
|
236
|
+
// canonical normalizer ever sees it. Ordinary create/restore callers and Codex keep today's order.
|
|
237
|
+
const defersClaudeResumeAlias = agentType === 'claude' && spec.claudeResumeThreadId !== undefined;
|
|
238
|
+
let resumeResolution = defersClaudeResumeAlias
|
|
239
|
+
? { args, resume: extractResumeTarget(agentType, args) }
|
|
240
|
+
: resolveResumeAlias(agentType, args, metadata);
|
|
232
241
|
args = resumeResolution.args;
|
|
233
242
|
let resume = resumeResolution.resume;
|
|
234
243
|
|
|
@@ -283,6 +292,54 @@ async function prepareLaunchPlan(spec = {}, progressPort = parentPort) {
|
|
|
283
292
|
const cliResolution = resolvePublishedCliCommand(cmd, spec, env);
|
|
284
293
|
cmd = cliResolution.cmd;
|
|
285
294
|
agentType = agentTypeForCommand(cmd);
|
|
295
|
+
// WP-0 D-2 (same-harness, early): the project config above may have just rewritten this launch to a
|
|
296
|
+
// DIFFERENT harness, and the Codex-specific MCP/profile rewrites and prepareCodexLaunch() run long
|
|
297
|
+
// before a plan is returned. The private Claude model-target field names a Claude thread, so a launch
|
|
298
|
+
// that resolved to another harness is refused HERE -- before any of that preparation -- instead of
|
|
299
|
+
// executing Codex preparation and only then refusing the produced plan.
|
|
300
|
+
// Ordinary callers never set the private field, and Codex callers never set it either, so their
|
|
301
|
+
// behavior is unchanged. The planner's post-plan same-harness guard remains as the outer defence.
|
|
302
|
+
if (spec.claudeResumeThreadId !== undefined && agentType !== 'claude') {
|
|
303
|
+
const error = new TypeError('spec.claudeResumeThreadId names a Claude thread but the launch resolved to another harness');
|
|
304
|
+
error.code = 'launch_claude_target_harness_changed';
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
// WP-0 (docs/claude-routed-native-history-resume-2026-10-24.html §5 D-2, §6): a Claude
|
|
308
|
+
// MODEL-TARGET preparation names the canonical source thread through the PRIVATE spec field
|
|
309
|
+
// `claudeResumeThreadId`, which only the lead-transition target planner sets after its canonical
|
|
310
|
+
// source proof. Claude keeps its own native transcript, so the launch must RESUME that exact
|
|
311
|
+
// thread instead of starting the recorded `--session-id` again (which would collide with the
|
|
312
|
+
// conversation already on disk). The classification below is the EXISTING native preflight --
|
|
313
|
+
// findClaudeResumeTranscript + transcriptHasConversation -- never a second reader, and nothing is
|
|
314
|
+
// written, moved, deleted or materialized here.
|
|
315
|
+
//
|
|
316
|
+
// A source with no recorded conversation is left EXACTLY as it is (today's fresh-launch
|
|
317
|
+
// behavior): forcing `--resume` onto a metadata-only stub is what the CLI answers with
|
|
318
|
+
// "No conversation found". The field is private to this worker spec, so an ordinary
|
|
319
|
+
// create/restore caller -- which never sets it -- cannot reach this block at all.
|
|
320
|
+
if (agentType === 'claude' && spec.claudeResumeThreadId !== undefined) {
|
|
321
|
+
const canonicalThreadId = String(spec.claudeResumeThreadId || '').trim();
|
|
322
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(canonicalThreadId)) {
|
|
323
|
+
const error = new TypeError('spec.claudeResumeThreadId must be the canonical Claude thread id');
|
|
324
|
+
error.code = 'launch_claude_resume_target_invalid';
|
|
325
|
+
throw error;
|
|
326
|
+
}
|
|
327
|
+
const canonicalTranscript = findClaudeResumeTranscript({
|
|
328
|
+
resumeId: canonicalThreadId,
|
|
329
|
+
jsonlPath: metadata.resumeAgent?.jsonl_path || metadata.resolved?.jsonl_path || '',
|
|
330
|
+
homeDir,
|
|
331
|
+
claudeConfigDir: env.CLAUDE_CONFIG_DIR || spec.claudeConfigDir,
|
|
332
|
+
});
|
|
333
|
+
if (canonicalTranscript && transcriptHasConversation(canonicalTranscript.path)) {
|
|
334
|
+
const normalized = ensureClaudeResumeTarget(args, canonicalThreadId);
|
|
335
|
+
if (!normalized.ok) {
|
|
336
|
+
const error = new TypeError(`the recorded Claude launch arguments cannot name the canonical thread: ${normalized.reason}`);
|
|
337
|
+
error.code = normalized.reason;
|
|
338
|
+
throw error;
|
|
339
|
+
}
|
|
340
|
+
args = normalized.args;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
286
343
|
resumeResolution = resolveResumeAlias(agentType, args, metadata);
|
|
287
344
|
args = resumeResolution.args;
|
|
288
345
|
resume = resumeResolution.resume;
|
|
@@ -217,6 +217,13 @@ function createLeadTransitionTargetPlanner(deps = {}) {
|
|
|
217
217
|
const cwd = task.cwd || session.cwd || '';
|
|
218
218
|
const agentType = detectAgentType(cmd);
|
|
219
219
|
const resume = extractResumeTarget(agentType, args);
|
|
220
|
+
// D-2 (docs/claude-routed-native-history-resume-2026-10-24.html §5 D-2, §6): a Claude target
|
|
221
|
+
// launch must name the canonical SOURCE thread -- never an old startup/parent selector still
|
|
222
|
+
// sitting in the recorded argv -- so the canonical owner's own provider thread is what the
|
|
223
|
+
// metadata read is keyed by, and the private spec field below is what the launch-plan worker
|
|
224
|
+
// classifies/normalizes against. Both are derived ONLY here, after the canonical source proof
|
|
225
|
+
// below; no client/API caller and no ordinary create/restore caller sets either.
|
|
226
|
+
const canonicalThreadId = String(source?.providerThreadId || '');
|
|
220
227
|
// The canonical SOURCE proof: the injected model runtime's owner must name THIS session, agent and
|
|
221
228
|
// provider thread at exactly the submitted generation — generation 0 included. A missing owner is
|
|
222
229
|
// refused here, BEFORE any reservation, metadata read or plan.
|
|
@@ -241,12 +248,19 @@ function createLeadTransitionTargetPlanner(deps = {}) {
|
|
|
241
248
|
const generation = reserved.generation;
|
|
242
249
|
const launchMetadata = await runReadPoolOp('readLaunchMetadata', {
|
|
243
250
|
dbPath: dbModule.getDbPath(), baseDbPath: dbModule.getDbPath(), sessionId,
|
|
244
|
-
resumeId:
|
|
251
|
+
resumeId: agentType === 'claude' ? canonicalThreadId : (resume?.sessionId || ''),
|
|
252
|
+
telemetryReason: 'lead-transition-target-preflight',
|
|
245
253
|
}, { timeoutMs: 10_000, signal });
|
|
246
254
|
if (identityGone()) return { ok: false, reason: 'lead_source_generation_changed' };
|
|
247
255
|
cacheSessionOwnershipProjection(sessionId, launchMetadata?.resolved || launchMetadata || null);
|
|
248
256
|
const mcpProfile = sessionMcpProfileSetting(task);
|
|
249
|
-
|
|
257
|
+
// Only Codex gathers warm-plan inputs. A Claude model-target preparation opts out of that cache
|
|
258
|
+
// entirely, because its key (transcript freshness, cwd, codex config, CLI stamp) cannot describe
|
|
259
|
+
// the same-thread resume operation below -- and a value that is computed only to be discarded
|
|
260
|
+
// would still cost the read.
|
|
261
|
+
const warmPlanInputs = agentType === 'codex'
|
|
262
|
+
? await launchPlanWarmInputs({ agentType, cwd, launchMetadata, mcpProfile })
|
|
263
|
+
: null;
|
|
250
264
|
if (identityGone()) return { ok: false, reason: 'lead_source_generation_changed' };
|
|
251
265
|
const capturedLaunch = session._modelTransitionLaunchContext || {};
|
|
252
266
|
const launchHomeDir = session._launchEnvOverrides?.HOME || capturedLaunch.homeDir || serverConfig.HOME;
|
|
@@ -262,11 +276,36 @@ function createLeadTransitionTargetPlanner(deps = {}) {
|
|
|
262
276
|
env: targetPlanEnv,
|
|
263
277
|
homeDir: launchHomeDir, cliCacheFile: agentCliCacheFile, codexHome: launchCodexHome,
|
|
264
278
|
codexTransportGuard: serverConfig.CTM_CODEX_MCP_TRANSPORT_GUARD !== '0', wallePort,
|
|
265
|
-
isRestore: true, launchMetadata, mcpProfile,
|
|
279
|
+
isRestore: true, launchMetadata, mcpProfile,
|
|
280
|
+
warmPlanInputs,
|
|
281
|
+
lane: 'interactive',
|
|
266
282
|
transcriptTrashRoot: sessionTranscriptTrashRoot,
|
|
283
|
+
// PRIVATE internal argument (never persisted, never published, never accepted from a client):
|
|
284
|
+
// the canonical source thread the produced plan must resume. Only this planner sets it.
|
|
285
|
+
...(agentType === 'claude' ? { claudeResumeThreadId: canonicalThreadId } : {}),
|
|
267
286
|
});
|
|
268
287
|
if (identityGone()) return { ok: false, reason: 'lead_source_generation_changed' };
|
|
269
288
|
if (!result?.plan || Number(result.plan.generation) !== generation) return { ok: false, reason: 'lead_target_plan_unavailable' };
|
|
289
|
+
// D-2/D-3: the produced plan must still name the canonical thread in its argv AND in its resume
|
|
290
|
+
// metadata, and the two must AGREE about whether there is a resume target at all.
|
|
291
|
+
// `resolveResumeAlias` may re-resolve a Claude resume id out of the metadata row, so a plan that
|
|
292
|
+
// ends up on ANOTHER thread is refused here -- before the controller ever parks the source. Both
|
|
293
|
+
// absent is the legitimate native no-history fresh launch; exactly one absent is an inconsistent
|
|
294
|
+
// plan (an argv the launcher will act on that the metadata denies, or the reverse).
|
|
295
|
+
if (agentType === 'claude') {
|
|
296
|
+
// Same-harness guard: project config's applyToSpec may substitute the live Claude `cmd`, so a
|
|
297
|
+
// plan for ANOTHER harness (or a plan that does not name its harness at all) is refused here
|
|
298
|
+
// rather than being accepted as this planner's fresh/both-absent result.
|
|
299
|
+
if (result.plan.agentType !== 'claude') return { ok: false, reason: 'lead_target_harness_changed' };
|
|
300
|
+
const planArgs = Array.isArray(result.plan.args) ? result.plan.args : [];
|
|
301
|
+
const argvResume = extractResumeTarget('claude', planArgs);
|
|
302
|
+
const argvId = argvResume ? String(argvResume.sessionId || '') : '';
|
|
303
|
+
const metadataId = String(result.plan.resume?.sessionId || '');
|
|
304
|
+
if (!!argvId !== !!metadataId) return { ok: false, reason: 'lead_target_resume_inconsistent' };
|
|
305
|
+
if (argvId && (argvId !== canonicalThreadId || metadataId !== canonicalThreadId)) {
|
|
306
|
+
return { ok: false, reason: 'lead_target_resume_changed' };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
270
309
|
noteLaunchPlanReadinessGeneration(result.plan);
|
|
271
310
|
return { ok: true, generation, launchPlan: result.plan, sourceGeneration };
|
|
272
311
|
};
|
|
@@ -670,7 +709,10 @@ function createLeadModelSwitchRuntime(host) {
|
|
|
670
709
|
const targetRecipe = {
|
|
671
710
|
id: targetRecipeId, sessionId, providerThreadId: source.providerThreadId, harness,
|
|
672
711
|
providerId: target.routeId || 'unknown', origin: target.routeId ? 'routed-proxy' : 'unknown',
|
|
673
|
-
|
|
712
|
+
// The marker names the Codex app-server conversion adapter. A Claude target -- routed or
|
|
713
|
+
// native -- has no conversion adapter at all, so recording the Codex one there would claim a
|
|
714
|
+
// conversion this operation never performs (same-harness native resume).
|
|
715
|
+
controlAdapterVersion: harness === 'codex-cli' && target.routeId ? CODEX_CONTROL_ADAPTER : null,
|
|
674
716
|
programVersion: null, cyberAccessProgram: null,
|
|
675
717
|
routeId: target.routeId || null,
|
|
676
718
|
wireModelId: target.routeId ? (target.modelId || null) : null, processGeneration: targetPlan.generation,
|
|
@@ -758,6 +800,17 @@ function createLeadModelSwitchRuntime(host) {
|
|
|
758
800
|
const rebound = require('./launch-model-override').ensureCodexResumeTarget(recoveryArgs, source.providerThreadId);
|
|
759
801
|
if (!rebound.ok) return { ok: false, reason: rebound.reason };
|
|
760
802
|
recoveryArgs = rebound.args;
|
|
803
|
+
} else if (source.agent === 'claude') {
|
|
804
|
+
// The SAME normalization for a native Claude source. A captured Claude argv may select its
|
|
805
|
+
// thread through `--resume` OR through an explicit `--session-id` (a fresh identity CTM
|
|
806
|
+
// injected at startup), and it may still carry that launch's own initial positional prompt.
|
|
807
|
+
// The existing pure normalizer produces exactly one canonical `--resume <source thread>`
|
|
808
|
+
// prefix: every permission/settings operand survives, while the selector that named the
|
|
809
|
+
// thread and the one-shot startup prompt do not -- so a rollback resumes the SAME
|
|
810
|
+
// conversation instead of replaying the original task as a new turn.
|
|
811
|
+
const rebound = require('./launch-model-override').ensureClaudeResumeTarget(recoveryArgs, source.providerThreadId);
|
|
812
|
+
if (!rebound.ok) return { ok: false, reason: rebound.reason };
|
|
813
|
+
recoveryArgs = rebound.args;
|
|
761
814
|
}
|
|
762
815
|
const selectedSourceThread = extractResumeTarget(source.agent, recoveryArgs)?.sessionId || '';
|
|
763
816
|
if (selectedSourceThread !== sourceThreadId) return { ok: false, reason: 'source_launch_context_unavailable' };
|
|
@@ -393,6 +393,7 @@ function createLeadModelSwitch(deps) {
|
|
|
393
393
|
entry.recovered = !!result?.ok;
|
|
394
394
|
if (!entry.recovered) {
|
|
395
395
|
entry.req.recovery_reason = 'source_recovery_failed';
|
|
396
|
+
diagnostic(entry.req.ctm_session_id, 'lead-transition-source-recovery-failed', { reason: String(result?.reason || 'unknown').slice(0, 120) });
|
|
396
397
|
const cause = entry.failureOutcome?.detail || 'The requested target was not applied.';
|
|
397
398
|
entry.req.detail = `${cause} The captured source provider could not be restored.`;
|
|
398
399
|
} else {
|
|
@@ -480,7 +481,7 @@ function createLeadModelSwitch(deps) {
|
|
|
480
481
|
return refuse(409, 'client_request_conflict');
|
|
481
482
|
}
|
|
482
483
|
if (existing?.confirmationPromise) return refuse(409, 'lead_transition_committing', { request: publicRequest(existing.req) });
|
|
483
|
-
if (existing?.handoffStarted && !existing.recovered && ['cancelled', 'failed'].includes(existing.req.state)) {
|
|
484
|
+
if (existing?.handoffStarted && (existing.sourceParked || existing.targetStarted) && !existing.recovered && ['cancelled', 'failed'].includes(existing.req.state)) {
|
|
484
485
|
return refuse(409, 'lead_switch_recovery_in_flight', { request: publicRequest(existing.req) });
|
|
485
486
|
}
|
|
486
487
|
if (existing?.req.state === 'awaiting_turn' && existing.handoffStarted && !existing.recovered) {
|
|
@@ -767,7 +768,7 @@ function createLeadModelSwitch(deps) {
|
|
|
767
768
|
return refuse(500, 'lead_transition_persist_failed', { message: String(error?.message || error).slice(0, 200) });
|
|
768
769
|
}
|
|
769
770
|
}
|
|
770
|
-
if (providerTransition) {
|
|
771
|
+
if (providerTransition && info.agent !== 'claude') {
|
|
771
772
|
if (!entry.transition) { requestControllers.delete(id); fail(entry, 'lead_transition_owner_unavailable', 'The transition owner is not available.'); return refuse(409, 'lead_transition_owner_unavailable'); }
|
|
772
773
|
try {
|
|
773
774
|
historyPreparation = await prepareHistory({
|
|
@@ -261,11 +261,41 @@ function createLeadModelTransitionStore({
|
|
|
261
261
|
const getActiveForSession = (ctmSessionId) => {
|
|
262
262
|
const sessionId = String(ctmSessionId || '').trim();
|
|
263
263
|
if (!sessionId || sessionId.length > 128) return null;
|
|
264
|
-
const
|
|
264
|
+
const db = getCoreDb();
|
|
265
|
+
// An explicit CTM_DB_DOMAIN_SPLIT=0 boot never stamps v18, so the v49 journal is never
|
|
266
|
+
// created there. A journal that does not exist holds no active transition: answer that
|
|
267
|
+
// truthfully instead of throwing, which made every deferred restore on such a boot refuse
|
|
268
|
+
// with lead-transition-reconciliation-unavailable.
|
|
269
|
+
if (!db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type='table' AND name='coding_model_transitions'").get()) return null;
|
|
270
|
+
const row = db.prepare(`SELECT transition_id FROM coding_model_transitions
|
|
265
271
|
WHERE ctm_session_id=? AND state IN ('queued','preparing','compacting','verified','handing_off','awaiting_turn')
|
|
266
272
|
ORDER BY updated_at DESC, transition_id DESC LIMIT 1`).get(sessionId);
|
|
267
273
|
return row ? get(row.transition_id) : null;
|
|
268
274
|
};
|
|
275
|
+
// WP-1 (docs/codex-routed-fork-cold-restore-guard-2026-10-22.html §5 D-3, §9 S-6): the journal
|
|
276
|
+
// reader the launch-time route reconciliation needs. `getActiveForSession` excludes terminal
|
|
277
|
+
// states, but the repair must find the fork a transition ACTUALLY launched even after it failed, so
|
|
278
|
+
// this reads ANY state, newest revision first, with the parsed target recipe beside the row
|
|
279
|
+
// identity. Read-only and bounded; a malformed recipe JSON is skipped, never surfaced.
|
|
280
|
+
const listForThread = (ctmSessionId, providerThreadId) => {
|
|
281
|
+
const sessionId = String(ctmSessionId || '').trim();
|
|
282
|
+
const threadId = String(providerThreadId || '').trim();
|
|
283
|
+
if (!sessionId || sessionId.length > 128 || !threadId || threadId.length > 512) return [];
|
|
284
|
+
const rows = getCoreDb().prepare(`SELECT transition_id, revision, state, target_recipe_json
|
|
285
|
+
FROM coding_model_transitions WHERE ctm_session_id = ? ORDER BY revision DESC, updated_at DESC, transition_id DESC`)
|
|
286
|
+
.all(sessionId);
|
|
287
|
+
const out = [];
|
|
288
|
+
for (const row of rows) {
|
|
289
|
+
let targetRecipe;
|
|
290
|
+
try { targetRecipe = JSON.parse(row.target_recipe_json); } catch { continue; /* expected: a corrupt recipe is not a route source */ }
|
|
291
|
+
out.push({
|
|
292
|
+
transition_id: row.transition_id, revision: Number(row.revision), state: row.state, target_recipe: targetRecipe,
|
|
293
|
+
provider_thread_id: targetRecipe?.providerThreadId || null, route_id: targetRecipe?.routeId || null,
|
|
294
|
+
model: targetRecipe?.wireModelId || null, harness: targetRecipe?.harness || null,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
};
|
|
269
299
|
function saveProfile(profile = {}) {
|
|
270
300
|
const allowed = new Set(['fingerprint', 'harness', 'cliVersion', 'adapterVersion', 'deployment', 'artifactPath', 'evidenceReceipt']);
|
|
271
301
|
if (Object.keys(profile).some((key) => !allowed.has(key))) throw new TypeError('profile contains an unapproved field');
|
|
@@ -690,11 +720,39 @@ function createLeadModelTransitionStore({
|
|
|
690
720
|
if (!row) return null;
|
|
691
721
|
try { return { ...row, bindings: JSON.parse(row.bindings_json) }; } catch { return null; }
|
|
692
722
|
}
|
|
693
|
-
return { get, getActiveForSession, getStagedToken, saveProfile, begin, advance, commit, stageToken, recordFork, clearStagedToken };
|
|
723
|
+
return { get, getActiveForSession, listForThread, getStagedToken, saveProfile, begin, advance, commit, stageToken, recordFork, clearStagedToken };
|
|
694
724
|
}
|
|
695
725
|
|
|
696
726
|
// `validateRecipe` is exported so the approved-intent store can reuse the ONE complete bounded
|
|
697
727
|
// journal recipe validation instead of keeping a parallel whitelist that silently drops (or refuses)
|
|
698
728
|
// the real producer's provider/context metadata. This module imports only the PURE intent contract,
|
|
699
729
|
// so the store importing this export introduces no construction cycle.
|
|
700
|
-
|
|
730
|
+
// The provider thread of a FORK the session's active transition is still trying, or null. Until
|
|
731
|
+
// commit() moves the startup pointer, that thread is a candidate: the startup row keeps the source so
|
|
732
|
+
// a cold start before the first confirmed target turn resumes the source. Every startup-pointer writer
|
|
733
|
+
// (db.js updateStartupTaskAgentSession) asks this on the same handle, inside its own transaction.
|
|
734
|
+
function activeCandidateForkThread(db, ctmSessionId) {
|
|
735
|
+
// A core schema without the journal (pre-migration fixtures) has no transitions, so no candidate.
|
|
736
|
+
if (!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='coding_model_transitions'").get()) return null;
|
|
737
|
+
const row = db.prepare(`SELECT source_recipe_json, target_recipe_json FROM coding_model_transitions
|
|
738
|
+
WHERE ctm_session_id=? AND state IN (${[...ACTIVE_STATES].map(() => '?').join(',')})
|
|
739
|
+
ORDER BY updated_at DESC, transition_id DESC LIMIT 1`).get(String(ctmSessionId || ''), ...ACTIVE_STATES);
|
|
740
|
+
if (!row) return null;
|
|
741
|
+
let source, target;
|
|
742
|
+
try { source = JSON.parse(row.source_recipe_json); target = JSON.parse(row.target_recipe_json); }
|
|
743
|
+
catch { return null; } // expected: a malformed journal row is refused by every transition reader; it names no candidate
|
|
744
|
+
const thread = String(target?.providerThreadId || '');
|
|
745
|
+
return thread && thread !== String(source?.providerThreadId || '') ? thread : null;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// The startup-pointer writers' guard (db.js updateStartupTaskAgentSession). Live: a fork relaunch wrote
|
|
749
|
+
// `resume <target>` and the commit then refused "startup task does not point at the captured source
|
|
750
|
+
// provider thread".
|
|
751
|
+
function resumesCandidateFork(db, ctmSessionId, resumeArgs) {
|
|
752
|
+
const candidate = Array.isArray(resumeArgs) ? activeCandidateForkThread(db, ctmSessionId) : null;
|
|
753
|
+
if (!candidate || !resumeArgs.some((arg) => String(arg) === candidate)) return false;
|
|
754
|
+
console.warn(`[startup-task] kept the source pointer for ${String(ctmSessionId).slice(0, 8)}: ${candidate.slice(0, 8)} is an uncommitted fork`);
|
|
755
|
+
return true;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
module.exports = { ACTIVE_STATES, createLeadModelTransitionStore, validateRecipe, activeCandidateForkThread, resumesCandidateFork };
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { createMediaJournalControlReader } = require('./media-journal-control-reader');
|
|
5
|
+
|
|
6
|
+
function unavailable(cause) {
|
|
7
|
+
return Object.assign(new Error('Pending image cancellation recovery is unavailable', { cause }), {
|
|
8
|
+
code: 'CTM_MEDIA_JOURNAL_UNAVAILABLE',
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// One recovery scope per logical DB handle and journal directory. No new SQL owner: the caller
|
|
13
|
+
// supplies the same worker projector used by the write-behind store. Neither journal nor cursor
|
|
14
|
+
// is advanced, because unrelated content must remain available to its ordinary replay owner.
|
|
15
|
+
function createLegacyDraftCancellationRecovery({ getDirectory, getContext, projectEntry }) {
|
|
16
|
+
for (const callback of [getDirectory, getContext, projectEntry]) {
|
|
17
|
+
if (typeof callback !== 'function') throw new TypeError('Cancellation recovery requires callbacks');
|
|
18
|
+
}
|
|
19
|
+
let scope = null;
|
|
20
|
+
let operation = null;
|
|
21
|
+
let retired = false;
|
|
22
|
+
let closing = null;
|
|
23
|
+
|
|
24
|
+
function binding() {
|
|
25
|
+
const context = getContext();
|
|
26
|
+
const directory = getDirectory();
|
|
27
|
+
if (!context || !directory) throw new Error('Cancellation recovery has no open storage context');
|
|
28
|
+
return { context, directory: path.resolve(directory) };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function assertCurrent(owner) {
|
|
32
|
+
if (retired || owner !== scope) throw new Error('Cancellation recovery scope is retired');
|
|
33
|
+
const current = binding();
|
|
34
|
+
if (current.context !== owner.context || current.directory !== owner.directory) {
|
|
35
|
+
throw new Error('Cancellation recovery storage context changed');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function closeReader(owner) {
|
|
40
|
+
if (!owner?.reader) return;
|
|
41
|
+
await owner.reader.close();
|
|
42
|
+
owner.reader = null; // Retain an unconfirmed resource owner on failure, not just its descriptor.
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function recover(current) {
|
|
46
|
+
await closeReader(scope);
|
|
47
|
+
const owner = scope = { ...current, reader: null, ready: false };
|
|
48
|
+
assertCurrent(owner);
|
|
49
|
+
const reader = owner.reader = createMediaJournalControlReader({
|
|
50
|
+
directory: owner.directory, assertCurrent: () => assertCurrent(owner),
|
|
51
|
+
});
|
|
52
|
+
let records;
|
|
53
|
+
let failed = false;
|
|
54
|
+
let failure;
|
|
55
|
+
try { records = await reader.read(); }
|
|
56
|
+
catch (error) { failed = true; failure = error; }
|
|
57
|
+
try { await closeReader(owner); }
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw failed
|
|
60
|
+
? new AggregateError([failure, error], 'Cancellation recovery and reader cleanup failed', { cause: failure })
|
|
61
|
+
: error;
|
|
62
|
+
}
|
|
63
|
+
if (failed) throw failure;
|
|
64
|
+
// Close every read handle BEFORE the first SQL projection. A partial projection remains
|
|
65
|
+
// idempotently retryable through applyMediaJournalEntry; it is never a completed recovery.
|
|
66
|
+
for (const { entry } of records) {
|
|
67
|
+
assertCurrent(owner);
|
|
68
|
+
const result = await projectEntry(entry, { urgent: true });
|
|
69
|
+
assertCurrent(owner);
|
|
70
|
+
if (typeof result?.cancelled !== 'boolean' || typeof result?.sessionEnded !== 'boolean'
|
|
71
|
+
|| result.cancelled === result.sessionEnded) {
|
|
72
|
+
throw new TypeError('Cancellation projection did not confirm a durable cancellation or ended session');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
assertCurrent(owner);
|
|
76
|
+
owner.ready = true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function prepare() {
|
|
80
|
+
try {
|
|
81
|
+
if (retired) throw new Error('Cancellation recovery is closed');
|
|
82
|
+
const current = binding();
|
|
83
|
+
if (operation) return operation;
|
|
84
|
+
if (scope?.ready && scope.context === current.context && scope.directory === current.directory) {
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
}
|
|
87
|
+
operation = recover(current).catch(error => { throw unavailable(error); })
|
|
88
|
+
.finally(() => { operation = null; });
|
|
89
|
+
return operation;
|
|
90
|
+
} catch (error) {
|
|
91
|
+
return Promise.reject(unavailable(error));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function close() {
|
|
96
|
+
retired = true;
|
|
97
|
+
if (closing) return closing;
|
|
98
|
+
closing = (async () => {
|
|
99
|
+
// Already delivered operational errors are not shutdown failures. Unconfirmed handles
|
|
100
|
+
// remain owned and closeReader must still report them. No race against a timeout here.
|
|
101
|
+
if (operation) await operation.catch(() => { /* expected: admitted caller receives the failure */ });
|
|
102
|
+
await closeReader(scope);
|
|
103
|
+
scope = null;
|
|
104
|
+
})().finally(() => { closing = null; });
|
|
105
|
+
return closing;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return { prepare, close };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
module.exports = { createLegacyDraftCancellationRecovery };
|