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
|
@@ -39,35 +39,83 @@ async function readCursor(journalPath) {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
// I/O working set only: neither the record size nor the recovered records array is capped.
|
|
43
|
+
const JOURNAL_READ_WINDOW_BYTES = 64 * 1024;
|
|
44
|
+
|
|
45
|
+
async function closeAfterJournalFailure(handle, error) {
|
|
46
|
+
try { await handle.close(); }
|
|
47
|
+
catch (closeError) {
|
|
48
|
+
throw new AggregateError([error, closeError], 'Media journal operation and owned handle cleanup failed', { cause: error });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function readJournalWindow(handle, journalPath, position, length) {
|
|
53
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
54
|
+
let filled = 0;
|
|
55
|
+
// Fill one window even when the filesystem returns tiny short reads. Retaining a new 64KiB
|
|
56
|
+
// buffer for each few bytes of progress would amplify a long line's working set needlessly.
|
|
57
|
+
while (filled < length) {
|
|
58
|
+
const remaining = length - filled;
|
|
59
|
+
const { bytesRead } = await handle.read(buffer, filled, remaining, position + filled);
|
|
60
|
+
if (bytesRead === 0) {
|
|
61
|
+
throw Object.assign(new Error(`Media journal ${path.basename(journalPath)} ended before its captured length; recovery is required`),
|
|
62
|
+
{ code: 'CTM_MEDIA_JOURNAL_TRUNCATED' });
|
|
56
63
|
}
|
|
57
|
-
if (bytesRead
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
if (!Number.isSafeInteger(bytesRead) || bytesRead < 0 || bytesRead > remaining) {
|
|
65
|
+
throw Object.assign(new Error('Media journal read returned invalid byte progress'),
|
|
66
|
+
{ code: 'CTM_MEDIA_JOURNAL_READ_INVALID' });
|
|
67
|
+
}
|
|
68
|
+
filled += bytesRead;
|
|
60
69
|
}
|
|
70
|
+
return buffer;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async function frameJournalRecords(handle, journalPath, absoluteStart, size) {
|
|
61
74
|
const records = [];
|
|
62
|
-
let
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
let pieces = [];
|
|
76
|
+
let lineBytes = 0;
|
|
77
|
+
let lineStart = absoluteStart;
|
|
78
|
+
let position = absoluteStart;
|
|
79
|
+
while (position < size) {
|
|
80
|
+
const buffer = await readJournalWindow(handle, journalPath, position,
|
|
81
|
+
Math.min(JOURNAL_READ_WINDOW_BYTES, size - position));
|
|
82
|
+
let pieceStart = 0;
|
|
83
|
+
for (let index = 0; index < buffer.length; index += 1) {
|
|
84
|
+
if (buffer[index] !== 0x0a) continue;
|
|
85
|
+
pieces.push(buffer.subarray(pieceStart, index));
|
|
86
|
+
lineBytes += index - pieceStart;
|
|
87
|
+
const endOffset = position + index + 1;
|
|
88
|
+
const line = pieces.length === 1 ? pieces[0] : Buffer.concat(pieces, lineBytes);
|
|
89
|
+
// Decode only after newline framing: split UTF-8 sequences survive read/window boundaries.
|
|
90
|
+
const raw = line.toString('utf8').trim();
|
|
91
|
+
if (raw) records.push({ entry: JSON.parse(raw), startOffset: lineStart, endOffset });
|
|
92
|
+
pieces = [];
|
|
93
|
+
lineBytes = 0;
|
|
94
|
+
lineStart = endOffset;
|
|
95
|
+
pieceStart = index + 1;
|
|
96
|
+
}
|
|
97
|
+
if (pieceStart < buffer.length) {
|
|
98
|
+
pieces.push(buffer.subarray(pieceStart));
|
|
99
|
+
lineBytes += buffer.length - pieceStart;
|
|
100
|
+
}
|
|
101
|
+
position += buffer.length;
|
|
69
102
|
}
|
|
70
|
-
return { records, size, partialOffset:
|
|
103
|
+
return { records, size, partialOffset: lineStart };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function readRecords(journalPath, startOffset = 0) {
|
|
107
|
+
const handle = await fs.promises.open(journalPath, 'r');
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
const size = (await handle.stat()).size;
|
|
111
|
+
const absoluteStart = Math.min(size, Math.max(0, Number(startOffset) || 0));
|
|
112
|
+
parsed = await frameJournalRecords(handle, journalPath, absoluteStart, size);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
await closeAfterJournalFailure(handle, error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
await handle.close();
|
|
118
|
+
return parsed;
|
|
71
119
|
}
|
|
72
120
|
|
|
73
121
|
async function createMediaJournal(options = {}) {
|
|
@@ -80,7 +128,6 @@ async function createMediaJournal(options = {}) {
|
|
|
80
128
|
const journalPath = path.join(root, `journal-${bootId}.jsonl`);
|
|
81
129
|
const handle = await fs.promises.open(journalPath, 'a', 0o600);
|
|
82
130
|
await fs.promises.chmod(journalPath, 0o600).catch(() => {});
|
|
83
|
-
await syncDirectory(root);
|
|
84
131
|
|
|
85
132
|
const files = new Map();
|
|
86
133
|
let op = Promise.resolve();
|
|
@@ -124,7 +171,14 @@ async function createMediaJournal(options = {}) {
|
|
|
124
171
|
files.set(filePath, { cursor: offset, records: parsed.records, size: parsed.size });
|
|
125
172
|
}
|
|
126
173
|
}
|
|
127
|
-
|
|
174
|
+
try {
|
|
175
|
+
await syncDirectory(root);
|
|
176
|
+
await refresh();
|
|
177
|
+
} catch (error) {
|
|
178
|
+
// A failed constructor returns no journal whose close() the caller could invoke.
|
|
179
|
+
await closeAfterJournalFailure(handle, error);
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
128
182
|
|
|
129
183
|
function serialize(fn) {
|
|
130
184
|
const next = op.then(fn, fn);
|
|
@@ -335,6 +389,9 @@ const { DRAFT_CANONICAL_FIELDS, DRAFT_STATE_VERSION_MAX, canonicalDraftProjectio
|
|
|
335
389
|
|
|
336
390
|
module.exports = {
|
|
337
391
|
createMediaJournal,
|
|
392
|
+
JOURNAL_READ_WINDOW_BYTES,
|
|
393
|
+
readCursor,
|
|
394
|
+
readJournalWindow,
|
|
338
395
|
DRAFT_CANONICAL_FIELDS,
|
|
339
396
|
DRAFT_STATE_VERSION_MAX,
|
|
340
397
|
canonicalDraftProjection,
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
function createMediaJournalProjector(runDbWorkerOp) {
|
|
4
|
+
return (entry, projection = {}) => {
|
|
5
|
+
const urgent = entry.projectionPriority === 'urgent' || projection.urgent;
|
|
6
|
+
const effectiveEntry = urgent && entry.projectionPriority !== 'urgent'
|
|
7
|
+
? { ...entry, projectionPriority: 'urgent' }
|
|
8
|
+
: entry;
|
|
9
|
+
return runDbWorkerOp('runDbMutation', {
|
|
10
|
+
action: 'applyMediaJournalEntry',
|
|
11
|
+
args: [effectiveEntry],
|
|
12
|
+
}, {
|
|
13
|
+
priority: urgent ? 'urgent' : 'low',
|
|
14
|
+
requestClass: urgent ? 'user-blocking' : 'background',
|
|
15
|
+
timeoutMs: urgent ? 10_000 : 30_000,
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
function buildMediaStoreOptions({
|
|
4
21
|
dataDir, bootId, registry, assertDraftOwner, runDbWorkerOp, onDrainProgress,
|
|
5
22
|
currentOwnerId, isSameOwnerLineage,
|
|
@@ -25,21 +42,32 @@ function buildMediaStoreOptions({
|
|
|
25
42
|
// drain progress with the load-pressure controller so the media journal participates
|
|
26
43
|
// in the same producer-debt/freshness framework as read-pool-batch/provider-index above.
|
|
27
44
|
onDrainProgress,
|
|
28
|
-
projectEntry: (
|
|
29
|
-
const urgent = entry.projectionPriority === 'urgent' || projection.urgent;
|
|
30
|
-
const effectiveEntry = urgent && entry.projectionPriority !== 'urgent'
|
|
31
|
-
? { ...entry, projectionPriority: 'urgent' }
|
|
32
|
-
: entry;
|
|
33
|
-
return runDbWorkerOp('runDbMutation', {
|
|
34
|
-
action: 'applyMediaJournalEntry',
|
|
35
|
-
args: [effectiveEntry],
|
|
36
|
-
}, {
|
|
37
|
-
priority: urgent ? 'urgent' : 'low',
|
|
38
|
-
requestClass: urgent ? 'user-blocking' : 'background',
|
|
39
|
-
timeoutMs: urgent ? 10_000 : 30_000,
|
|
40
|
-
});
|
|
41
|
-
},
|
|
45
|
+
projectEntry: createMediaJournalProjector(runDbWorkerOp),
|
|
42
46
|
};
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
|
|
49
|
+
async function prepareMainMediaStore({
|
|
50
|
+
createStore, getDataDir, bootId, runDbWorkerOp, assertDraftOwner,
|
|
51
|
+
onDrainProgress, getCurrentOwnerId, isSameOwnerLineage,
|
|
52
|
+
}) {
|
|
53
|
+
const registry = await runDbWorkerOp('loadMediaStoreRegistry', {}, {
|
|
54
|
+
// Listener activation depends on this registry. It is boot-critical
|
|
55
|
+
// maintenance, while the journal projections below remain background work.
|
|
56
|
+
priority: 'high',
|
|
57
|
+
requestClass: 'maintenance',
|
|
58
|
+
timeoutMs: 30_000,
|
|
59
|
+
});
|
|
60
|
+
return createStore(buildMediaStoreOptions({
|
|
61
|
+
dataDir: getDataDir(), bootId, registry, assertDraftOwner, runDbWorkerOp, onDrainProgress,
|
|
62
|
+
// WP-1 (docs/image-draft-event-ordering-and-verified-adoption-2026-10-14.html §6.4): the store
|
|
63
|
+
// is the single draft version allocator. It recovers the highest pending journal version and
|
|
64
|
+
// then applies verified owner-lineage normalization as one journaled mutation — the draft
|
|
65
|
+
// restamp was removed from db.js restampOwnerLineage so the two can never allocate concurrently.
|
|
66
|
+
// Review finding 9: getCurrentOwnerId delegates to the existing LAZY, MEMOIZED identity
|
|
67
|
+
// accessor only after the DB is open. It returns no invented hostname/port-derived identity.
|
|
68
|
+
// isSameOwnerLineage is the existing dbModule-free lineage snapshot, not a new DB boundary.
|
|
69
|
+
currentOwnerId: getCurrentOwnerId(), isSameOwnerLineage,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = { buildMediaStoreOptions, createMediaJournalProjector, prepareMainMediaStore };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// WP-1 (docs/machine-pool-picker-pairing-dashboard-2026-10-24.html §5 D-4/D-7/D-11, §6.1, §8 WP-1,
|
|
4
|
+
// §9 S-3): the machine-pool schema, in one migration because every piece of it lands with the same
|
|
5
|
+
// reader (lib/host-stats.js today; WP-2/WP-3 for the pairing/self tables).
|
|
6
|
+
//
|
|
7
|
+
// host_samples D-11 — the box owns its own 24 h time series (one row per 60 s tick;
|
|
8
|
+
// ≤1440 rows/machine). No hub-side samples table exists.
|
|
9
|
+
// machine_self D-4 rev 2 — this machine's OWN user settings (display name, favorite,
|
|
10
|
+
// hidden). Exactly one row, id = 1.
|
|
11
|
+
// machine_pairing_offers D-6 — the RFC 8628-shaped code a joining member redeems. The plaintext
|
|
12
|
+
// code is never stored, only its hash.
|
|
13
|
+
// machines.urls_json P-1/P-4 rev 2 — the member's dialable URLs in dial order.
|
|
14
|
+
//
|
|
15
|
+
// Rev 2 deliberately has NO peer_credentials table: D-7 is one shared pool secret in
|
|
16
|
+
// machine-pool.json, never in the DB.
|
|
17
|
+
//
|
|
18
|
+
// The shape follows v55-agent-origin-backfill.js: a narrow dependency object, idempotent SQL, and
|
|
19
|
+
// the version stamp LAST so a failure leaves the ladder where it was. ALTER TABLE has no
|
|
20
|
+
// `IF NOT EXISTS` in SQLite, so the column add is guarded by its own PRAGMA read — which also
|
|
21
|
+
// makes a re-run (a restored snapshot, a partially upgraded file) a no-op rather than an error.
|
|
22
|
+
|
|
23
|
+
const TABLES_DDL = `
|
|
24
|
+
CREATE TABLE IF NOT EXISTS host_samples (
|
|
25
|
+
at INTEGER PRIMARY KEY,
|
|
26
|
+
sample_json TEXT NOT NULL
|
|
27
|
+
);
|
|
28
|
+
CREATE TABLE IF NOT EXISTS machine_self (
|
|
29
|
+
id INTEGER PRIMARY KEY CHECK (id = 1),
|
|
30
|
+
display_name TEXT NOT NULL DEFAULT '',
|
|
31
|
+
favorite INTEGER NOT NULL DEFAULT 0,
|
|
32
|
+
hidden INTEGER NOT NULL DEFAULT 0,
|
|
33
|
+
updated_at INTEGER NOT NULL DEFAULT 0
|
|
34
|
+
);
|
|
35
|
+
CREATE TABLE IF NOT EXISTS machine_pairing_offers (
|
|
36
|
+
id TEXT PRIMARY KEY,
|
|
37
|
+
code_hash TEXT NOT NULL UNIQUE,
|
|
38
|
+
created_at INTEGER NOT NULL,
|
|
39
|
+
expires_at INTEGER NOT NULL,
|
|
40
|
+
redeemed_at INTEGER,
|
|
41
|
+
redeemed_by TEXT
|
|
42
|
+
);
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
function _tableExists(db, table) {
|
|
46
|
+
try {
|
|
47
|
+
return !!db.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table);
|
|
48
|
+
} catch {
|
|
49
|
+
return false; // expected: a handle that cannot read sqlite_master (pre-boot) has nothing to alter
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function _tableHasColumn(db, table, column) {
|
|
54
|
+
try {
|
|
55
|
+
return db.prepare(`PRAGMA table_info(${table})`).all().some((c) => c.name === column);
|
|
56
|
+
} catch {
|
|
57
|
+
return false; // expected: no such table on an old/partial database -> nothing to alter
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function migrateToV56({ getDb, setSchemaVersion, log = console } = {}) {
|
|
62
|
+
if (typeof getDb !== 'function' || typeof setSchemaVersion !== 'function') throw new TypeError('migration dependencies are required');
|
|
63
|
+
const db = getDb();
|
|
64
|
+
db.exec(TABLES_DDL);
|
|
65
|
+
// S-3: existing databases get the column by ALTER; db.js's machines CREATE literal carries the
|
|
66
|
+
// same column for a fresh file, and the two must stay in the same ordinal position.
|
|
67
|
+
let altered = 0;
|
|
68
|
+
if (_tableExists(db, 'machines') && !_tableHasColumn(db, 'machines', 'urls_json')) {
|
|
69
|
+
db.exec("ALTER TABLE machines ADD COLUMN urls_json TEXT NOT NULL DEFAULT '[]'");
|
|
70
|
+
altered = 1;
|
|
71
|
+
}
|
|
72
|
+
setSchemaVersion(56);
|
|
73
|
+
log.log(`[db] Schema migrated to v56 (host samples + machine pool): ${altered} column(s) added`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { migrateToV56 };
|
|
@@ -151,9 +151,14 @@ function createHostedMirrorFeedCoalescer(options = {}) {
|
|
|
151
151
|
clear();
|
|
152
152
|
if (!buffer) return false;
|
|
153
153
|
const batch = buffer;
|
|
154
|
+
// WP-4 (clock-free-tests-followups-r4-2026-10-24.html §5 R-9, §6.5): the batch's FIRST-byte
|
|
155
|
+
// time, not the drain time -- a held/buffered batch was received when its first byte arrived,
|
|
156
|
+
// and the hold is exactly the delay this stamp exists to expose. Captured before `startedAt`
|
|
157
|
+
// is cleared below.
|
|
158
|
+
const receivedAt = startedAt || now();
|
|
154
159
|
buffer = '';
|
|
155
160
|
startedAt = 0;
|
|
156
|
-
deliver(sanitizeAndCoalesceHostedMirrorFeed(batch, command()));
|
|
161
|
+
deliver(sanitizeAndCoalesceHostedMirrorFeed(batch, command()), { receivedAt });
|
|
157
162
|
return true;
|
|
158
163
|
};
|
|
159
164
|
const arm = (ms, opts = {}) => {
|
|
@@ -174,7 +179,8 @@ function createHostedMirrorFeedCoalescer(options = {}) {
|
|
|
174
179
|
const hasSyncControl = _hasSyncFrameControl(text);
|
|
175
180
|
const hasRedrawControl = _hasCursorRedrawControl(text);
|
|
176
181
|
if (!buffer && !hasSyncControl && !hasRedrawControl) {
|
|
177
|
-
|
|
182
|
+
// WP-4 (R-9, §6.5): the immediate path was never held, so its receipt time IS now.
|
|
183
|
+
deliver(sanitizeHostedMirrorFeed(text, command()), { receivedAt: now() });
|
|
178
184
|
return true;
|
|
179
185
|
}
|
|
180
186
|
if (!startedAt) startedAt = now();
|
|
@@ -204,7 +210,10 @@ function createHostedMirrorFeedCoalescer(options = {}) {
|
|
|
204
210
|
const prefix = buffer.slice(0, lastOff + SYNC_OFF.length);
|
|
205
211
|
const trailing = buffer.slice(lastOff + SYNC_OFF.length);
|
|
206
212
|
buffer = trailing;
|
|
207
|
-
|
|
213
|
+
// WP-4 (R-9, §6.5): this prefix came out of the same buffer as flush()'s batch, so it carries
|
|
214
|
+
// the same first-byte time. `startedAt` is still live here when `trailing` is non-empty; the
|
|
215
|
+
// `|| now()` fallback only covers a zeroed clock.
|
|
216
|
+
deliver(sanitizeAndCoalesceHostedMirrorFeed(prefix, command()), { receivedAt: startedAt || now() });
|
|
208
217
|
if (trailing) {
|
|
209
218
|
// Keep startedAt running for the trailing incomplete fragment and re-arm the safety timer.
|
|
210
219
|
arm(2000, { reset: true });
|
|
@@ -6,13 +6,24 @@ const RECIPE_KEYS = Object.freeze([
|
|
|
6
6
|
'version', 'ctmSessionId', 'processGeneration', 'harness', 'providerThreadId',
|
|
7
7
|
'routeId', 'wireModelId', 'profileFingerprint', 'factsRevision', 'transitionId',
|
|
8
8
|
]);
|
|
9
|
-
|
|
9
|
+
// `nativeConfigReceipt` is the Codex config.toml receipt read at launch (state + sha256). It rides
|
|
10
|
+
// the recipe so a session ADOPTED from a surviving host after a CTM restart still proves which
|
|
11
|
+
// config its process started under; without it a lead switch refuses source_config_policy_unqualified.
|
|
12
|
+
const OPTIONAL_RECIPE_KEYS = Object.freeze(['sourceEnvironmentReference', 'nativeConfigReceipt']);
|
|
10
13
|
const SOURCE_ENVIRONMENT_REFERENCES = new Set(['captured-empty', 'private-owner-required']);
|
|
11
14
|
const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
|
|
12
15
|
const CANONICAL_MODEL_ID_PATTERN = /^[A-Za-z0-9@][A-Za-z0-9@._:/+-]{0,255}$/;
|
|
13
16
|
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
14
17
|
const SHA256_PATTERN = /^[0-9a-f]{64}$/;
|
|
15
18
|
|
|
19
|
+
function validConfigReceipt(value) {
|
|
20
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
21
|
+
const keys = Object.keys(value);
|
|
22
|
+
if (keys.length !== 2 || !keys.includes('state') || !keys.includes('sha256')) return false;
|
|
23
|
+
return (value.state === 'present' && typeof value.sha256 === 'string' && SHA256_PATTERN.test(value.sha256))
|
|
24
|
+
|| (value.state === 'missing' && value.sha256 === null);
|
|
25
|
+
}
|
|
26
|
+
|
|
16
27
|
function boundedId(value) {
|
|
17
28
|
return typeof value === 'string' && ID_PATTERN.test(value);
|
|
18
29
|
}
|
|
@@ -37,6 +48,7 @@ function sanitizedRecipe(value, minimumGeneration = 1) {
|
|
|
37
48
|
|| RECIPE_KEYS.some((key) => !Object.hasOwn(value, key))) return undefined;
|
|
38
49
|
if (Object.hasOwn(value, 'sourceEnvironmentReference')
|
|
39
50
|
&& !SOURCE_ENVIRONMENT_REFERENCES.has(value.sourceEnvironmentReference)) return undefined;
|
|
51
|
+
if (Object.hasOwn(value, 'nativeConfigReceipt') && !validConfigReceipt(value.nativeConfigReceipt)) return undefined;
|
|
40
52
|
if (value.version !== 1 || !boundedId(value.ctmSessionId)
|
|
41
53
|
|| !Number.isSafeInteger(value.processGeneration) || value.processGeneration < minimumGeneration
|
|
42
54
|
|| !['codex-cli', 'claude-code'].includes(value.harness)
|
|
@@ -50,8 +62,9 @@ function sanitizedRecipe(value, minimumGeneration = 1) {
|
|
|
50
62
|
|| typeof value.factsRevision !== 'string' || !SHA256_PATTERN.test(value.factsRevision)) return undefined;
|
|
51
63
|
|
|
52
64
|
if (value.transitionId !== null && !boundedId(value.transitionId)) return undefined;
|
|
53
|
-
return Object.fromEntries([...RECIPE_KEYS, ...(Object.hasOwn(value,
|
|
54
|
-
|
|
65
|
+
return Object.fromEntries([...RECIPE_KEYS, ...OPTIONAL_RECIPE_KEYS.filter((key) => Object.hasOwn(value, key))]
|
|
66
|
+
.map((key) => [key, key === 'nativeConfigReceipt'
|
|
67
|
+
? { state: value[key].state, sha256: value[key].sha256 } : value[key]]));
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
function modelExecutionRecipeFromEnv(env) {
|
|
@@ -92,6 +92,10 @@ function anthropicErrorType(kind) {
|
|
|
92
92
|
if (kind === 'rate_limit_exceeded') return 'rate_limit_error';
|
|
93
93
|
if (kind === 'insufficient_quota') return 'billing_error';
|
|
94
94
|
if (kind === 'server_is_overloaded') return 'overloaded_error';
|
|
95
|
+
// WP-2 D-5: the two truthful refusal classes carry their own HTTP status (400 / 403), so the type
|
|
96
|
+
// must not collapse into api_error -- a permission denial is not an upstream fault.
|
|
97
|
+
if (kind === 'model_not_invocable') return 'invalid_request_error';
|
|
98
|
+
if (kind === 'model_access_denied') return 'permission_error';
|
|
95
99
|
return 'api_error';
|
|
96
100
|
}
|
|
97
101
|
|
|
@@ -20,6 +20,9 @@ function createChatResponseTranslators({ normalizeUpstreamOutcome, firstString,
|
|
|
20
20
|
if (kind === 'rate_limit_exceeded') return 'rate_limit_error';
|
|
21
21
|
if (kind === 'insufficient_quota') return 'billing_error';
|
|
22
22
|
if (kind === 'server_is_overloaded') return 'overloaded_error';
|
|
23
|
+
// WP-2 D-5: same two mappings as anthropic-face.js (HTTP 400 / 403 respectively).
|
|
24
|
+
if (kind === 'model_not_invocable') return 'invalid_request_error';
|
|
25
|
+
if (kind === 'model_access_denied') return 'permission_error';
|
|
23
26
|
return 'api_error';
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -27,6 +27,12 @@
|
|
|
27
27
|
// Nothing here reads or writes the upstream-native Responses body: a
|
|
28
28
|
// `passthrough` route never calls this module at all.
|
|
29
29
|
|
|
30
|
+
// node:crypto is used for sha256 ONLY (WP-3's handoff marker): a digest is a pure,
|
|
31
|
+
// deterministic function of its argument, so this module stays free of randomness
|
|
32
|
+
// -- no randomUUID/no randomBytes, and every call still returns the same value for
|
|
33
|
+
// the same arguments.
|
|
34
|
+
const crypto = require('node:crypto');
|
|
35
|
+
|
|
30
36
|
// The reserved V2 collaboration namespace (Codex multi_agents_v2.rs) and the
|
|
31
37
|
// older V1 one (multi_agent_v1). A call is only "readable plaintext" in the V2
|
|
32
38
|
// namespace -- V1's `spawn_agent` is a different wire contract entirely.
|
|
@@ -449,6 +455,93 @@ function validateCollaborationInput(body) {
|
|
|
449
455
|
});
|
|
450
456
|
}
|
|
451
457
|
|
|
458
|
+
// ── handed-off compaction drop (WP-3) ────────────────────────────────────
|
|
459
|
+
//
|
|
460
|
+
// A Codex lead whose history holds an OpenAI-encrypted `compaction` item cannot
|
|
461
|
+
// replay that item to a routed (chat-translate) upstream: the ciphertext is bound
|
|
462
|
+
// to its issuer and reads as garbage there. The handoff path therefore injects,
|
|
463
|
+
// into the target thread, ONE developer message carrying a plaintext summary and
|
|
464
|
+
// naming -- by SHA-256 of the ciphertext it replaces -- the exact compaction item
|
|
465
|
+
// it stands for:
|
|
466
|
+
//
|
|
467
|
+
// <ctm_handoff compaction_sha256="<64 lowercase hex>" source_model="<model>">
|
|
468
|
+
// …summary…
|
|
469
|
+
// </ctm_handoff>
|
|
470
|
+
//
|
|
471
|
+
// Codex then sends every subsequent request with BOTH the `compaction` item
|
|
472
|
+
// (verbatim) and, later in `input`, that developer message. The pairing is the
|
|
473
|
+
// whole contract: a compaction item is dropped IFF its own replacement is present
|
|
474
|
+
// in the SAME request, at a LATER index. An unmatched compaction item is history
|
|
475
|
+
// this route cannot read and stays exactly where it was, so `validateCollaborationInput`
|
|
476
|
+
// keeps refusing it (fail-closed) rather than silently losing a turn.
|
|
477
|
+
//
|
|
478
|
+
// The drop is a COPY: the caller's body object and its `input` array are never
|
|
479
|
+
// mutated, and the caller's own body reference is returned untouched when nothing
|
|
480
|
+
// was dropped.
|
|
481
|
+
|
|
482
|
+
const HANDOFF_MARKER_PREFIX = '<ctm_handoff compaction_sha256="';
|
|
483
|
+
|
|
484
|
+
/** sha256 (utf8) of a ciphertext string, lowercase hex. */
|
|
485
|
+
function ciphertextSha256(encryptedContent) {
|
|
486
|
+
return crypto.createHash('sha256').update(encryptedContent, 'utf8').digest('hex');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/** True for a `compaction` item whose own ciphertext is present and non-empty. */
|
|
490
|
+
function isCiphertextCompaction(item) {
|
|
491
|
+
return isObject(item)
|
|
492
|
+
&& item.type === 'compaction'
|
|
493
|
+
&& typeof item.encrypted_content === 'string'
|
|
494
|
+
&& item.encrypted_content.length > 0;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* True for the handoff developer message that REPLACES the compaction item whose
|
|
499
|
+
* ciphertext hashes to `sha`.
|
|
500
|
+
*
|
|
501
|
+
* The shape is exact and deliberately narrow: a `message` item whose role is
|
|
502
|
+
* `developer`, whose `content` is an array, and whose FIRST part starts with the
|
|
503
|
+
* literal marker prefix. A bare string `content`, a second-part marker, a
|
|
504
|
+
* `role:'user'` message, a leading space before the marker or a marker for another
|
|
505
|
+
* ciphertext all fail here -- the marker is the pairing proof, so a near-miss must
|
|
506
|
+
* never be treated as one.
|
|
507
|
+
*/
|
|
508
|
+
function isHandoffMarkerFor(item, sha) {
|
|
509
|
+
if (!isObject(item) || item.type !== 'message' || item.role !== 'developer') return false;
|
|
510
|
+
if (!Array.isArray(item.content) || item.content.length === 0) return false;
|
|
511
|
+
const first = item.content[0];
|
|
512
|
+
if (!isObject(first) || first.type !== 'input_text' || typeof first.text !== 'string') return false;
|
|
513
|
+
return first.text.startsWith(`${HANDOFF_MARKER_PREFIX}${sha}"`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Omit every `compaction` item whose handoff replacement is present LATER in the
|
|
518
|
+
* same `input`.
|
|
519
|
+
*
|
|
520
|
+
* @param {unknown} body a Responses request body
|
|
521
|
+
* @returns {{ok:true, body:object, droppedHandedOffCompactions:number}} `body` is
|
|
522
|
+
* the caller's own object (same reference) whenever nothing was dropped.
|
|
523
|
+
*/
|
|
524
|
+
function dropHandedOffCompactions(body) {
|
|
525
|
+
const source = isObject(body) ? body : {};
|
|
526
|
+
const items = normalizeItems(source.input);
|
|
527
|
+
let droppedHandedOffCompactions = 0;
|
|
528
|
+
const kept = [];
|
|
529
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
530
|
+
const item = items[index];
|
|
531
|
+
if (isCiphertextCompaction(item)) {
|
|
532
|
+
const sha = ciphertextSha256(item.encrypted_content);
|
|
533
|
+
let covered = false;
|
|
534
|
+
for (let later = index + 1; later < items.length; later += 1) {
|
|
535
|
+
if (isHandoffMarkerFor(items[later], sha)) { covered = true; break; }
|
|
536
|
+
}
|
|
537
|
+
if (covered) { droppedHandedOffCompactions += 1; continue; }
|
|
538
|
+
}
|
|
539
|
+
kept.push(item);
|
|
540
|
+
}
|
|
541
|
+
if (droppedHandedOffCompactions === 0) return { ok: true, body, droppedHandedOffCompactions };
|
|
542
|
+
return { ok: true, body: { ...source, input: kept }, droppedHandedOffCompactions };
|
|
543
|
+
}
|
|
544
|
+
|
|
452
545
|
// ── translated function-call constructor ─────────────────────────────────
|
|
453
546
|
|
|
454
547
|
/** True only for a translated call Codex must read as readable plaintext args. */
|
|
@@ -488,6 +581,7 @@ function makeTranslatedFunctionCall(fields = {}) {
|
|
|
488
581
|
|
|
489
582
|
module.exports = {
|
|
490
583
|
validateCollaborationInput,
|
|
584
|
+
dropHandedOffCompactions,
|
|
491
585
|
agentMessageToChat,
|
|
492
586
|
makeTranslatedFunctionCall,
|
|
493
587
|
isReadableCollaborationCall,
|