create-walle 0.10.0 → 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 +88 -41
- 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 +7 -5
- package/package.json +10 -4
- 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/capture-codex-rollout-records.js +417 -0
- package/template/coding-task-manager/bin/census-codex-lead-history.js +325 -0
- 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/seam-replay-codex.js +301 -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 +25 -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-history-terminal-renderer.js +33 -33
- 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-local-links.js +267 -0
- package/template/coding-task-manager/lib/codex-markdown-lists.js +160 -0
- package/template/coding-task-manager/lib/codex-native-history-prefix.js +4 -0
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/codex-source-handoff.js +186 -0
- 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-owner-worker-client.js +22 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -3
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +41 -14
- 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 +60 -23
- package/template/coding-task-manager/lib/history-transition-read-op.js +179 -23
- 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/kernel/diag-log.js +12 -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-observer.js +17 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +11 -2
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +42 -4
- 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 +18 -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 +56 -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-execution-recipe-metadata.js +16 -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/collaboration-codec.js +94 -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/responses-face.js +24 -2
- 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 +62 -14
- 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-admission-trace.js +69 -0
- 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/raw-history-block.js +3 -1
- package/template/coding-task-manager/lib/read-pool-client.js +36 -24
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/read-pool-telemetry.js +14 -5
- 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 +18 -5
- 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 +43 -11
- package/template/coding-task-manager/lib/root-prompt-flow.js +175 -38
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/server-memory-sampler-runtime.js +10 -0
- package/template/coding-task-manager/lib/server-memory-sampler.js +41 -2
- 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 +38 -39
- 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 +20 -50
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +68 -3
- package/template/coding-task-manager/lib/session-resource-sampler.js +67 -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-status.js +2 -2
- 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 +136 -2
- package/template/coding-task-manager/lib/typing-worker-stages.js +208 -1
- package/template/coding-task-manager/lib/usage-ledger/claude-parse.js +53 -2
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +13 -4
- package/template/coding-task-manager/lib/usage-ledger/read.js +14 -0
- package/template/coding-task-manager/lib/usage-ledger/schema.js +49 -1
- package/template/coding-task-manager/lib/usage-ledger/store.js +337 -6
- package/template/coding-task-manager/lib/usage-ledger/task-read.js +123 -5
- 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/input.js +1 -0
- 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/protocol/message-table.json +0 -10
- package/template/coding-task-manager/protocol/messages.js +0 -10
- package/template/coding-task-manager/protocol/ws-schema.json +0 -20
- package/template/coding-task-manager/protocol/ws-schema.md +0 -2
- 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 -2
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +297 -240
- 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/client-health-core.js +81 -0
- package/template/coding-task-manager/public/js/client-health-main.js +61 -0
- 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 -4
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/protocol.js +0 -10
- 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 +18 -3
- 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/session-usage-view.js +1 -0
- 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 -3
- 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 +964 -425
- 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/host-capabilities.js +2 -2
- 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/fly.toml +1 -1
- 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 +12 -5
- 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
- package/template/coding-task-manager/lib/giant-freeze-park.js +0 -31
|
@@ -76,6 +76,7 @@ const { createErrorSink } = require('./error-sink');
|
|
|
76
76
|
const { createPendingClientRegistry } = require('./state-sync/pending-client-registry');
|
|
77
77
|
const { createApprovalTrailingRecheck } = require('./approval-trailing-recheck');
|
|
78
78
|
const { composeTerminalBootstrapResult, truncateBootstrapAnsi } = require('./terminal-bootstrap');
|
|
79
|
+
const { createInFlightOps } = require('./headless-inflight-ops'); // WP-0 (D-6): per-session in-flight op table
|
|
79
80
|
|
|
80
81
|
let postMessage = () => {};
|
|
81
82
|
const errorSink = createErrorSink({ name: 'worker:headless-terminal' });
|
|
@@ -87,6 +88,8 @@ const errorSink = createErrorSink({ name: 'worker:headless-terminal' });
|
|
|
87
88
|
// is a complete no-op, so behaviour is unchanged everywhere else.
|
|
88
89
|
let _opStampBuffer = null;
|
|
89
90
|
let _opTable = null;
|
|
91
|
+
// WP-0 (D-6): the per-session truth the single SAB slot pair above can never hold.
|
|
92
|
+
const _inFlightOps = createInFlightOps();
|
|
90
93
|
|
|
91
94
|
function setOpStampBuffer(shared, opTable) {
|
|
92
95
|
_opStampBuffer = shared ? new BigInt64Array(shared) : null;
|
|
@@ -106,18 +109,31 @@ function _sid32(sessionId) {
|
|
|
106
109
|
return Number.isFinite(n) ? BigInt(n >>> 0) : 0n;
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
// Returns the packed (sid32<<32)|opCode this call wrote (or null with no buffer)
|
|
113
|
+
// so the op's own finisher can compare-and-clear exactly its own stamp.
|
|
114
|
+
// asIntN(64, ...) is NOT cosmetic: a BigInt64Array wraps on store, so the value
|
|
115
|
+
// read back (and hence what compareExchange must be given) is the signed 64-bit
|
|
116
|
+
// one -- the unwrapped positive BigInt would never match and the clear would
|
|
117
|
+
// silently become a no-op.
|
|
109
118
|
function _stampOp(sessionId, opType) {
|
|
110
|
-
if (!_opStampBuffer) return;
|
|
119
|
+
if (!_opStampBuffer) return null;
|
|
111
120
|
const sid32 = _sid32(sessionId);
|
|
112
121
|
const opCode = BigInt(_opCode(opType));
|
|
122
|
+
const packed = BigInt.asIntN(64, (sid32 << 32n) | opCode);
|
|
113
123
|
Atomics.store(_opStampBuffer, 2, BigInt(Date.now()));
|
|
114
|
-
Atomics.store(_opStampBuffer, 3,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
124
|
+
Atomics.store(_opStampBuffer, 3, packed);
|
|
125
|
+
return packed;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// WP-0 (D-6, S-12): compare-and-clear. Slots [2]/[3] are ONE shared pair per
|
|
129
|
+
// process, so an unconditional zero would erase a DIFFERENT session's op that
|
|
130
|
+
// stamped after this one. Clear [2] only when slot [3] still holds this op's
|
|
131
|
+
// own packed value.
|
|
132
|
+
function _clearOp(packed) {
|
|
133
|
+
if (!_opStampBuffer || packed == null) return;
|
|
134
|
+
if (Atomics.compareExchange(_opStampBuffer, 3, packed, 0n) === packed) {
|
|
135
|
+
Atomics.store(_opStampBuffer, 2, 0n);
|
|
136
|
+
}
|
|
121
137
|
}
|
|
122
138
|
|
|
123
139
|
function postTransport(message) {
|
|
@@ -730,20 +746,21 @@ function _stateSyncOnMirrorWrite(sessionId, bytes, opts) {
|
|
|
730
746
|
_stateSyncEmitter.setFlooding(sessionId, _stateSyncIsFlooding(flood, _stateSyncClock.now(), {}));
|
|
731
747
|
const clearScrollback = _stateSyncPendingClearScrollback.delete(sessionId);
|
|
732
748
|
const currentEntry = terminals.get(sessionId);
|
|
733
|
-
|
|
749
|
+
const offeredEchoSeq = Number(currentEntry?.state?.echoedThroughInputSeq || 0);
|
|
750
|
+
_noteWorkerTypingStagePending(sessionId, currentEntry, 'emit-offered', { offeredEchoSeq });
|
|
734
751
|
const sent = _stateSyncEmitter.onMirrorUpdated(sessionId, {
|
|
735
752
|
bypassRate: true,
|
|
736
753
|
clearScrollback,
|
|
737
|
-
echoedThroughSeq:
|
|
754
|
+
echoedThroughSeq: offeredEchoSeq,
|
|
738
755
|
synchronizedOutputOpen: _stateSyncSynchronizedOutputOpen(sessionId),
|
|
739
756
|
});
|
|
740
757
|
if (sent && currentEntry?.state) {
|
|
741
758
|
currentEntry.state.lastStateSyncEmittedInputSeq = Number(
|
|
742
759
|
currentEntry.state.echoedThroughInputSeq || 0
|
|
743
760
|
);
|
|
744
|
-
// A frame actually shipped for these interactions -- clear the
|
|
745
|
-
// refusal (a different write's gate) never double-attributes
|
|
746
|
-
currentEntry.state.pendingTypingInteractionIds =
|
|
761
|
+
// A frame actually shipped for these interactions -- clear only the ids whose echo it
|
|
762
|
+
// covers (WP-4 R-7); a LATER refusal (a different write's gate) never double-attributes.
|
|
763
|
+
currentEntry.state.pendingTypingInteractionIds = _typingWorkerStages.noteFramePostedForEchoed(postTransport, sessionId, currentEntry, offeredEchoSeq);
|
|
747
764
|
}
|
|
748
765
|
}
|
|
749
766
|
};
|
|
@@ -1265,12 +1282,14 @@ const opQueues = new Map(); // sessionId -> Promise chain for feed/serialize/des
|
|
|
1265
1282
|
|
|
1266
1283
|
function enqueueSessionOp(sessionId, fn, opType) {
|
|
1267
1284
|
const prev = opQueues.get(sessionId) || Promise.resolve();
|
|
1285
|
+
_inFlightOps.noteQueued(sessionId, 1); // WP-0: depth behind the running op
|
|
1268
1286
|
let next;
|
|
1269
1287
|
next = prev
|
|
1270
1288
|
.catch(() => {})
|
|
1271
1289
|
.then(() => {
|
|
1272
|
-
|
|
1273
|
-
|
|
1290
|
+
const seq = _inFlightOps.begin(sessionId, opType);
|
|
1291
|
+
const packed = _stampOp(sessionId, opType);
|
|
1292
|
+
return Promise.resolve().then(fn).finally(() => { _clearOp(packed); _inFlightOps.end(sessionId, seq); });
|
|
1274
1293
|
})
|
|
1275
1294
|
.catch((err) => {
|
|
1276
1295
|
postTransport({
|
|
@@ -1320,6 +1339,18 @@ async function handleMessage(msg) {
|
|
|
1320
1339
|
if (feedEntry.state.typingIdsAwaitingFeed && feedEntry.state.pendingTypingInteractionIds.length) {
|
|
1321
1340
|
feedEntry.state.typingIdsAwaitingFeed = false;
|
|
1322
1341
|
_noteWorkerTypingStage(msg.sessionId, feedEntry.state.pendingTypingInteractionIds, 'worker-received');
|
|
1342
|
+
// WP-4 (clock-free-tests-followups-r4-2026-10-24.html §5 R-9, §6.5): the SAME ids, in
|
|
1343
|
+
// the same call pattern, gain a second stamp at the instant the host's mirror-feed
|
|
1344
|
+
// coalescer took the batch in (`hostReceivedAt`, carried from the deliver callback) --
|
|
1345
|
+
// 'worker-received' above is the parse leg, this one is the host's receipt leg, and the
|
|
1346
|
+
// delta between them is what R-9 exists to measure. Only a finite host time stamps
|
|
1347
|
+
// anything: a sender that predates the field leaves the stage absent, never at 0.
|
|
1348
|
+
if (Number.isFinite(msg.hostReceivedAt)) {
|
|
1349
|
+
_noteWorkerTypingStage(
|
|
1350
|
+
msg.sessionId, feedEntry.state.pendingTypingInteractionIds, 'host-pty-data',
|
|
1351
|
+
{ at: msg.hostReceivedAt },
|
|
1352
|
+
);
|
|
1353
|
+
}
|
|
1323
1354
|
}
|
|
1324
1355
|
}
|
|
1325
1356
|
const byteCount = Buffer.byteLength(String(msg.data || ''));
|
|
@@ -1345,6 +1376,8 @@ async function handleMessage(msg) {
|
|
|
1345
1376
|
// WP-0b (§6): the xterm write callback for THIS feed -- exactly where the brief says
|
|
1346
1377
|
// `mirror-written` belongs.
|
|
1347
1378
|
_noteWorkerTypingStagePending(msg.sessionId, entry, 'mirror-written');
|
|
1379
|
+
// WP-3 (D-C2): per-key shadow echo matchers -- see lib/typing-worker-stages.js.
|
|
1380
|
+
_typingWorkerStages.matchEchoPredictions(postTransport, msg.sessionId, entry, msg.data);
|
|
1348
1381
|
entry.state.liveOutputSeq += 1;
|
|
1349
1382
|
entry.state.liveBytesSinceSeed += byteCount;
|
|
1350
1383
|
if (entry.state.pendingInputSeq > entry.state.echoedThroughInputSeq) {
|
|
@@ -1470,12 +1503,9 @@ async function handleMessage(msg) {
|
|
|
1470
1503
|
// every keystroke (HeadlessTerminalRouter.postMessage, lib/session-host-manager.js
|
|
1471
1504
|
// :1815-1834, forwards by sessionId to the pool host when one owns the session, else the
|
|
1472
1505
|
// legacy worker thread) -- carry the pending typing-interaction ids here, not on 'feed'.
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
);
|
|
1477
|
-
entry.state.typingIdsAwaitingFeed = true;
|
|
1478
|
-
}
|
|
1506
|
+
// WP-3 (D-C2): the pending-id merge above moved into armEchoPrediction, which also arms
|
|
1507
|
+
// this keystroke's shadow echo prediction when the message carries one.
|
|
1508
|
+
_typingWorkerStages.armEchoPrediction(entry, msg);
|
|
1479
1509
|
break;
|
|
1480
1510
|
}
|
|
1481
1511
|
|
|
@@ -2368,8 +2398,12 @@ async function handleMessage(msg) {
|
|
|
2368
2398
|
function dispatchHeadlessMessage(msg) {
|
|
2369
2399
|
const sessionId = msg && msg.sessionId;
|
|
2370
2400
|
if (sessionId && msg.type === 'getViewportText') {
|
|
2371
|
-
|
|
2372
|
-
|
|
2401
|
+
// WP-0: SAB stamp only. This op is outside the per-session chain and cannot wedge it,
|
|
2402
|
+
// and the in-flight table holds ONE row per session -- registering here would overwrite
|
|
2403
|
+
// (and its end() would then delete) a wedged chain op for the same session, hiding the
|
|
2404
|
+
// very wedge WP-0 exists to name.
|
|
2405
|
+
const packed = _stampOp(sessionId, msg.type);
|
|
2406
|
+
return handleMessage(msg).finally(() => _clearOp(packed));
|
|
2373
2407
|
}
|
|
2374
2408
|
if (!sessionId) {
|
|
2375
2409
|
return handleMessage(msg).catch((err) => {
|
|
@@ -2392,6 +2426,9 @@ function bindHeadlessTerminalService(options = {}) {
|
|
|
2392
2426
|
return {
|
|
2393
2427
|
handleMessage: dispatchHeadlessMessage,
|
|
2394
2428
|
hasTerminal,
|
|
2429
|
+
// WP-0 (D-6): report-only views of the per-session in-flight op table.
|
|
2430
|
+
getInFlightOps: () => _inFlightOps.list(),
|
|
2431
|
+
oldestInFlightOps: (n) => _inFlightOps.oldest(n),
|
|
2395
2432
|
getStats() {
|
|
2396
2433
|
const pendingStats = pendingStateSyncClients.snapshot();
|
|
2397
2434
|
const warningStats = _stalledSessionWarnings.snapshot();
|
|
@@ -7,17 +7,23 @@ const transcriptSource = require('./transcript-source');
|
|
|
7
7
|
const sessionHistory = require('./session-history');
|
|
8
8
|
const codexPaths = require('./codex-paths');
|
|
9
9
|
const { readNativeHistoryPrefix, findCanonicalRolloutsByFilenameId } = require('./codex-native-history-prefix');
|
|
10
|
+
// S-4: one definition of the portable history kinds, in the planner. This module only reads it.
|
|
11
|
+
const { PORTABLE_HISTORY_KINDS } = require('./harness-history-transition');
|
|
10
12
|
|
|
11
13
|
const DEFAULT_SCAN_BYTES = 64 * 1024 * 1024;
|
|
12
14
|
const MAX_SCAN_BYTES = 64 * 1024 * 1024;
|
|
13
15
|
const MAX_RECORDS = 200_000;
|
|
14
16
|
const THREAD_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17
|
+
// D-5/D-8 (docs/codex-lead-routed-switch-history-handoff-2026-10-21.html §6.1): the plaintext
|
|
18
|
+
// handoff a source GPT model writes before the switch, exactly as lib/native-history-control.js
|
|
19
|
+
// injects it. Only the marker sha is parsed here; the summary text itself never leaves the digest.
|
|
20
|
+
const HANDOFF_MARKER = /^<ctm_handoff compaction_sha256="([0-9a-f]{64})"/;
|
|
21
|
+
const COMPACTION_ITEM_KEYS = Object.freeze(['replacement_history', 'replacementHistory', 'summary']);
|
|
15
22
|
const TOOL_PAIRS = Object.freeze({
|
|
16
23
|
function_call: 'function_call_output', custom_tool_call: 'custom_tool_call_output',
|
|
17
24
|
computer_call: 'computer_call_output', local_shell_call: 'local_shell_call_output',
|
|
18
25
|
});
|
|
19
26
|
const TOOL_OUTPUTS = new Set(Object.values(TOOL_PAIRS));
|
|
20
|
-
const PORTABLE_HISTORY_KINDS = new Set(['text', 'tool-pair', 'native-world-state', 'native-lifecycle']);
|
|
21
27
|
const SAFE_EVENT_TYPES = new Set([
|
|
22
28
|
'task_started', 'task_complete', 'turn_aborted', 'token_count', 'user_message',
|
|
23
29
|
'agent_message_delta', 'agent_reasoning_delta', 'agent_reasoning_section_break', 'item_completed',
|
|
@@ -70,7 +76,12 @@ function summarizeCodexHistoryRecords(records, { threadId, generation, lineageTh
|
|
|
70
76
|
active.kinds.add('text');
|
|
71
77
|
collectHashes(record, active.hashes);
|
|
72
78
|
if (containsFlag(payload, /^opaque$/i)) active.opaque = true;
|
|
73
|
-
|
|
79
|
+
// S-9/D-5: a `compaction` item inside the replacement history is the ONLY ciphertext that a
|
|
80
|
+
// source-written plaintext handoff can cover, so it is tracked by digest instead of being
|
|
81
|
+
// collapsed into the blanket `encrypted` flag. The record-level flag is evaluated on a copy
|
|
82
|
+
// with those items removed, so every OTHER ciphertext still marks the window non-portable.
|
|
83
|
+
const withoutSealed = withoutSealedCompactionItems(payload);
|
|
84
|
+
if (containsFlag(withoutSealed, /^(encrypted|ciphertext|encrypted_content)$/i)) active.encrypted = true;
|
|
74
85
|
const replacement = payload.replacement_history ?? payload.replacementHistory ?? payload.summary;
|
|
75
86
|
if (replacement !== undefined) {
|
|
76
87
|
const status = classifyReplacement(replacement, active);
|
|
@@ -189,12 +200,25 @@ function summarizeCodexHistoryRecords(records, { threadId, generation, lineageTh
|
|
|
189
200
|
}
|
|
190
201
|
if (pairKind === 'output') active.estimateValid = false;
|
|
191
202
|
} else if (itemType === 'message' || itemType === 'agent_message' || itemType === 'reasoning') {
|
|
192
|
-
|
|
193
|
-
|
|
203
|
+
// D-2: a `message` whose only non-text content parts are input_image parts is native media,
|
|
204
|
+
// not a refusal -- Codex strips an image the target cannot accept
|
|
205
|
+
// (core/src/context_manager/normalize.rs:346 @ rust-v0.163.0) and CTM declares
|
|
206
|
+
// input_modalities:['text'] for routed models (lib/harness-model-profile.js:85). Any other
|
|
207
|
+
// modality (input_audio, file, ...) and an agent_message carrying media still refuse.
|
|
208
|
+
if (itemType !== 'reasoning' && !portableTextOnly(payload)) {
|
|
209
|
+
if (itemType !== 'message' || !imageOnlyNonText(payload)) return unsupported('unsupported_native_history_item_content');
|
|
210
|
+
active.kinds.add('native-media');
|
|
211
|
+
} else {
|
|
212
|
+
active.kinds.add('text');
|
|
213
|
+
}
|
|
194
214
|
if (itemType === 'agent_message') active.estimateValid = false;
|
|
195
215
|
if (payload.role === 'user' || payload.role === 'developer' || payload.role === 'system') active.estimateValid = false;
|
|
196
216
|
}
|
|
197
217
|
if (itemType === 'reasoning' && ownsTopLevelFlag(payload, 'encrypted_content')) active.droppableReasoningCount += 1;
|
|
218
|
+
// D-8: the covering proof for a sealed compaction is a developer message the source model wrote
|
|
219
|
+
// after it. Only its digests are recorded; the summary text stays out of this object.
|
|
220
|
+
const marker = handoffMarkerOf(payload);
|
|
221
|
+
if (marker) active.handoffMarkers.push(marker);
|
|
198
222
|
// D-1: a reasoning item's own ciphertext is droppable (the issuer omits incompatible reasoning
|
|
199
223
|
// itself); nested ciphertext in its content/summary parts still marks the window non-portable.
|
|
200
224
|
const ciphertextScope = itemType === 'reasoning' ? withoutTopLevelFlag(payload, 'encrypted_content') : payload;
|
|
@@ -261,6 +285,11 @@ function summarizeCodexHistoryRecords(records, { threadId, generation, lineageTh
|
|
|
261
285
|
const nativeCurrentPolicyStatus = !active.currentThreadSettings ? 'not-present'
|
|
262
286
|
: !completedContext?.nativePolicyFingerprint || !active.currentThreadSettings.policyFingerprint ? 'unknown'
|
|
263
287
|
: completedContext.nativePolicyFingerprint === active.currentThreadSettings.policyFingerprint ? 'match' : 'mismatch';
|
|
288
|
+
// D-8: coverage is proven from the readback itself -- every sealed compaction digest must have a
|
|
289
|
+
// marker at or after it, and the marker covering the first one identifies the exact text.
|
|
290
|
+
const encryptedCompactions = [...new Set(active.encryptedCompactions)];
|
|
291
|
+
const coveredShas = new Set(active.handoffMarkers.map((marker) => marker.sha));
|
|
292
|
+
const coveringMarker = active.handoffMarkers.find((marker) => marker.sha === encryptedCompactions[0]) || null;
|
|
264
293
|
return {
|
|
265
294
|
complete: true, sourceThreadId: threadId, generation,
|
|
266
295
|
compacted: sawCompaction,
|
|
@@ -270,6 +299,9 @@ function summarizeCodexHistoryRecords(records, { threadId, generation, lineageTh
|
|
|
270
299
|
historyKinds: [...active.kinds].sort().length ? [...active.kinds].sort() : [sawCompaction ? 'text' : 'unknown'],
|
|
271
300
|
toolPairsValid: active.calls.size === active.outputs.size && [...active.calls].every((id) => active.outputs.has(id)),
|
|
272
301
|
opaque: active.opaque, encrypted: active.encrypted,
|
|
302
|
+
encryptedCompactions,
|
|
303
|
+
handoffCovers: encryptedCompactions.every((sha) => coveredShas.has(sha)),
|
|
304
|
+
handoffTextSha256: coveringMarker ? coveringMarker.textSha256 : null,
|
|
273
305
|
droppableReasoningCount: active.droppableReasoningCount, compactionHashes: hashSet,
|
|
274
306
|
previousSettings, nativePolicyControl: completedContext?.nativePolicyControl || null,
|
|
275
307
|
nativeCurrentPolicyStatus, currentThreadSettingsModel: active.currentThreadSettings?.model || null,
|
|
@@ -278,6 +310,59 @@ function summarizeCodexHistoryRecords(records, { threadId, generation, lineageTh
|
|
|
278
310
|
};
|
|
279
311
|
}
|
|
280
312
|
|
|
313
|
+
// D-5: the digest of a `compaction` replacement item's ciphertext, or '' when the item is not one.
|
|
314
|
+
// `type` is read the same way classifyReplacement reads it, so the two can never disagree.
|
|
315
|
+
function sealedCompactionSha(item) {
|
|
316
|
+
if (!isRecord(item) || nonempty(item.type || item.kind) !== 'compaction') return '';
|
|
317
|
+
const content = item.encrypted_content;
|
|
318
|
+
return typeof content === 'string' && content.length > 0 ? digest(content) : '';
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// A copy of a `compacted` payload without the ciphertext this scanner already accounts for, so the
|
|
322
|
+
// record-level probe sees every OTHER encrypted value:
|
|
323
|
+
// - a sealed `compaction` replacement item, which a source-written handoff can cover (D-5);
|
|
324
|
+
// - a `reasoning` item's own top-level encrypted_content, droppable exactly as for a top-level
|
|
325
|
+
// reasoning response_item (D-1). Codex >= 0.163 checkpoints the auto-reviewer's transcript as
|
|
326
|
+
// `guardian_history` (core/src/session/guardian_checkpoint.rs @ rust-v0.163.0), and its
|
|
327
|
+
// reasoning items carry their own ciphertext; nested ciphertext inside them still counts.
|
|
328
|
+
const CHECKPOINT_ITEM_KEYS = Object.freeze([...COMPACTION_ITEM_KEYS, 'guardian_history']);
|
|
329
|
+
|
|
330
|
+
function withoutSealedCompactionItems(payload) {
|
|
331
|
+
if (typeof payload !== 'object' || payload === null) return payload;
|
|
332
|
+
let copy = null;
|
|
333
|
+
for (const key of CHECKPOINT_ITEM_KEYS) {
|
|
334
|
+
const value = payload[key];
|
|
335
|
+
if (!Array.isArray(value)) continue;
|
|
336
|
+
let changed = false;
|
|
337
|
+
const kept = [];
|
|
338
|
+
for (const item of value) {
|
|
339
|
+
if (sealedCompactionSha(item)) { changed = true; continue; }
|
|
340
|
+
if (isRecord(item) && item.type === 'reasoning' && ownsTopLevelFlag(item, 'encrypted_content')) {
|
|
341
|
+
changed = true;
|
|
342
|
+
kept.push(withoutTopLevelFlag(item, 'encrypted_content'));
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
kept.push(item);
|
|
346
|
+
}
|
|
347
|
+
if (!changed) continue;
|
|
348
|
+
if (!copy) copy = { ...payload };
|
|
349
|
+
copy[key] = kept;
|
|
350
|
+
}
|
|
351
|
+
return copy || payload;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// The covering proof: a developer message whose first content part is input_text starting at the
|
|
355
|
+
// handoff marker. Returns digests only -- never the summary text.
|
|
356
|
+
function handoffMarkerOf(payload) {
|
|
357
|
+
if (!isRecord(payload) || payload.type !== 'message' || payload.role !== 'developer') return null;
|
|
358
|
+
const content = payload.content;
|
|
359
|
+
if (!Array.isArray(content) || content.length === 0) return null;
|
|
360
|
+
const first = content[0];
|
|
361
|
+
if (!isRecord(first) || first.type !== 'input_text' || typeof first.text !== 'string') return null;
|
|
362
|
+
const match = HANDOFF_MARKER.exec(first.text);
|
|
363
|
+
return match ? { sha: match[1], textSha256: digest(first.text) } : null;
|
|
364
|
+
}
|
|
365
|
+
|
|
281
366
|
function readCodexHistoryTransitionSnapshot({ db, ctmSessionId, sourceThreadId, processGeneration, signal, assertLive,
|
|
282
367
|
maxBytes = DEFAULT_SCAN_BYTES, storageRootReceipt } = {}) {
|
|
283
368
|
if (cancelled(signal)) return unsupported('transition_cancelled');
|
|
@@ -311,7 +396,7 @@ function readCodexHistoryTransitionSnapshot({ db, ctmSessionId, sourceThreadId,
|
|
|
311
396
|
|
|
312
397
|
function verifyCodexTransitionFork({ db, transitionId, expectedRevision, sessionId, sourceThreadId,
|
|
313
398
|
sourceGeneration, targetGeneration, sourceCheckpointId, sourceContentDigest, targetThreadId,
|
|
314
|
-
signal, assertLive, storageRootReceipt } = {}) {
|
|
399
|
+
expectedHandoff, signal, assertLive, storageRootReceipt } = {}) {
|
|
315
400
|
if (cancelled(signal)) return unsupported('transition_cancelled');
|
|
316
401
|
assertLive?.();
|
|
317
402
|
if (!db || !nonempty(transitionId) || !nonempty(sessionId) || !THREAD_ID.test(String(sourceThreadId || ''))
|
|
@@ -355,6 +440,18 @@ function verifyCodexTransitionFork({ db, transitionId, expectedRevision, session
|
|
|
355
440
|
if (!target.complete || target.sourceThreadId !== targetThreadId || target.checkpoint?.id !== sourceCheckpointId) {
|
|
356
441
|
return unsupported('fork_target_checkpoint_mismatch');
|
|
357
442
|
}
|
|
443
|
+
// S-10/D-8: a sealed compaction in the FORKED history is accepted only when the readback itself
|
|
444
|
+
// proves the exact plaintext handoff that covers it. Trusting the inject call would accept a lost
|
|
445
|
+
// or partial inject, so the coverage digests are compared against what the controller wrote.
|
|
446
|
+
const sealedTarget = Array.isArray(target.encryptedCompactions) ? target.encryptedCompactions : [];
|
|
447
|
+
if (sealedTarget.length && (target.handoffCovers !== true
|
|
448
|
+
|| !isRecord(expectedHandoff)
|
|
449
|
+
|| !/^[a-f0-9]{64}$/.test(String(expectedHandoff.compactionSha256 || ''))
|
|
450
|
+
|| !/^[a-f0-9]{64}$/.test(String(expectedHandoff.textSha256 || ''))
|
|
451
|
+
|| sealedTarget[0] !== expectedHandoff.compactionSha256
|
|
452
|
+
|| target.handoffTextSha256 !== expectedHandoff.textSha256)) {
|
|
453
|
+
return unsupported('fork_target_handoff_missing');
|
|
454
|
+
}
|
|
358
455
|
if (target.opaque || target.encrypted || target.toolPairsValid !== true
|
|
359
456
|
|| !Array.isArray(target.historyKinds) || target.historyKinds.length === 0
|
|
360
457
|
|| target.historyKinds.some((kind) => !PORTABLE_HISTORY_KINDS.has(kind))) return unsupported('fork_target_history_unsafe');
|
|
@@ -416,12 +513,20 @@ function classifyReplacement(value, active) {
|
|
|
416
513
|
else if (type === 'compaction') {
|
|
417
514
|
// Codex 0.162.1 keeps the pre-window digest in a `compaction` item. It is a known shape,
|
|
418
515
|
// but its ciphertext is the only record of earlier context, so it is never droppable.
|
|
516
|
+
// D-5: the SOURCE model can write a plaintext handoff covering exactly this ciphertext, so
|
|
517
|
+
// the item is tracked by digest; the coverage decision belongs to the planner.
|
|
419
518
|
active.kinds.add('text');
|
|
420
|
-
|
|
519
|
+
const sealed = sealedCompactionSha(item);
|
|
520
|
+
if (sealed) {
|
|
521
|
+
if (!active.encryptedCompactions.includes(sealed)) active.encryptedCompactions.push(sealed);
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
421
524
|
}
|
|
422
525
|
else if (type === 'message') {
|
|
423
|
-
|
|
424
|
-
active.kinds.add('text');
|
|
526
|
+
// D-2 applies inside a compaction replacement too: an image-only message is native media.
|
|
527
|
+
if (portableTextOnly(item)) active.kinds.add('text');
|
|
528
|
+
else if (imageOnlyNonText(item)) active.kinds.add('native-media');
|
|
529
|
+
else return 'compaction_replacement_unknown';
|
|
425
530
|
}
|
|
426
531
|
else if (type === 'function_call' || type === 'custom_tool_call' || type === 'computer_call' || type === 'local_shell_call') {
|
|
427
532
|
const id = nonempty(item.call_id || item.id);
|
|
@@ -544,17 +649,30 @@ function inspectCompletedItemEvent(payload, lineage) {
|
|
|
544
649
|
return { ok: inspection.ok, opaque: inspection.opaque, encrypted: inspection.encrypted };
|
|
545
650
|
}
|
|
546
651
|
|
|
652
|
+
// D-1: exactly the field set of Codex ThreadSettingsSnapshot
|
|
653
|
+
// (codex-rs/protocol/src/protocol.rs:2335-2362 @ rust-v0.163.0). The fields below are the ones the
|
|
654
|
+
// struct requires; the rest carry a serde default (runtime_workspace_roots, disabled_plugin_ids,
|
|
655
|
+
// active_permission_profile) or are Option. The payload's own thread_id is Option<ThreadId>
|
|
656
|
+
// (protocol.rs:2329), so it is optional but must be in the lineage when present.
|
|
657
|
+
const THREAD_SETTINGS_REQUIRED = Object.freeze(['model', 'model_provider_id', 'approval_policy',
|
|
658
|
+
'approvals_reviewer', 'permission_profile', 'cwd', 'collaboration_mode']);
|
|
659
|
+
const THREAD_SETTINGS_OPTIONAL = Object.freeze(['service_tier', 'active_permission_profile',
|
|
660
|
+
'runtime_workspace_roots', 'reasoning_effort', 'reasoning_summary', 'personality', 'disabled_plugin_ids']);
|
|
661
|
+
const THREAD_SETTINGS_KEYS = new Set([...THREAD_SETTINGS_REQUIRED, ...THREAD_SETTINGS_OPTIONAL]);
|
|
662
|
+
const THREAD_SETTINGS_PAYLOAD_KEYS = new Set(['type', 'thread_id', 'thread_settings']);
|
|
663
|
+
|
|
547
664
|
function inspectThreadSettingsApplied(payload, lineage) {
|
|
548
665
|
const settings = payload.thread_settings;
|
|
549
|
-
const keys = new Set(['model', 'model_provider_id', 'approval_policy', 'approvals_reviewer',
|
|
550
|
-
'permission_profile', 'cwd', 'runtime_workspace_roots', 'collaboration_mode', 'disabled_plugin_ids']);
|
|
551
666
|
const invalid = () => ({ ok: false, opaque: false, encrypted: false });
|
|
552
|
-
if (!hasOnlyKeys(payload,
|
|
667
|
+
if (!hasOnlyKeys(payload, THREAD_SETTINGS_PAYLOAD_KEYS)
|
|
553
668
|
|| payload.type !== 'thread_settings_applied'
|
|
554
|
-
||
|
|
555
|
-
|
|
669
|
+
|| (payload.thread_id !== undefined && payload.thread_id !== null
|
|
670
|
+
&& !lineage.has(String(payload.thread_id).toLowerCase()))
|
|
671
|
+
|| !isRecord(settings) || Object.keys(settings).some((key) => !THREAD_SETTINGS_KEYS.has(key))) return invalid();
|
|
556
672
|
const boundedString = (value, max, pattern = null) => typeof value === 'string' && value.length > 0
|
|
557
673
|
&& value.length <= max && (!pattern || pattern.test(value));
|
|
674
|
+
const optionalBoundedString = (value, max, pattern) => value === undefined || value === null
|
|
675
|
+
|| boundedString(value, max, pattern);
|
|
558
676
|
const collaboration = settings.collaboration_mode;
|
|
559
677
|
const collaborationSettings = collaboration?.settings;
|
|
560
678
|
const permissionKeys = settings.permission_profile && isRecord(settings.permission_profile)
|
|
@@ -566,14 +684,25 @@ function inspectThreadSettingsApplied(payload, lineage) {
|
|
|
566
684
|
: profileType === 'external'
|
|
567
685
|
? permissionKeys.length === 2 && permissionKeys.includes('network') && ['enabled', 'restricted'].includes(settings.permission_profile.network)
|
|
568
686
|
: profileType === 'disabled' && permissionKeys.length === 1;
|
|
687
|
+
// A serde-defaulted Vec is absent in real records with an empty list; the two are the same value.
|
|
688
|
+
const disabledPluginIds = settings.disabled_plugin_ids ?? [];
|
|
689
|
+
const runtimeWorkspaceRoots = settings.runtime_workspace_roots;
|
|
690
|
+
const activePermissionProfile = settings.active_permission_profile;
|
|
569
691
|
if (!boundedString(settings.model, 256, /^[A-Za-z0-9@][A-Za-z0-9@._:/+-]*$/)
|
|
570
692
|
|| !boundedString(settings.model_provider_id, 128, /^[A-Za-z0-9][A-Za-z0-9._-]*$/)
|
|
571
693
|
|| !['never', 'on-request', 'on-failure', 'untrusted'].includes(settings.approval_policy)
|
|
572
694
|
|| !['user', 'auto_review', 'guardian_subagent'].includes(settings.approvals_reviewer)
|
|
573
695
|
|| !validPermissionProfile
|
|
574
696
|
|| !boundedString(settings.cwd, 4096) || !path.isAbsolute(settings.cwd)
|
|
575
|
-
|| !
|
|
576
|
-
|| settings.
|
|
697
|
+
|| !optionalBoundedString(settings.service_tier, 64, /^[a-z0-9_-]{1,64}$/)
|
|
698
|
+
|| !optionalBoundedString(settings.reasoning_effort, 32, /^[a-z]{1,32}$/)
|
|
699
|
+
|| !optionalBoundedString(settings.reasoning_summary, 32, /^[a-z]{1,32}$/)
|
|
700
|
+
|| !optionalBoundedString(settings.personality, 64, /^[a-z0-9_-]{1,64}$/)
|
|
701
|
+
|| (activePermissionProfile !== undefined && activePermissionProfile !== null
|
|
702
|
+
&& !isRecord(activePermissionProfile))
|
|
703
|
+
|| (runtimeWorkspaceRoots !== undefined && runtimeWorkspaceRoots !== null
|
|
704
|
+
&& (!Array.isArray(runtimeWorkspaceRoots) || runtimeWorkspaceRoots.length > 256
|
|
705
|
+
|| runtimeWorkspaceRoots.some((value) => !boundedString(value, 4096) || !path.isAbsolute(value))))
|
|
577
706
|
|| !isRecord(collaboration) || Object.keys(collaboration).some((key) => !['mode', 'settings'].includes(key))
|
|
578
707
|
|| !['default', 'plan'].includes(collaboration.mode)
|
|
579
708
|
|| !isRecord(collaborationSettings)
|
|
@@ -583,25 +712,30 @@ function inspectThreadSettingsApplied(payload, lineage) {
|
|
|
583
712
|
|| boundedString(collaborationSettings.reasoning_effort, 128, /^[A-Za-z0-9._-]+$/))
|
|
584
713
|
|| !(collaborationSettings.developer_instructions === undefined || collaborationSettings.developer_instructions === null
|
|
585
714
|
|| boundedString(collaborationSettings.developer_instructions, 64 * 1024))
|
|
586
|
-
|| !Array.isArray(
|
|
587
|
-
||
|
|
715
|
+
|| !Array.isArray(disabledPluginIds) || disabledPluginIds.length > 256
|
|
716
|
+
|| disabledPluginIds.some((value) => !boundedString(value, 256, /^[A-Za-z0-9][A-Za-z0-9._:-]*$/))) return invalid();
|
|
588
717
|
const permission = inspectNativeState(settings.permission_profile);
|
|
589
718
|
const collaborationInspection = inspectNativeState(collaboration);
|
|
590
|
-
|
|
719
|
+
const activeInspection = activePermissionProfile === undefined || activePermissionProfile === null
|
|
720
|
+
? { ok: true, opaque: false, encrypted: false } : inspectNativeState(activePermissionProfile);
|
|
721
|
+
if (!permission.ok || !collaborationInspection.ok || !activeInspection.ok) return invalid();
|
|
591
722
|
return { ok: true, model: settings.model, policyFingerprint: nativePolicyFingerprint(settings),
|
|
592
|
-
opaque: permission.opaque || collaborationInspection.opaque,
|
|
593
|
-
encrypted: permission.encrypted || collaborationInspection.encrypted };
|
|
723
|
+
opaque: permission.opaque || collaborationInspection.opaque || activeInspection.opaque,
|
|
724
|
+
encrypted: permission.encrypted || collaborationInspection.encrypted || activeInspection.encrypted };
|
|
594
725
|
}
|
|
595
726
|
|
|
596
727
|
function nativePolicyFingerprint(value) {
|
|
728
|
+
// An absent (serde-default) disabled_plugin_ids is the same policy as an explicit empty list.
|
|
729
|
+
const disabledPluginIds = value?.disabled_plugin_ids === undefined || value?.disabled_plugin_ids === null
|
|
730
|
+
? [] : (Array.isArray(value.disabled_plugin_ids) ? value.disabled_plugin_ids : null);
|
|
597
731
|
if (!isRecord(value) || !isRecord(value.permission_profile) || !nonempty(value.cwd)
|
|
598
732
|
|| !nonempty(value.approval_policy) || !nonempty(value.approvals_reviewer)
|
|
599
|
-
|| !isRecord(value.collaboration_mode) ||
|
|
733
|
+
|| !isRecord(value.collaboration_mode) || disabledPluginIds === null) return null;
|
|
600
734
|
return digest(JSON.stringify({ permissionProfile: stableValue(value.permission_profile), cwd: value.cwd,
|
|
601
735
|
approvalPolicy: value.approval_policy, approvalsReviewer: value.approvals_reviewer,
|
|
602
736
|
collaborationMode: { mode: value.collaboration_mode.mode,
|
|
603
737
|
developerInstructions: value.collaboration_mode.settings?.developer_instructions ?? null },
|
|
604
|
-
disabledPluginIds: [...
|
|
738
|
+
disabledPluginIds: [...disabledPluginIds].sort() }));
|
|
605
739
|
}
|
|
606
740
|
|
|
607
741
|
function stableValue(value) {
|
|
@@ -678,13 +812,14 @@ function optionalSafeInteger(value) { return value === undefined || value === nu
|
|
|
678
812
|
|
|
679
813
|
function freshActive() {
|
|
680
814
|
return { kinds: new Set(), calls: new Set(), outputs: new Set(), hashes: [], opaque: false, encrypted: false,
|
|
681
|
-
droppableReasoningCount: 0,
|
|
815
|
+
droppableReasoningCount: 0, encryptedCompactions: [], handoffMarkers: [],
|
|
682
816
|
latestContext: null, lastCompletedContext: null, currentThreadSettings: null, compactTurnId: '', estimatedTokens: null, estimateValid: false, programVersion: '', modelProvider: '' };
|
|
683
817
|
}
|
|
684
818
|
|
|
685
819
|
function resetActive(active) {
|
|
686
820
|
active.kinds.clear(); active.calls.clear(); active.outputs.clear(); active.hashes.length = 0;
|
|
687
821
|
active.opaque = false; active.encrypted = false; active.droppableReasoningCount = 0;
|
|
822
|
+
active.encryptedCompactions.length = 0; active.handoffMarkers.length = 0;
|
|
688
823
|
active.latestContext = null; active.lastCompletedContext = null;
|
|
689
824
|
active.currentThreadSettings = null;
|
|
690
825
|
active.compactTurnId = ''; active.estimatedTokens = null; active.estimateValid = false;
|
|
@@ -750,6 +885,27 @@ function portableTextOnly(value) {
|
|
|
750
885
|
return visit(value);
|
|
751
886
|
}
|
|
752
887
|
|
|
888
|
+
// D-2: a `message` item whose content carries at least one Codex InputImage part and no other
|
|
889
|
+
// non-text modality. A part is an image part only when its key set is exactly type/image_url/detail;
|
|
890
|
+
// anything else (input_audio, file, nested media, extra keys) falls back to portableTextOnly and
|
|
891
|
+
// therefore refuses, exactly as before.
|
|
892
|
+
function imageOnlyNonText(value) {
|
|
893
|
+
if (!isRecord(value) || !Array.isArray(value.content) || value.content.length === 0) return false;
|
|
894
|
+
let images = 0;
|
|
895
|
+
for (const part of value.content) {
|
|
896
|
+
if (isInputImagePart(part)) { images += 1; continue; }
|
|
897
|
+
if (!portableTextOnly(part)) return false;
|
|
898
|
+
}
|
|
899
|
+
return images > 0;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
function isInputImagePart(part) {
|
|
903
|
+
return isRecord(part) && part.type === 'input_image'
|
|
904
|
+
&& typeof part.image_url === 'string' && part.image_url.length > 0
|
|
905
|
+
&& Object.keys(part).every((key) => ['type', 'image_url', 'detail'].includes(key))
|
|
906
|
+
&& (part.detail === undefined || part.detail === null || typeof part.detail === 'string');
|
|
907
|
+
}
|
|
908
|
+
|
|
753
909
|
function tableExists(db, name) {
|
|
754
910
|
try { return !!db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name=?").get(name); } catch { return false; }
|
|
755
911
|
}
|