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
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
// public/m/pool-failover.js — WP-6 P-7 (docs/machine-pool-picker-pairing-dashboard-2026-10-24.html
|
|
2
|
+
// §5 P-7, §6.4 "rev 2 P-7 phone pool", §8 WP-6, §9 S-26).
|
|
3
|
+
//
|
|
4
|
+
// The phone signs in (passkey) once per member origin, so passkeys — and the per-origin outbox — are
|
|
5
|
+
// pinned to a hostname. When the origin the phone is on stops answering, this module probes the other
|
|
6
|
+
// pool members' public origins with an opaque `fetch(origin + '/m/manifest.json', {mode:'no-cors'})`
|
|
7
|
+
// and sends the browser to the first that answers, carrying `?poolFrom=<this instance>` so the
|
|
8
|
+
// receiving member can say who it took over from (P-7).
|
|
9
|
+
//
|
|
10
|
+
// It is a classic script, loaded by public/m/index.html BEFORE /m/app.js and listed in sw.js
|
|
11
|
+
// SHELL_ASSETS, because the whole point is that it runs while the app's own API is unreachable.
|
|
12
|
+
//
|
|
13
|
+
// * localStorage holds ONLY the dial cache `ctm.pool.origins`
|
|
14
|
+
// ([{ instanceId, displayName, origin, lastState, lastSeenAt }], last-reached first) and the
|
|
15
|
+
// content-free presence marker `ctm.pool.outboxPending` ('1' while app.js has queued outbox
|
|
16
|
+
// entries, absent otherwise — see below). Never a secret, never a token, never an entry, never a
|
|
17
|
+
// machine setting (D-4: settings live on the machine).
|
|
18
|
+
// * Every dependency is injectable (storage, location, fetch, confirm, setTimeout/clearTimeout,
|
|
19
|
+
// AbortController, clock, DOM host), so both the boot-failure path and the banner are provable
|
|
20
|
+
// without a browser. Nothing here reads Date.now() on a path a test drives: `now` is injected.
|
|
21
|
+
// * Every storage access is wrapped: a private-mode or blocked localStorage returns the empty dial
|
|
22
|
+
// cache and boot continues, it never throws.
|
|
23
|
+
(function (root) {
|
|
24
|
+
'use strict';
|
|
25
|
+
|
|
26
|
+
var POOL_ORIGINS_KEY = 'ctm.pool.origins';
|
|
27
|
+
// P-7 boot seam. The outbox itself is private: it lives behind the private lease (IndexedDB plus a
|
|
28
|
+
// leased localStorage mirror), and the boot-failure path runs BEFORE any lease exists — so it cannot
|
|
29
|
+
// read the queue and `state.remoteOutbox` is always empty there. app.js therefore mirrors ONLY the
|
|
30
|
+
// queue's presence into plain window.localStorage: this one key, the string '1' while entries are
|
|
31
|
+
// queued, and no key at all the moment the queue empties. Never an entry, an id, a count, a command
|
|
32
|
+
// or a principal — a boolean's worth of state, which is exactly what P-7's "ask before leaving an
|
|
33
|
+
// origin that still holds unsent messages" prompt needs.
|
|
34
|
+
var POOL_OUTBOX_PENDING_KEY = 'ctm.pool.outboxPending';
|
|
35
|
+
var PROBE_PATH = '/m/manifest.json';
|
|
36
|
+
var PROBE_TIMEOUT_MS = 4000;
|
|
37
|
+
var BANNER_ID = 'pool-from-banner';
|
|
38
|
+
// A pool is 2-20 of the user's own machines (design §2). The cache is capped so a runaway roster
|
|
39
|
+
// can never fill the 5 MB localStorage quota the outbox also lives in.
|
|
40
|
+
var ORIGINS_MAX = 24;
|
|
41
|
+
|
|
42
|
+
function trims(value) {
|
|
43
|
+
return String(value == null ? '' : value).trim();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// The one escaper. This module deliberately does not depend on the app's escAbsent esc: it runs in
|
|
47
|
+
// the shell before app.js and inside a vm test.
|
|
48
|
+
function poolEsc(value) {
|
|
49
|
+
return String(value == null ? '' : value).replace(/[&<>"']/g, function (ch) {
|
|
50
|
+
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ch];
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// A public origin: scheme + host (+ port), no path, no trailing slash. Anything that is not http(s)
|
|
55
|
+
// is not a dial target (a blob:/data: URL would be a bug, not a member).
|
|
56
|
+
function normalizePoolOrigin(value) {
|
|
57
|
+
var raw = trims(value).replace(/\/+$/, '');
|
|
58
|
+
if (!/^https?:\/\/[^/?#]+/i.test(raw)) return '';
|
|
59
|
+
var match = raw.match(/^(https?:\/\/[^/?#]+)/i);
|
|
60
|
+
return match ? match[1] : '';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// One stored row, or null. Exactly the five documented fields — a row that carries anything else
|
|
64
|
+
// (a token, a secret, a session id) is rebuilt from the five, so nothing extra is ever re-persisted.
|
|
65
|
+
function normalizePoolOriginRow(row) {
|
|
66
|
+
if (!row || typeof row !== 'object') return null;
|
|
67
|
+
var origin = normalizePoolOrigin(row.origin);
|
|
68
|
+
if (!origin) return null;
|
|
69
|
+
return {
|
|
70
|
+
instanceId: trims(row.instanceId),
|
|
71
|
+
displayName: trims(row.displayName),
|
|
72
|
+
origin: origin,
|
|
73
|
+
lastState: trims(row.lastState),
|
|
74
|
+
lastSeenAt: Number(row.lastSeenAt) || 0,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function poolStorage(storage) {
|
|
79
|
+
if (storage) return storage;
|
|
80
|
+
try {
|
|
81
|
+
return typeof localStorage !== 'undefined' ? localStorage : null;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
return null; // expected: a blocked/opaque context throws on the localStorage getter itself
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function readPoolOrigins(storage) {
|
|
88
|
+
var store = poolStorage(storage);
|
|
89
|
+
if (!store || typeof store.getItem !== 'function') return [];
|
|
90
|
+
var raw = null;
|
|
91
|
+
try {
|
|
92
|
+
raw = store.getItem(POOL_ORIGINS_KEY);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
return []; // HANDLE: private mode / blocked storage — the dial cache is optional, boot continues
|
|
95
|
+
}
|
|
96
|
+
if (!raw) return [];
|
|
97
|
+
var parsed = null;
|
|
98
|
+
try {
|
|
99
|
+
parsed = JSON.parse(raw);
|
|
100
|
+
} catch (error) {
|
|
101
|
+
return []; // HANDLE: a corrupted cache is dropped, never fatal — the phone boots with no roster
|
|
102
|
+
}
|
|
103
|
+
if (!Array.isArray(parsed)) return [];
|
|
104
|
+
return parsed.map(normalizePoolOriginRow).filter(Boolean).slice(0, ORIGINS_MAX);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function writePoolOrigins(storage, rows) {
|
|
108
|
+
var store = poolStorage(storage);
|
|
109
|
+
if (!store || typeof store.setItem !== 'function') return false;
|
|
110
|
+
var clean = (Array.isArray(rows) ? rows : []).map(normalizePoolOriginRow).filter(Boolean).slice(0, ORIGINS_MAX);
|
|
111
|
+
try {
|
|
112
|
+
store.setItem(POOL_ORIGINS_KEY, JSON.stringify(clean));
|
|
113
|
+
} catch (error) {
|
|
114
|
+
return false; // REPORT: quota/blocked storage — the caller keeps the in-memory rows it just built
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// P-7 boot seam, read half: is there anything queued on this origin? `true` only for the presence
|
|
120
|
+
// marker app.js writes; a missing key, a blocked storage or a corrupted value all mean "nothing
|
|
121
|
+
// queued" so the caller can fall through to the ordinary boot. Storage is injectable.
|
|
122
|
+
function readOutboxPendingMarker(storage) {
|
|
123
|
+
var store = poolStorage(storage);
|
|
124
|
+
if (!store || typeof store.getItem !== 'function') return false;
|
|
125
|
+
var raw = null;
|
|
126
|
+
try {
|
|
127
|
+
raw = store.getItem(POOL_OUTBOX_PENDING_KEY);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
return false; // HANDLE: private mode / blocked storage — boot continues as if nothing is queued
|
|
130
|
+
}
|
|
131
|
+
return String(raw) === '1';
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// P-7 boot seam, write half: presence only — '1' while `pending`, the key removed when not. Called
|
|
135
|
+
// from every app.js outbox persist and from every path that clears the queue.
|
|
136
|
+
function writeOutboxPendingMarker(storage, pending) {
|
|
137
|
+
var store = poolStorage(storage);
|
|
138
|
+
if (!store) return false;
|
|
139
|
+
try {
|
|
140
|
+
if (pending) {
|
|
141
|
+
if (typeof store.setItem !== 'function') return false;
|
|
142
|
+
store.setItem(POOL_OUTBOX_PENDING_KEY, '1');
|
|
143
|
+
} else {
|
|
144
|
+
if (typeof store.removeItem !== 'function') return false;
|
|
145
|
+
store.removeItem(POOL_OUTBOX_PENDING_KEY);
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return false; // HANDLE: quota / blocked storage — the marker is an optimisation, never fatal
|
|
149
|
+
}
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// P-7: called after every successful phone /api/machines load. THIS origin is the one just reached,
|
|
154
|
+
// so it is stamped `now` (and therefore sorts first: "last reached, then the next reachable"); every
|
|
155
|
+
// other member keeps the lastSeenAt it already had. `self` is the phone's own manifest/machine-self
|
|
156
|
+
// row — used for the display name only, never for a credential.
|
|
157
|
+
function rememberPoolOrigins(machines, self, deps) {
|
|
158
|
+
var options = deps || {};
|
|
159
|
+
var at = Number(typeof options.now === 'function' ? options.now() : Date.now()) || 0;
|
|
160
|
+
var store = poolStorage(options.storage);
|
|
161
|
+
var previous = readPoolOrigins(store);
|
|
162
|
+
var selfId = trims((self && self.instanceId) || options.selfInstanceId);
|
|
163
|
+
var selfName = trims(self && (self.displayName || self.hostname));
|
|
164
|
+
var selfOrigin = normalizePoolOrigin((self && machinePoolOrigin(self)) || options.origin || '');
|
|
165
|
+
var reachable = {};
|
|
166
|
+
var rows = [];
|
|
167
|
+
var push = function (row) {
|
|
168
|
+
var clean = normalizePoolOriginRow(row);
|
|
169
|
+
if (!clean || reachable[clean.origin]) return;
|
|
170
|
+
reachable[clean.origin] = true;
|
|
171
|
+
rows.push(clean);
|
|
172
|
+
};
|
|
173
|
+
var lastSeenFor = function (origin) {
|
|
174
|
+
var found = previous.filter(function (row) { return row.origin === origin; })[0];
|
|
175
|
+
return found ? found.lastSeenAt : 0;
|
|
176
|
+
};
|
|
177
|
+
if (selfOrigin) {
|
|
178
|
+
push({ instanceId: selfId, displayName: selfName, origin: selfOrigin, lastState: trims(self && self.health) || 'reachable', lastSeenAt: at });
|
|
179
|
+
}
|
|
180
|
+
(Array.isArray(machines) ? machines : []).forEach(function (machine) {
|
|
181
|
+
if (!machine || !machine.instanceId) return;
|
|
182
|
+
var origin = typeof machinePoolOrigin === 'function' ? machinePoolOrigin(machine) : '';
|
|
183
|
+
if (!origin) return;
|
|
184
|
+
push({
|
|
185
|
+
instanceId: trims(machine.instanceId),
|
|
186
|
+
displayName: trims(machine.displayName || machine.hostname || machine.url),
|
|
187
|
+
origin: origin,
|
|
188
|
+
lastState: trims(machine.health) || 'unknown',
|
|
189
|
+
lastSeenAt: lastSeenFor(origin),
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
rows.sort(function (a, b) {
|
|
193
|
+
return (b.lastSeenAt - a.lastSeenAt) || a.displayName.localeCompare(b.displayName) || a.origin.localeCompare(b.origin);
|
|
194
|
+
});
|
|
195
|
+
writePoolOrigins(store, rows);
|
|
196
|
+
return rows;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// P-7: `fetch(origin + '/m/manifest.json', { mode:'no-cors', cache:'no-store' })` with an
|
|
200
|
+
// AbortController timeout. An OPAQUE response (type 'opaque') is the reachable signal: a cross-origin
|
|
201
|
+
// no-cors read can never expose a status, and a request that resolved at all proves the origin
|
|
202
|
+
// answered. A rejection, a synchronous throw, or the timeout is `false` — never a throw.
|
|
203
|
+
function probeOrigin(origin, options) {
|
|
204
|
+
var settings = options || {};
|
|
205
|
+
var base = normalizePoolOrigin(origin);
|
|
206
|
+
if (!base) return Promise.resolve(false);
|
|
207
|
+
var fetchImpl = settings.fetchImpl || (typeof fetch === 'function' ? fetch : null);
|
|
208
|
+
if (typeof fetchImpl !== 'function') return Promise.resolve(false);
|
|
209
|
+
var setTimer = settings.setTimeoutImpl || (typeof setTimeout === 'function' ? setTimeout : null);
|
|
210
|
+
var clearTimer = settings.clearTimeoutImpl || (typeof clearTimeout === 'function' ? clearTimeout : null);
|
|
211
|
+
var AbortCtor = settings.AbortControllerImpl || (typeof AbortController === 'function' ? AbortController : null);
|
|
212
|
+
var timeoutMs = Number(settings.timeoutMs == null ? PROBE_TIMEOUT_MS : settings.timeoutMs);
|
|
213
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) timeoutMs = PROBE_TIMEOUT_MS;
|
|
214
|
+
var controller = AbortCtor ? new AbortCtor() : null;
|
|
215
|
+
return new Promise(function (resolve) {
|
|
216
|
+
var settled = false;
|
|
217
|
+
var timer = null;
|
|
218
|
+
var finish = function (ok) {
|
|
219
|
+
if (settled) return;
|
|
220
|
+
settled = true;
|
|
221
|
+
if (timer != null && typeof clearTimer === 'function') clearTimer(timer);
|
|
222
|
+
resolve(!!ok);
|
|
223
|
+
};
|
|
224
|
+
if (typeof setTimer === 'function') {
|
|
225
|
+
timer = setTimer(function () {
|
|
226
|
+
// The probe is cut at the timeout: an unresolved fetch is not evidence the origin is up.
|
|
227
|
+
try {
|
|
228
|
+
if (controller && typeof controller.abort === 'function') controller.abort();
|
|
229
|
+
} catch (error) {
|
|
230
|
+
/* expected: aborting a request that already settled is a no-op */
|
|
231
|
+
}
|
|
232
|
+
finish(false);
|
|
233
|
+
}, timeoutMs);
|
|
234
|
+
}
|
|
235
|
+
var request = null;
|
|
236
|
+
try {
|
|
237
|
+
request = fetchImpl(base + PROBE_PATH, {
|
|
238
|
+
mode: 'no-cors',
|
|
239
|
+
cache: 'no-store',
|
|
240
|
+
signal: controller ? controller.signal : undefined,
|
|
241
|
+
});
|
|
242
|
+
} catch (error) {
|
|
243
|
+
finish(false); // HANDLE: a synchronous fetch throw (blocked URL, no CORS) is "not reachable"
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
Promise.resolve(request).then(function (res) {
|
|
247
|
+
// No status is readable through an opaque response, so "it resolved" is the whole signal.
|
|
248
|
+
finish(!!res);
|
|
249
|
+
}, function () {
|
|
250
|
+
finish(false); // HANDLE: a network error is exactly "this member does not answer"
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function poolOriginsListHtml(rows) {
|
|
256
|
+
var items = (Array.isArray(rows) ? rows : []).map(function (row) {
|
|
257
|
+
var name = row.displayName || row.instanceId || row.origin;
|
|
258
|
+
var state = row.lastState || 'unknown';
|
|
259
|
+
var seen = row.lastSeenAt ? 'last seen ' + new Date(row.lastSeenAt).toLocaleString() : 'never seen';
|
|
260
|
+
return '<li class="pool-origin-row" data-origin="' + poolEsc(row.origin) + '">'
|
|
261
|
+
+ '<span class="pool-origin-name">' + poolEsc(name) + '</span>'
|
|
262
|
+
+ '<span class="pool-origin-state">' + poolEsc(state + ' · ' + seen) + '</span>'
|
|
263
|
+
+ '<span class="pool-origin-address">' + poolEsc(row.origin) + '</span>'
|
|
264
|
+
+ '</li>';
|
|
265
|
+
}).join('');
|
|
266
|
+
return '<div class="pool-failover-list" role="status">'
|
|
267
|
+
+ '<p class="pool-failover-copy">No machine in this pool answered from this phone. '
|
|
268
|
+
+ 'These are their last known states.</p>'
|
|
269
|
+
+ '<ul class="pool-origin-rows">' + items + '</ul>'
|
|
270
|
+
+ '</div>';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function mountPoolOriginsList(html, rows, deps) {
|
|
274
|
+
var host = (deps && deps.document) || (typeof document !== 'undefined' ? document : null);
|
|
275
|
+
if (!host || typeof host.getElementById !== 'function') return null;
|
|
276
|
+
var node = host.getElementById('pool-failover-list');
|
|
277
|
+
if (!node) return null;
|
|
278
|
+
if (typeof node.innerHTML === 'string' || node.innerHTML === '') node.innerHTML = String(html);
|
|
279
|
+
return node;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// P-7 boot failure. Called by app.js when the FIRST API call of a boot does not answer (a network
|
|
283
|
+
// error, or a 5xx/offline-tunnel answer from the relay):
|
|
284
|
+
// * with nothing queued, the first member that answers takes over (location.assign, carrying
|
|
285
|
+
// `?poolFrom=<this instance>`);
|
|
286
|
+
// * with unsent outbox items the switch is ASKED for first, because the outbox is per origin and
|
|
287
|
+
// would otherwise be stranded — "no" leaves the user exactly where they are;
|
|
288
|
+
// * when no member answers, the roster renders with its last-known states.
|
|
289
|
+
function failoverOnBootFailure(options) {
|
|
290
|
+
var settings = options || {};
|
|
291
|
+
var loc = settings.location || (typeof location !== 'undefined' ? location : null);
|
|
292
|
+
var rows = readPoolOrigins(settings.storage);
|
|
293
|
+
var selfOrigin = normalizePoolOrigin(settings.origin
|
|
294
|
+
|| (loc && (loc.origin || (loc.protocol && loc.host ? loc.protocol + '//' + loc.host : ''))) || '');
|
|
295
|
+
var selfId = trims(settings.selfInstanceId);
|
|
296
|
+
var candidates = rows.filter(function (row) { return row.origin !== selfOrigin; });
|
|
297
|
+
if (!candidates.length) {
|
|
298
|
+
return Promise.resolve({ switched: false, to: '', asked: false, reason: 'no_members', rows: rows });
|
|
299
|
+
}
|
|
300
|
+
var selfName = (rows.filter(function (row) { return row.origin === selfOrigin; })[0] || {}).displayName
|
|
301
|
+
|| selfOrigin || selfId;
|
|
302
|
+
if (settings.hasUnsentOutbox) {
|
|
303
|
+
var ask = settings.confirmImpl || (typeof confirm === 'function' ? confirm : null);
|
|
304
|
+
var question = settings.confirmText
|
|
305
|
+
|| ('This phone has messages that have not been sent from ' + selfName + '. Switch to another machine anyway?');
|
|
306
|
+
var yes = false;
|
|
307
|
+
if (typeof ask === 'function') {
|
|
308
|
+
try {
|
|
309
|
+
yes = !!ask(question);
|
|
310
|
+
} catch (error) {
|
|
311
|
+
yes = false; // expected: a blocked/dismissed confirm dialog means "do not navigate away"
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (!yes) {
|
|
315
|
+
return Promise.resolve({ switched: false, to: '', asked: true, reason: 'outbox_unsent', rows: rows });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
var index = 0;
|
|
319
|
+
var attempt = function () {
|
|
320
|
+
if (index >= candidates.length) {
|
|
321
|
+
var html = poolOriginsListHtml(rows);
|
|
322
|
+
var render = settings.renderList || function (markup, list) { return mountPoolOriginsList(markup, list, settings); };
|
|
323
|
+
render(html, rows);
|
|
324
|
+
return { switched: false, to: '', asked: false, reason: 'no_member_answered', html: html, rows: rows };
|
|
325
|
+
}
|
|
326
|
+
var row = candidates[index];
|
|
327
|
+
index += 1;
|
|
328
|
+
return probeOrigin(row.origin, settings).then(function (reachable) {
|
|
329
|
+
if (!reachable) return attempt();
|
|
330
|
+
var target = row.origin + '/m/?poolFrom=' + encodeURIComponent(selfId || selfOrigin);
|
|
331
|
+
if (loc && typeof loc.assign === 'function') loc.assign(target);
|
|
332
|
+
else if (loc) loc.href = target;
|
|
333
|
+
return { switched: true, to: row.origin, asked: false, reason: 'switched', href: target, rows: rows };
|
|
334
|
+
});
|
|
335
|
+
};
|
|
336
|
+
return Promise.resolve().then(attempt);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// `?poolFrom=<id>` on arrival: "<from name> is unreachable — switched to <this name>". Both names
|
|
340
|
+
// come from the stored roster (fall back to the id), every string is escaped, and the banner mounts
|
|
341
|
+
// into #pool-from-banner when the page has one.
|
|
342
|
+
function showPoolFromBanner(options) {
|
|
343
|
+
var settings = options || {};
|
|
344
|
+
var loc = settings.location || (typeof location !== 'undefined' ? location : null);
|
|
345
|
+
var search = settings.search != null ? String(settings.search) : String((loc && loc.search) || '');
|
|
346
|
+
var match = search.match(/[?&]poolFrom=([^&#]*)/);
|
|
347
|
+
var from = match ? decodeURIComponent(match[1].replace(/\+/g, ' ')) : '';
|
|
348
|
+
if (!from) return null;
|
|
349
|
+
var rows = settings.origins || readPoolOrigins(settings.storage);
|
|
350
|
+
var find = function (id) {
|
|
351
|
+
return rows.filter(function (row) { return row.instanceId === id; })[0] || null;
|
|
352
|
+
};
|
|
353
|
+
var self = settings.self || null;
|
|
354
|
+
var selfId = trims((self && self.instanceId) || settings.selfInstanceId);
|
|
355
|
+
var fromRow = find(from);
|
|
356
|
+
var selfRow = find(selfId);
|
|
357
|
+
var fromName = (fromRow && fromRow.displayName) || from;
|
|
358
|
+
var selfName = (selfRow && selfRow.displayName) || trims(self && self.displayName) || selfId || trims(settings.origin);
|
|
359
|
+
var text = fromName + ' is unreachable — switched to ' + selfName;
|
|
360
|
+
var html = '<div class="pool-from-banner" role="status">' + poolEsc(text) + '</div>';
|
|
361
|
+
var host = settings.document || (typeof document !== 'undefined' ? document : null);
|
|
362
|
+
var node = null;
|
|
363
|
+
if (host && typeof host.getElementById === 'function') {
|
|
364
|
+
node = host.getElementById(BANNER_ID);
|
|
365
|
+
if (node && typeof node.innerHTML === 'string') node.innerHTML = String(html);
|
|
366
|
+
}
|
|
367
|
+
return { from: from, selfId: selfId, fromName: fromName, selfName: selfName, text: text, html: html, node: node };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
var out = {
|
|
371
|
+
POOL_ORIGINS_KEY: POOL_ORIGINS_KEY,
|
|
372
|
+
POOL_OUTBOX_PENDING_KEY: POOL_OUTBOX_PENDING_KEY,
|
|
373
|
+
PROBE_PATH: PROBE_PATH,
|
|
374
|
+
PROBE_TIMEOUT_MS: PROBE_TIMEOUT_MS,
|
|
375
|
+
BANNER_ID: BANNER_ID,
|
|
376
|
+
poolEsc: poolEsc,
|
|
377
|
+
normalizePoolOrigin: normalizePoolOrigin,
|
|
378
|
+
normalizePoolOriginRow: normalizePoolOriginRow,
|
|
379
|
+
readPoolOrigins: readPoolOrigins,
|
|
380
|
+
writePoolOrigins: writePoolOrigins,
|
|
381
|
+
readOutboxPendingMarker: readOutboxPendingMarker,
|
|
382
|
+
writeOutboxPendingMarker: writeOutboxPendingMarker,
|
|
383
|
+
rememberPoolOrigins: rememberPoolOrigins,
|
|
384
|
+
probeOrigin: probeOrigin,
|
|
385
|
+
poolOriginsListHtml: poolOriginsListHtml,
|
|
386
|
+
failoverOnBootFailure: failoverOnBootFailure,
|
|
387
|
+
showPoolFromBanner: showPoolFromBanner,
|
|
388
|
+
};
|
|
389
|
+
if (typeof module === 'object' && module.exports) module.exports = out;
|
|
390
|
+
else root.CtmPoolFailover = out;
|
|
391
|
+
})(typeof window !== 'undefined' ? window : this);
|
|
@@ -167,15 +167,34 @@
|
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
function captureSelectedRows(pane, selected) {
|
|
170
|
-
return selected.map(({ item }, index) =>
|
|
171
|
-
|
|
172
|
-
fingerprint: JSON.stringify(item),
|
|
173
|
-
payload: {
|
|
170
|
+
return selected.map(({ item }, index) => {
|
|
171
|
+
const payload = {
|
|
174
172
|
title: item.title || `Prompt ${index + 1}`,
|
|
175
173
|
text: dependencies.itemText(item),
|
|
176
174
|
images: Array.isArray(item.images) ? item.images : [],
|
|
177
|
-
}
|
|
178
|
-
|
|
175
|
+
};
|
|
176
|
+
// D-7/R-3: posting the pane's own id lets the engine (lib/queue-item.js:32 keeps a
|
|
177
|
+
// supplied id) and every reader match the durable row to this draft row by identity.
|
|
178
|
+
if (typeof item.id === 'string' && item.id) payload.id = item.id;
|
|
179
|
+
return { item, fingerprint: JSON.stringify(item), payload };
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// R-3: a queue-draft echo or a queue-state delivery frame for the open pane reloads the
|
|
184
|
+
// draft through the existing loadDraft path. Skipped (and retried on the next frame) while
|
|
185
|
+
// the user is mid-operation, so a reload can never clobber an in-flight save/send or an
|
|
186
|
+
// open edit. NOTE: the design text says "editingIndex != null", but the phone stores -1
|
|
187
|
+
// (never null) for "no row being edited" (public/m/app.js:10862, :10835), so a literal
|
|
188
|
+
// `!= null` guard would never reload at all. The guard therefore tests the index
|
|
189
|
+
// (`>= 0`), which is the pane's own meaning of "an edit row is open" (app.js:10747).
|
|
190
|
+
async function reloadIfIdle(sessionId) {
|
|
191
|
+
const pane = getState()?.queueBuilder || null;
|
|
192
|
+
if (!pane || pane.open !== true) return false;
|
|
193
|
+
if (String(pane.sessionId || '') !== String(sessionId ?? '')) return false;
|
|
194
|
+
const editing = Number.isInteger(pane.editingIndex) && pane.editingIndex >= 0;
|
|
195
|
+
if (pane.saving || pane.sending || editing) return false;
|
|
196
|
+
await loadDraft(pane.sessionId);
|
|
197
|
+
return true;
|
|
179
198
|
}
|
|
180
199
|
|
|
181
200
|
async function sendQueue(options = {}) {
|
|
@@ -274,7 +293,7 @@
|
|
|
274
293
|
return true;
|
|
275
294
|
}
|
|
276
295
|
|
|
277
|
-
return Object.freeze({ captureOrigin, isOriginCurrent, runMutation, confirmStepUp, saveDraft, loadDraft, sendQueue, retire });
|
|
296
|
+
return Object.freeze({ captureOrigin, isOriginCurrent, runMutation, confirmStepUp, saveDraft, loadDraft, reloadIfIdle, sendQueue, retire });
|
|
278
297
|
}
|
|
279
298
|
|
|
280
299
|
return Object.freeze({ createPrivateQueueActions });
|
|
@@ -23,6 +23,11 @@ const SHELL_ASSETS = [
|
|
|
23
23
|
'/m/principal-access.js?v=__CTM_MOBILE_ASSET__',
|
|
24
24
|
'/m/principal-ui-policy.js?v=__CTM_MOBILE_ASSET__',
|
|
25
25
|
'/m/command-outcome-policy.js?v=__CTM_MOBILE_ASSET__',
|
|
26
|
+
// WP-6 (S-26/P-7): the cached shell must be able to fail over to another pool member with no
|
|
27
|
+
// network, so the failover module and the two machine-pool files ride the precache allowlist.
|
|
28
|
+
'/js/machine-pool-shared.js?v=__CTM_MOBILE_ASSET__',
|
|
29
|
+
'/m/pool-failover.js?v=__CTM_MOBILE_ASSET__',
|
|
30
|
+
'/m/machines.js?v=__CTM_MOBILE_ASSET__',
|
|
26
31
|
'/m/outbox-persistence.js?v=__CTM_MOBILE_ASSET__',
|
|
27
32
|
'/js/private-state-scope.js?v=__CTM_MOBILE_ASSET__',
|
|
28
33
|
'/m/private-state-runtime.js?v=__CTM_MOBILE_ASSET__',
|
|
@@ -489,6 +489,18 @@ function getQueue(sessionId) {
|
|
|
489
489
|
return queues.get(sessionId) || null;
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
+
// Durable per-item status for readers that must not see the WS broadcast
|
|
493
|
+
// shape (queue-draft GET overlay, R-1/R-2/D-6). Returns null when the
|
|
494
|
+
// session has no in-memory queue. getState() is deliberately untouched: its
|
|
495
|
+
// item shape feeds the queue-state broadcast.
|
|
496
|
+
function getItemStatusMap(sessionId) {
|
|
497
|
+
const q = queues.get(sessionId);
|
|
498
|
+
if (!q) return null;
|
|
499
|
+
const map = new Map();
|
|
500
|
+
for (const i of q.items) if (i && i.id) map.set(i.id, { status: i.status, statusUpdatedAt: Number(i.statusUpdatedAt) || 0 });
|
|
501
|
+
return map;
|
|
502
|
+
}
|
|
503
|
+
|
|
492
504
|
function getState(sessionId) {
|
|
493
505
|
const q = queues.get(sessionId);
|
|
494
506
|
if (!q) return null;
|
|
@@ -1233,6 +1245,7 @@ module.exports = {
|
|
|
1233
1245
|
createQueue,
|
|
1234
1246
|
appendItems,
|
|
1235
1247
|
getQueue,
|
|
1248
|
+
getItemStatusMap,
|
|
1236
1249
|
getState,
|
|
1237
1250
|
getPersistedState,
|
|
1238
1251
|
stateFromSavedQueue,
|
|
@@ -979,6 +979,10 @@ function createApprovals(deps) {
|
|
|
979
979
|
policyDecision: `rescue_provider_rejected_${admittedInteraction.reasonCode || 'unknown'}`,
|
|
980
980
|
keystrokeStatus: 'not_sent',
|
|
981
981
|
});
|
|
982
|
+
// Drift alarm: the screen is a live approval the rescuer refused to admit. If NO provider
|
|
983
|
+
// recognizes it, the rejection itself is the drift signal — surface it here, not only on
|
|
984
|
+
// the later choice branch (which the very same rejection makes unreachable).
|
|
985
|
+
if (admittedInteraction.reasonCode === 'provider_unknown') _recordApprovalDrift(sessionId, approvalDrift.driftIfUnrecognized({ text, detectProvider: approvalProviders.detectProvider }));
|
|
982
986
|
return;
|
|
983
987
|
}
|
|
984
988
|
// Fully hands-off on plan approvals (ExitPlanMode). The main path skips these
|
|
@@ -1008,12 +1012,7 @@ function createApprovals(deps) {
|
|
|
1008
1012
|
// passed the isLiveApprovalPrompt gate above). If NO provider recognized it yet
|
|
1009
1013
|
// its options carry approval verbs, a provider that SHOULD have matched didn't —
|
|
1010
1014
|
// i.e. the CLI changed its prompt UI. Record it so the miss is loud, not silent.
|
|
1011
|
-
|
|
1012
|
-
if (!approvalProviders.detectProvider(text)) {
|
|
1013
|
-
const drift = approvalDrift.evaluateDrift({ text, providerMatched: false, waitingForInput: true });
|
|
1014
|
-
if (drift) _recordApprovalDrift(sessionId, drift);
|
|
1015
|
-
}
|
|
1016
|
-
} catch { /* alarm is best-effort */ }
|
|
1015
|
+
_recordApprovalDrift(sessionId, approvalDrift.driftIfUnrecognized({ text, detectProvider: approvalProviders.detectProvider }));
|
|
1017
1016
|
if (!buf._lastRescueChoiceSkipLogAt || Date.now() - buf._lastRescueChoiceSkipLogAt > 30000) {
|
|
1018
1017
|
buf._lastRescueChoiceSkipLogAt = Date.now();
|
|
1019
1018
|
logger.log(`[shadow-approver] Ignoring choice/question menu in rescue path for session ${sessionId.slice(0, 8)} — agent is asking the user, not a missed permission (via ${source})`);
|