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
|
@@ -56,6 +56,16 @@ var _modelsAgentStatusPromise = null;
|
|
|
56
56
|
// 2 s setTimeout while a flow is open — never an interval, and it stops itself as soon
|
|
57
57
|
// as no flow is open, so an idle models page costs nothing.
|
|
58
58
|
var _modelsProviderLogin = null;
|
|
59
|
+
// WP-3 (docs/remote-agent-sign-in-from-hub-browser-2026-10-25.html §5 D-7/D-9): the last
|
|
60
|
+
// login-state payload read for a REMOTE machine (keyed by instance id) — the Machines page's
|
|
61
|
+
// machine-scoped poll keeps its box's truth here, deliberately apart from _modelsProviderLogin so a
|
|
62
|
+
// box's sign-in state can never be painted as this machine's own card.
|
|
63
|
+
var _modelsProviderLoginMachines = {};
|
|
64
|
+
// WP-2 fix: the last payload fingerprint the card was painted from. The 2 s poll
|
|
65
|
+
// re-reads login-state every tick, but the probe only moves `account.checkedAt`
|
|
66
|
+
// between ticks — repainting for that alone rebuilt the whole section (and with it
|
|
67
|
+
// the code box the user was typing into) every 2 s. See _modelsProviderLoginRenderKey.
|
|
68
|
+
var _modelsProviderLoginLastRenderKey = '';
|
|
59
69
|
var _modelsProviderLoginPollTimer = null;
|
|
60
70
|
var _modelsProviderLoginPolling = false;
|
|
61
71
|
var _MODELS_PROVIDER_LOGIN_OPEN_STATUSES = ['starting', 'running', 'awaiting_user'];
|
|
@@ -97,6 +107,10 @@ var _routingSuggestionHistory = [];
|
|
|
97
107
|
var _routingBanditHistory = [];
|
|
98
108
|
var _routingBanditReadiness = null;
|
|
99
109
|
var _routingLaunchState = null;
|
|
110
|
+
// WP-7 (lead-cost routing §6.9): the "Helper rules" pill's read model — the Wall-E cell list and
|
|
111
|
+
// the one-line error the panel shows instead of an alert.
|
|
112
|
+
var _helperRulesCells = null;
|
|
113
|
+
var _helperRulesError = null;
|
|
100
114
|
|
|
101
115
|
// AI Providers → Usage tab: token/cost consumption for the default model, split by
|
|
102
116
|
// process (Wall-E chat vs CTM) and kept separate from the coding-agent model.
|
|
@@ -1857,6 +1871,9 @@ function _ensureModelsAgentStatus(force) {
|
|
|
1857
1871
|
]).then(function(results) {
|
|
1858
1872
|
_modelsAutoUpdate = results[3];
|
|
1859
1873
|
if (results[4] && results[4].providers) _modelsProviderLogin = results[4];
|
|
1874
|
+
// WP-2 fix (A): this fan-out renders the card itself (below), so remember what it
|
|
1875
|
+
// painted — the first poll after a page load must not repaint for nothing.
|
|
1876
|
+
_modelsProviderLoginLastRenderKey = _modelsProviderLoginRenderKey(_modelsProviderLogin);
|
|
1860
1877
|
_modelsCodingAgentMigrateLocalDismissals(results[1]);
|
|
1861
1878
|
_modelsAgentStatus = {
|
|
1862
1879
|
available: results[0] || { agents: {} },
|
|
@@ -1909,18 +1926,34 @@ function _modelsProviderLoginFlowIsOpen(flow) {
|
|
|
1909
1926
|
return !!flow && _MODELS_PROVIDER_LOGIN_OPEN_STATUSES.indexOf(String(flow.status || '')) >= 0;
|
|
1910
1927
|
}
|
|
1911
1928
|
|
|
1912
|
-
// The Account row: signed-in email + plan, "Not signed in", or
|
|
1929
|
+
// The Account row (R-4): signed-in email + plan, "Not signed in", or -- when the
|
|
1930
|
+
// probe could not answer (signedIn === null: non-primary instance, hermetic env,
|
|
1931
|
+
// timeout, CLI missing) -- plain "Unknown". The probe's machine reason
|
|
1932
|
+
// ('probe_unavailable', 'cli_missing', ...) is a diagnostic, never user copy: it
|
|
1933
|
+
// rides in the value's title via _modelsCodingAgentAccountTitle below, exactly
|
|
1934
|
+
// like the status pill's own title.
|
|
1913
1935
|
function _modelsCodingAgentAccountText(preset) {
|
|
1914
1936
|
var entry = _modelsProviderLoginEntry(preset);
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
if (!account) return 'Unknown (no probe)';
|
|
1918
|
-
if (account.signedIn === true) {
|
|
1937
|
+
var account = (entry && entry.account) || null;
|
|
1938
|
+
if (account && account.signedIn === true) {
|
|
1919
1939
|
var who = account.email ? String(account.email) : 'signed in';
|
|
1920
1940
|
return account.plan ? (who + ' · ' + account.plan) : who;
|
|
1921
1941
|
}
|
|
1922
|
-
if (account.signedIn === false) return 'Not signed in';
|
|
1923
|
-
return 'Unknown
|
|
1942
|
+
if (account && account.signedIn === false) return 'Not signed in';
|
|
1943
|
+
return 'Unknown';
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// The diagnostic behind an "Unknown" account: which machine reason kept the probe
|
|
1947
|
+
// from answering, plus the probe's own detail when it has one. Empty when the row
|
|
1948
|
+
// has nothing to explain (a probe that answered, signed in or not).
|
|
1949
|
+
function _modelsCodingAgentAccountTitle(preset) {
|
|
1950
|
+
var entry = _modelsProviderLoginEntry(preset);
|
|
1951
|
+
if (!entry) return 'Login probe: unavailable';
|
|
1952
|
+
var account = entry.account || null;
|
|
1953
|
+
if (!account) return 'Login probe: no probe';
|
|
1954
|
+
if (typeof account.signedIn === 'boolean') return '';
|
|
1955
|
+
var reason = account.reason ? String(account.reason) : 'unknown';
|
|
1956
|
+
return 'Login probe: ' + reason + (account.detail ? ' — ' + String(account.detail) : '');
|
|
1924
1957
|
}
|
|
1925
1958
|
|
|
1926
1959
|
function _modelsCodingAgentAccountColor(preset) {
|
|
@@ -1930,17 +1963,154 @@ function _modelsCodingAgentAccountColor(preset) {
|
|
|
1930
1963
|
return 'var(--fg-dim,#565f89)';
|
|
1931
1964
|
}
|
|
1932
1965
|
|
|
1933
|
-
//
|
|
1934
|
-
//
|
|
1966
|
+
// D-1 on the client (S-10, defence in depth): the CLI also opens an automatic
|
|
1967
|
+
// browser on ITS own machine, so a loopback URL is that machine's link, never one a
|
|
1968
|
+
// remote (hub / phone) viewer of this card can follow. Both halves of the URL are
|
|
1969
|
+
// checked — the link host and, when present, the OAuth redirect_uri it carries.
|
|
1970
|
+
//
|
|
1971
|
+
// true when `value` parses to a loopback host. A value that is not a URL at all is
|
|
1972
|
+
// not loopback: it just cannot promote an href (the caller drops it for its scheme).
|
|
1973
|
+
function _modelsProviderLoginLoopbackHost(value) {
|
|
1974
|
+
var hosts = ['localhost', '127.0.0.1', '::1', '[::1]'];
|
|
1975
|
+
var host = '';
|
|
1976
|
+
try {
|
|
1977
|
+
host = new URL(String(value || '')).hostname;
|
|
1978
|
+
} catch (e) {
|
|
1979
|
+
return false;
|
|
1980
|
+
}
|
|
1981
|
+
return hosts.indexOf(String(host).toLowerCase()) >= 0;
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
// Only a URL the browser parses as https — and whose host, and redirect_uri host,
|
|
1985
|
+
// are not loopback — may become an href. The CLI prints this string; the card must
|
|
1986
|
+
// never turn it into a link of another scheme, nor hand out its own machine's link.
|
|
1935
1987
|
function _modelsProviderLoginUrl(value) {
|
|
1936
1988
|
try {
|
|
1937
1989
|
var parsed = new URL(String(value || ''));
|
|
1938
|
-
|
|
1990
|
+
if (parsed.protocol !== 'https:') return '';
|
|
1991
|
+
if (_modelsProviderLoginLoopbackHost(parsed.href)) return '';
|
|
1992
|
+
var redirect = parsed.searchParams.get('redirect_uri');
|
|
1993
|
+
if (redirect && _modelsProviderLoginLoopbackHost(redirect)) return '';
|
|
1994
|
+
return parsed.href;
|
|
1939
1995
|
} catch (e) {
|
|
1940
1996
|
return '';
|
|
1941
1997
|
}
|
|
1942
1998
|
}
|
|
1943
1999
|
|
|
2000
|
+
function _modelsProviderLoginHintStyle() {
|
|
2001
|
+
return 'font-size:11px;color:var(--fg-dim,#565f89);';
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// §9 S-9: the server's refusal ids are machine copy — the card says what the user
|
|
2005
|
+
// can do about each one. Anything unrecognised still names its id, never a blank.
|
|
2006
|
+
function _modelsProviderLoginErrorText(errorId) {
|
|
2007
|
+
var id = String(errorId === null || errorId === undefined ? '' : errorId);
|
|
2008
|
+
if (id === 'code_format_invalid') return "That doesn't look like a sign-in code. Paste the code, or the page address, from the sign-in page.";
|
|
2009
|
+
if (id === 'code_state_mismatch') return 'That code is from a different sign-in. Use the link above and try again.';
|
|
2010
|
+
if (id === 'code_from_loopback_redirect') return 'That page came from a localhost link. Use the Open sign-in page link above.';
|
|
2011
|
+
if (id === 'login_tab_gone' || id === 'provider_login_not_open') return 'The sign-in tab closed. Start Sign in again.';
|
|
2012
|
+
if (id === 'code_entry_not_supported') return 'This sign-in does not take a code here.';
|
|
2013
|
+
return 'Could not send the code (' + id + ').';
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// D-3/D-7: the way the code travels decides the fragment — never the provider id.
|
|
2017
|
+
// 'browser' (Codex) shows the one-time code the tab printed for the browser,
|
|
2018
|
+
// 'paste' (Claude) takes the code the browser shows back, '' waits for the page.
|
|
2019
|
+
// Same markup and same labels on every host.
|
|
2020
|
+
function _modelsProviderLoginCodeEntryHtml(flow) {
|
|
2021
|
+
var entry = (flow && flow.codeEntry) || '';
|
|
2022
|
+
var hintStyle = _modelsProviderLoginHintStyle();
|
|
2023
|
+
if (entry === 'browser') {
|
|
2024
|
+
return '<code data-sign-in-user-code style="font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;background:var(--bg,#1a1b26);border:1px solid var(--border,#414868);border-radius:4px;padding:2px 6px;color:var(--fg,#c0caf5);">'
|
|
2025
|
+
+ escHtml((flow && flow.userCode) || '') + '</code>'
|
|
2026
|
+
+ '<button type="button" data-sign-in-copy-code style="' + _modelsProviderLoginButtonStyle(false) + '">Copy code</button>'
|
|
2027
|
+
+ '<span data-sign-in-hint style="' + hintStyle + '">Enter this code on the sign-in page.</span>';
|
|
2028
|
+
}
|
|
2029
|
+
if (entry === 'paste') {
|
|
2030
|
+
return '<input data-sign-in-code type="text" inputmode="text" autocomplete="off" spellcheck="false" placeholder="Paste the code from the sign-in page" style="font-size:11px;padding:4px 7px;border-radius:5px;border:1px solid var(--border,#414868);background:var(--bg,#1a1b26);color:var(--fg,#c0caf5);min-width:240px;" />'
|
|
2031
|
+
+ '<button type="button" data-sign-in-code-submit style="' + _modelsProviderLoginButtonStyle(true) + '">Submit code</button>'
|
|
2032
|
+
+ '<span data-sign-in-hint style="' + hintStyle + '">After you sign in, the page shows a code. Paste it here (the page address works too).</span>'
|
|
2033
|
+
+ '<span data-sign-in-error style="font-size:11px;color:#f7768e;"></span>';
|
|
2034
|
+
}
|
|
2035
|
+
return '<span data-sign-in-hint style="' + hintStyle + '">Waiting for the sign-in page…</span>';
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
// WP-3 (docs/remote-agent-sign-in-from-hub-browser-2026-10-25.html §5 D-7/D-9, §6, S-13):
|
|
2039
|
+
// the machine scope. The SAME `&machine=<id>` fragment the picker routes carry
|
|
2040
|
+
// (machineQueryParam(), public/js/core/session-commands.js) — spelled here rather than called,
|
|
2041
|
+
// because machineQueryParam() reads the PICKER's selection and the machine a card is scoped to is
|
|
2042
|
+
// an explicit argument, not that selection. '' produces nothing, so every unscoped URL is
|
|
2043
|
+
// byte-identical to its pre-WP-3 self.
|
|
2044
|
+
//
|
|
2045
|
+
// It is appended to the URL _modelsApiUrl() RETURNS, never to its argument: _modelsApiUrl appends
|
|
2046
|
+
// `?token=`/`&token=` to whatever it is handed, so a fragment spliced into the pathname would end
|
|
2047
|
+
// up before the token and the query would read `…/login&machine=x?token=…` — a route the hub does
|
|
2048
|
+
// not serve. `&machine=` is always well-formed here because _modelsApiUrl always emits a query.
|
|
2049
|
+
function _modelsProviderLoginMachineScope(machineId) {
|
|
2050
|
+
var id = machineId === null || machineId === undefined ? '' : String(machineId).trim();
|
|
2051
|
+
return id ? '&machine=' + encodeURIComponent(id) : '';
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// One POST, one meaning: hand the pasted code to the sign-in tab (§5 D-4). The value
|
|
2055
|
+
// is never logged, toasted or written anywhere but the input itself, and the button
|
|
2056
|
+
// stays disabled until the answer arrives (so a second Enter cannot double-post).
|
|
2057
|
+
// WP-3: `opts.machineId` (S-13) targets the box that owns the flow — the hub forwards to it.
|
|
2058
|
+
function _modelsProviderLoginSubmitCode(providerId, inputEl, errorEl, btn, opts) {
|
|
2059
|
+
var options = opts || {};
|
|
2060
|
+
if (!providerId || !inputEl) return Promise.resolve();
|
|
2061
|
+
var submitBtn = btn || null;
|
|
2062
|
+
var errorSpan = errorEl || null;
|
|
2063
|
+
if (submitBtn && submitBtn.disabled) return Promise.resolve();
|
|
2064
|
+
if (submitBtn) submitBtn.disabled = true;
|
|
2065
|
+
if (errorSpan) errorSpan.textContent = '';
|
|
2066
|
+
var refuse = function(errorId) {
|
|
2067
|
+
if (errorSpan) errorSpan.textContent = _modelsProviderLoginErrorText(errorId);
|
|
2068
|
+
if (submitBtn) submitBtn.disabled = false;
|
|
2069
|
+
};
|
|
2070
|
+
return fetch(_modelsApiUrl('/api/providers/' + encodeURIComponent(providerId) + '/login/code')
|
|
2071
|
+
+ _modelsProviderLoginMachineScope(options.machineId), {
|
|
2072
|
+
method: 'POST',
|
|
2073
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2074
|
+
body: JSON.stringify({ code: String(inputEl.value || '') }),
|
|
2075
|
+
})
|
|
2076
|
+
.then(
|
|
2077
|
+
function(r) {
|
|
2078
|
+
return r.json().then(
|
|
2079
|
+
function(data) { return { ok: r.ok, data: data }; },
|
|
2080
|
+
function() { return { ok: r.ok, data: null }; },
|
|
2081
|
+
);
|
|
2082
|
+
},
|
|
2083
|
+
function() { return null; },
|
|
2084
|
+
)
|
|
2085
|
+
.then(function(result) {
|
|
2086
|
+
if (!result) {
|
|
2087
|
+
refuse('network_error');
|
|
2088
|
+
return null;
|
|
2089
|
+
}
|
|
2090
|
+
if (result.ok) {
|
|
2091
|
+
if (typeof toast === 'function') toast('Code sent to the sign-in tab');
|
|
2092
|
+
inputEl.value = '';
|
|
2093
|
+
return _modelsProviderLoginRefresh(options);
|
|
2094
|
+
}
|
|
2095
|
+
refuse((result.data && result.data.error) || 'unknown_error');
|
|
2096
|
+
return null;
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
// The clipboard is the browser's, and its refusal is a label, never an exception
|
|
2101
|
+
// escaping to the console. No timer: the label holds until the next render.
|
|
2102
|
+
function _modelsProviderLoginCopyCode(code, btn) {
|
|
2103
|
+
var label = function(text) { if (btn) btn.textContent = text; };
|
|
2104
|
+
try {
|
|
2105
|
+
navigator.clipboard.writeText(String(code || '')).then(
|
|
2106
|
+
function() { label('Copied'); },
|
|
2107
|
+
function() { label('Copy failed'); },
|
|
2108
|
+
);
|
|
2109
|
+
} catch (e) {
|
|
2110
|
+
label('Copy failed');
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
|
|
1944
2114
|
function _modelsProviderLoginButtonStyle(primary) {
|
|
1945
2115
|
return primary
|
|
1946
2116
|
? 'padding:5px 10px;border-radius:5px;border:1px solid rgba(224,175,104,0.55);background:rgba(224,175,104,0.12);color:#e0af68;cursor:pointer;font-size:11px;font-weight:700;'
|
|
@@ -1948,9 +2118,17 @@ function _modelsProviderLoginButtonStyle(primary) {
|
|
|
1948
2118
|
}
|
|
1949
2119
|
|
|
1950
2120
|
// The card's sign-in action area. Same markup and same labels on every host (R-4).
|
|
1951
|
-
|
|
2121
|
+
//
|
|
2122
|
+
// WP-3 (S-13): `flowOverride` (undefined = read the card's own payload) and `opts.machineId` let a
|
|
2123
|
+
// DIFFERENT surface — the Machines page — render this same block for a REMOTE machine. With a
|
|
2124
|
+
// machineId the block is machine-scoped: the tab button is never offered (D-9: the sign-in tab
|
|
2125
|
+
// lives on the box, there is no local session to activate), and the caller fills the block for its
|
|
2126
|
+
// own row. Called with no flow and no opts (the card's own call site) the output is unchanged.
|
|
2127
|
+
function _modelsProviderLoginActionsHtml(preset, flowOverride, opts) {
|
|
2128
|
+
var options = opts || {};
|
|
2129
|
+
var machineId = options.machineId === null || options.machineId === undefined ? '' : String(options.machineId).trim();
|
|
1952
2130
|
if (!_modelsProviderIdForPreset(preset)) return '';
|
|
1953
|
-
var flow = _modelsProviderLoginFlowFor(preset);
|
|
2131
|
+
var flow = flowOverride === undefined ? _modelsProviderLoginFlowFor(preset) : flowOverride;
|
|
1954
2132
|
var status = _modelsCodingAgentStatusFor(preset, _modelsCodingAgentAccountFor(preset));
|
|
1955
2133
|
if (_modelsProviderLoginFlowIsOpen(flow)) {
|
|
1956
2134
|
var parts = [];
|
|
@@ -1958,12 +2136,15 @@ function _modelsProviderLoginActionsHtml(preset) {
|
|
|
1958
2136
|
if (url) {
|
|
1959
2137
|
parts.push('<a data-open-sign-in-page href="' + escHtml(url) + '" target="_blank" rel="noopener" style="' + _modelsProviderLoginButtonStyle(true) + 'text-decoration:none;display:inline-block;">Open sign-in page</a>');
|
|
1960
2138
|
}
|
|
1961
|
-
parts.push(
|
|
1962
|
-
if (flow.sessionId) {
|
|
2139
|
+
parts.push(_modelsProviderLoginCodeEntryHtml(flow));
|
|
2140
|
+
if (flow.sessionId && !machineId) {
|
|
1963
2141
|
parts.push('<button type="button" data-show-sign-in-tab="' + escHtml(flow.sessionId) + '" style="' + _modelsProviderLoginButtonStyle(false) + '">Show sign-in tab</button>');
|
|
1964
2142
|
}
|
|
1965
2143
|
return parts.join('');
|
|
1966
2144
|
}
|
|
2145
|
+
// A machine-scoped block with no open flow renders nothing: the Machines page owns that row's
|
|
2146
|
+
// own Sign in button (data-machine-sign-in), so a second one here would double the affordance.
|
|
2147
|
+
if (machineId) return '';
|
|
1967
2148
|
var failed = !!(flow && flow.status === 'failed');
|
|
1968
2149
|
var html = '';
|
|
1969
2150
|
if (failed) {
|
|
@@ -1978,8 +2159,11 @@ function _modelsProviderLoginActionsHtml(preset) {
|
|
|
1978
2159
|
return html;
|
|
1979
2160
|
}
|
|
1980
2161
|
|
|
1981
|
-
|
|
1982
|
-
|
|
2162
|
+
// `login` defaults to the card's own payload, so the card's call sites are unchanged; a
|
|
2163
|
+
// machine-scoped poll passes the payload it just fetched for that box.
|
|
2164
|
+
function _modelsProviderLoginHasOpenFlow(login) {
|
|
2165
|
+
var source = login === undefined ? _modelsProviderLogin : login;
|
|
2166
|
+
var providers = (source && source.providers) || {};
|
|
1983
2167
|
return Object.keys(providers).some(function(id) {
|
|
1984
2168
|
return _modelsProviderLoginFlowIsOpen(providers[id] && providers[id].flow);
|
|
1985
2169
|
});
|
|
@@ -1993,30 +2177,78 @@ function _modelsProviderLoginStopPoll() {
|
|
|
1993
2177
|
_modelsProviderLoginPolling = false;
|
|
1994
2178
|
}
|
|
1995
2179
|
|
|
2180
|
+
// WP-2 fix (A): what a login-state payload contributes to the card — per provider
|
|
2181
|
+
// (sorted, so key order never matters): `status`, `credential`, every field of `flow`
|
|
2182
|
+
// and every field of `account` EXCEPT `checkedAt`, which is the probe's own timestamp
|
|
2183
|
+
// and is not rendered anywhere. Two payloads with the same key paint the same card.
|
|
2184
|
+
function _modelsProviderLoginRenderKey(login) {
|
|
2185
|
+
var stable = function stableJson(value) {
|
|
2186
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value === undefined ? null : value);
|
|
2187
|
+
if (Array.isArray(value)) return '[' + value.map(stableJson).join(',') + ']';
|
|
2188
|
+
return '{' + Object.keys(value).sort().map(function(k) {
|
|
2189
|
+
return JSON.stringify(k) + ':' + stableJson(value[k]);
|
|
2190
|
+
}).join(',') + '}';
|
|
2191
|
+
};
|
|
2192
|
+
var providers = (login && login.providers) || {};
|
|
2193
|
+
return Object.keys(providers).sort().map(function(id) {
|
|
2194
|
+
var entry = providers[id] || {};
|
|
2195
|
+
var account = entry.account;
|
|
2196
|
+
if (account && typeof account === 'object' && !Array.isArray(account)) {
|
|
2197
|
+
account = Object.keys(account).reduce(function(kept, k) {
|
|
2198
|
+
if (k !== 'checkedAt') kept[k] = account[k];
|
|
2199
|
+
return kept;
|
|
2200
|
+
}, {});
|
|
2201
|
+
}
|
|
2202
|
+
return stable([id, entry.status, entry.credential, entry.flow, account]);
|
|
2203
|
+
}).join('\n');
|
|
2204
|
+
}
|
|
2205
|
+
|
|
1996
2206
|
// Re-reads login-state and re-renders. Never rejects: a failed poll keeps the last
|
|
1997
|
-
// payload, so an open flow stays visible while the next poll retries.
|
|
1998
|
-
|
|
1999
|
-
|
|
2207
|
+
// payload, so an open flow stays visible while the next poll retries. The repaint
|
|
2208
|
+
// happens only when the payload's fingerprint moved (WP-2 fix A): a tick that only
|
|
2209
|
+
// re-stamped `account.checkedAt` leaves the card — and any sign-in draft in it — alone.
|
|
2210
|
+
// WP-3 (S-13): `opts.machineId` reads the BOX's login-state through the hub's proxy. The payload
|
|
2211
|
+
// is kept per machine and never painted as this machine's own card (that is what
|
|
2212
|
+
// `opts.onPayload` is for: the Machines page repaints ITS row), so the two readers cannot
|
|
2213
|
+
// contaminate each other.
|
|
2214
|
+
function _modelsProviderLoginRefresh(opts) {
|
|
2215
|
+
var options = opts || {};
|
|
2216
|
+
var machineId = options.machineId === null || options.machineId === undefined ? '' : String(options.machineId).trim();
|
|
2217
|
+
return fetch(_modelsApiUrl('/api/providers/login-state') + _modelsProviderLoginMachineScope(options.machineId), { cache: 'no-store' })
|
|
2000
2218
|
.then(function(r) { return r.ok ? r.json() : null; })
|
|
2001
2219
|
.then(function(data) {
|
|
2220
|
+
if (machineId) {
|
|
2221
|
+
if (data && data.providers) _modelsProviderLoginMachines[machineId] = data;
|
|
2222
|
+
if (typeof options.onPayload === 'function') options.onPayload(_modelsProviderLoginMachines[machineId] || null);
|
|
2223
|
+
return _modelsProviderLoginMachines[machineId] || null;
|
|
2224
|
+
}
|
|
2002
2225
|
if (data && data.providers) _modelsProviderLogin = data;
|
|
2003
|
-
|
|
2226
|
+
var key = _modelsProviderLoginRenderKey(_modelsProviderLogin);
|
|
2227
|
+
if (key !== _modelsProviderLoginLastRenderKey) {
|
|
2228
|
+
_modelsProviderLoginLastRenderKey = key;
|
|
2229
|
+
_modelsRefreshAgentStatusUi();
|
|
2230
|
+
}
|
|
2004
2231
|
return _modelsProviderLogin;
|
|
2005
2232
|
})
|
|
2006
2233
|
.catch(function() {
|
|
2007
|
-
return _modelsProviderLogin;
|
|
2234
|
+
return machineId ? (_modelsProviderLoginMachines[machineId] || null) : _modelsProviderLogin;
|
|
2008
2235
|
});
|
|
2009
2236
|
}
|
|
2010
2237
|
|
|
2011
|
-
|
|
2238
|
+
// The ONE 2 s poll. `opts.machineId` scopes it to a box (WP-3): same timer, same stop condition —
|
|
2239
|
+
// a machine-scoped poll stops as soon as THAT box reports no open flow.
|
|
2240
|
+
function _modelsProviderLoginPoll(opts) {
|
|
2241
|
+
var options = opts || {};
|
|
2242
|
+
var machineId = options.machineId === null || options.machineId === undefined ? '' : String(options.machineId).trim();
|
|
2012
2243
|
if (_modelsProviderLoginPollTimer) return;
|
|
2013
2244
|
_modelsProviderLoginPolling = true;
|
|
2014
2245
|
_modelsProviderLoginPollTimer = setTimeout(function() {
|
|
2015
2246
|
_modelsProviderLoginPollTimer = null;
|
|
2016
|
-
_modelsProviderLoginRefresh().then(function() {
|
|
2247
|
+
_modelsProviderLoginRefresh(options).then(function() {
|
|
2017
2248
|
if (!_modelsProviderLoginPolling) return;
|
|
2018
|
-
|
|
2019
|
-
|
|
2249
|
+
var source = machineId ? _modelsProviderLoginMachines[machineId] : _modelsProviderLogin;
|
|
2250
|
+
if (!_modelsProviderLoginHasOpenFlow(source)) { _modelsProviderLoginPolling = false; return; }
|
|
2251
|
+
_modelsProviderLoginPoll(options);
|
|
2020
2252
|
});
|
|
2021
2253
|
}, _MODELS_PROVIDER_LOGIN_POLL_MS);
|
|
2022
2254
|
}
|
|
@@ -2028,11 +2260,14 @@ function _modelsProviderLoginEnsurePoll() {
|
|
|
2028
2260
|
}
|
|
2029
2261
|
|
|
2030
2262
|
// POST opens the login tab; the flow then arrives through the login-state poll.
|
|
2031
|
-
|
|
2263
|
+
// WP-3: `opts.machineId` opens the tab on THAT box through the hub's proxy.
|
|
2264
|
+
function _modelsProviderLoginStart(preset, btn, opts) {
|
|
2265
|
+
var options = opts || {};
|
|
2032
2266
|
var providerId = _modelsProviderIdForPreset(preset);
|
|
2033
2267
|
if (!providerId) return Promise.resolve(null);
|
|
2034
2268
|
if (btn) { btn.disabled = true; btn.textContent = 'Opening...'; }
|
|
2035
|
-
return fetch(_modelsApiUrl('/api/providers/' + encodeURIComponent(providerId) + '/login')
|
|
2269
|
+
return fetch(_modelsApiUrl('/api/providers/' + encodeURIComponent(providerId) + '/login')
|
|
2270
|
+
+ _modelsProviderLoginMachineScope(options.machineId), {
|
|
2036
2271
|
method: 'POST',
|
|
2037
2272
|
headers: { 'Content-Type': 'application/json' },
|
|
2038
2273
|
body: '{}',
|
|
@@ -2046,8 +2281,8 @@ function _modelsProviderLoginStart(preset, btn) {
|
|
|
2046
2281
|
if (typeof toast === 'function') toast('Could not start sign-in: ' + reason, { type: 'error', duration: 5000 });
|
|
2047
2282
|
}
|
|
2048
2283
|
_modelsProviderLoginPolling = true;
|
|
2049
|
-
return _modelsProviderLoginRefresh().then(function() {
|
|
2050
|
-
if (_modelsProviderLoginHasOpenFlow()) _modelsProviderLoginPoll();
|
|
2284
|
+
return _modelsProviderLoginRefresh(options).then(function() {
|
|
2285
|
+
if (_modelsProviderLoginHasOpenFlow(options.machineId ? _modelsProviderLoginMachines[String(options.machineId).trim()] : undefined)) _modelsProviderLoginPoll(options);
|
|
2051
2286
|
else _modelsProviderLoginPolling = false;
|
|
2052
2287
|
return result;
|
|
2053
2288
|
});
|
|
@@ -2903,7 +3138,7 @@ function _routingConfirm(title, detail, acceptLabel) {
|
|
|
2903
3138
|
|
|
2904
3139
|
function _routingWorkflowPills() {
|
|
2905
3140
|
return '<div role="tablist" aria-label="Routing views" style="display:flex;gap:4px;margin-bottom:14px;overflow-x:auto;">' +
|
|
2906
|
-
[['workflows','Workflows'],['policies','Policies'],['measurements','Measurements']].map(function(item) {
|
|
3141
|
+
[['workflows','Workflows'],['policies','Policies'],['measurements','Measurements'],['helper-rules','Helper rules']].map(function(item) {
|
|
2907
3142
|
var active = _routingWorkflowPill === item[0];
|
|
2908
3143
|
return '<button type="button" data-routing-pill="' + item[0] + '" style="padding:7px 12px;border-radius:6px;border:1px solid ' + (active ? 'var(--accent,#7aa2f7)' : 'var(--border,#414868)') + ';background:' + (active ? 'rgba(122,162,247,.16)' : 'transparent') + ';color:' + (active ? '#7aa2f7' : 'var(--fg-dim,#565f89)') + ';font-weight:700;cursor:pointer;white-space:nowrap;">' + item[1] + '</button>';
|
|
2909
3144
|
}).join('') + '</div>';
|
|
@@ -3158,15 +3393,200 @@ function _routingMeasurementsMarkup() {
|
|
|
3158
3393
|
'<div style="margin-top:14px;"><strong style="font-size:12px;">Suggestions</strong>' + (suggestions || '<div style="font-size:11px;color:var(--fg-dim,#565f89);margin-top:5px;">Suggestions appear after two arms each have at least 30 measured runs.</div>') + (audit?'<div style="margin-top:8px;">'+audit+'</div>':'') + '</div>' + banditPanel;
|
|
3159
3394
|
}
|
|
3160
3395
|
|
|
3396
|
+
// WP-7 (design §6.9): the "Helper rules" panel — one row per rule cell as Wall-E reports it.
|
|
3397
|
+
// The rule evaluator (Wall-E, lib/helper-rules/store.js) owns every write; this panel only reads
|
|
3398
|
+
// and asks: Veto / Enable go through _routingConfirm and then straight to the API (D-18).
|
|
3399
|
+
var HELPER_RULE_STATE_COLOR = { on: '#9ece6a', probe: '#e0af68', off: '#f7768e' };
|
|
3400
|
+
// WP-6 (§6.9): the panel's outcome disclosure, keyed by cell. An entry exists only while the row is
|
|
3401
|
+
// open: { rows: array|null (null = in flight), error: string|null }. Session-only, never persisted.
|
|
3402
|
+
var _helperRulesOutcomes = {};
|
|
3403
|
+
|
|
3404
|
+
function _helperRulesPct(value) {
|
|
3405
|
+
var n = Number(value);
|
|
3406
|
+
return (value == null || !isFinite(n)) ? '-' : (n * 100).toFixed(1) + '%';
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
// WP-6 (design §6.9, D-7): the rate column reports the measurability the evaluator stores
|
|
3410
|
+
// (`collecting` = "not enough measured rows to judge") instead of always showing a percentage, and
|
|
3411
|
+
// names the rows that measure nothing so a fallback rate is never read off an all-unmeasured window.
|
|
3412
|
+
function _helperRulesCount(metrics, key) {
|
|
3413
|
+
return Math.max(0, Number(metrics[key] || 0) || 0);
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
function _helperRulesRate(cell) {
|
|
3417
|
+
var metrics = cell.metrics || {};
|
|
3418
|
+
if (cell.collecting) {
|
|
3419
|
+
var collecting = ['collecting'];
|
|
3420
|
+
if (cell.kind === 'explore' && _helperRulesCount(metrics, 'unmeasured') > 0) collecting.push('unmeasured ' + _helperRulesCount(metrics, 'unmeasured'));
|
|
3421
|
+
return collecting.join(' · ');
|
|
3422
|
+
}
|
|
3423
|
+
if (cell.kind === 'explore') {
|
|
3424
|
+
var parts = ['fallback ' + _helperRulesPct(metrics.fallback_rate)];
|
|
3425
|
+
if (_helperRulesCount(metrics, 'unmeasured') > 0) parts.push('unmeasured ' + _helperRulesCount(metrics, 'unmeasured'));
|
|
3426
|
+
if (_helperRulesCount(metrics, 'abandoned') > 0) parts.push('abandoned ' + _helperRulesCount(metrics, 'abandoned'));
|
|
3427
|
+
if (Number(metrics.graded || 0) >= 1) parts.push('sufficient ' + _helperRulesPct(metrics.sufficient_rate));
|
|
3428
|
+
if (_helperRulesCount(metrics, 'grade_unavailable') > 0) parts.push('grade unavailable ' + _helperRulesCount(metrics, 'grade_unavailable'));
|
|
3429
|
+
return parts.join(' · ');
|
|
3430
|
+
}
|
|
3431
|
+
var watch = [_helperRulesPct(metrics.precision)];
|
|
3432
|
+
if (typeof metrics.watcher_usd_window === 'number' && isFinite(metrics.watcher_usd_window)) {
|
|
3433
|
+
watch.push('$' + metrics.watcher_usd_window.toFixed(4) + ' watched');
|
|
3434
|
+
}
|
|
3435
|
+
return watch.join(' · ');
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3438
|
+
function _helperRulesStateChip(cell) {
|
|
3439
|
+
var state = HELPER_RULE_STATE_COLOR[cell.state] ? cell.state : 'on';
|
|
3440
|
+
return '<span style="color:' + HELPER_RULE_STATE_COLOR[state] + ';font-weight:700;white-space:nowrap;">' + escHtml(state) + (cell.user_veto ? ' · vetoed' : '') + '</span>';
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
function _helperRulesLastEvent(cell) {
|
|
3444
|
+
var event = cell.last_event;
|
|
3445
|
+
if (!event) return '<span style="color:var(--fg-dim,#565f89);">-</span>';
|
|
3446
|
+
return escHtml([event.to_state, event.reason, event.created_at].filter(function(part) { return part != null && part !== ''; }).join(' · '));
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
function _helperRulesActions(cell) {
|
|
3450
|
+
var key = escHtml(cell.cell_key);
|
|
3451
|
+
var html = '';
|
|
3452
|
+
if (cell.state !== 'off' || Number(cell.user_veto) === 0) {
|
|
3453
|
+
html += '<button type="button" class="btn small" data-helper-cell="' + key + '" data-helper-action="veto">Veto</button>';
|
|
3454
|
+
}
|
|
3455
|
+
if (Number(cell.user_veto) === 1 || cell.state === 'off') {
|
|
3456
|
+
html += (html ? ' ' : '') + '<button type="button" class="btn small" data-helper-cell="' + key + '" data-helper-action="enable">Enable</button>';
|
|
3457
|
+
}
|
|
3458
|
+
html += (html ? ' ' : '') + '<button type="button" class="btn small" data-helper-outcomes="' + key + '">Outcomes</button>';
|
|
3459
|
+
return html;
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
// --- WP-6 (§6.9): the per-cell outcome disclosure -------------------------------------------
|
|
3463
|
+
// Every value is escaped; a missing field renders '-'. The five facts are the API's allow-list
|
|
3464
|
+
// (terminal_status, report_source, report_citation_rows, wait_variant, harness) -- no paths, no
|
|
3465
|
+
// brief/report text, never the raw row.
|
|
3466
|
+
function _helperRulesText(value) {
|
|
3467
|
+
return (value == null || value === '') ? '-' : String(value);
|
|
3468
|
+
}
|
|
3469
|
+
|
|
3470
|
+
function _helperRulesOutcomeRows(cellKey) {
|
|
3471
|
+
var state = _helperRulesOutcomes[cellKey];
|
|
3472
|
+
if (!state) return '';
|
|
3473
|
+
var empty = function(message, color) {
|
|
3474
|
+
return '<tr><td colspan="9" style="color:' + (color || 'var(--fg-dim,#565f89)') + ';">' + escHtml(message) + '</td></tr>';
|
|
3475
|
+
};
|
|
3476
|
+
if (state.error) return empty(state.error, '#f7768e');
|
|
3477
|
+
if (!state.rows) return empty('Loading outcomes...');
|
|
3478
|
+
if (!state.rows.length) return empty('No outcomes in this window.');
|
|
3479
|
+
return state.rows.map(function(row) {
|
|
3480
|
+
var facts = row.facts || {};
|
|
3481
|
+
var decision = [row.decision, row.label].filter(function(part) { return part != null && part !== ''; }).join(' / ');
|
|
3482
|
+
return '<tr>' +
|
|
3483
|
+
'<td>' + escHtml(_helperRulesText(row.seq)) + '</td>' +
|
|
3484
|
+
'<td>' + escHtml(decision || '-') + '</td>' +
|
|
3485
|
+
'<td>' + escHtml(_helperRulesText(row.report_rows)) + '</td>' +
|
|
3486
|
+
'<td>' + escHtml(_helperRulesText(facts.terminal_status)) + '</td>' +
|
|
3487
|
+
'<td>' + escHtml(_helperRulesText(facts.report_source)) + '</td>' +
|
|
3488
|
+
'<td>' + escHtml(_helperRulesText(facts.wait_variant)) + '</td>' +
|
|
3489
|
+
'<td>' + escHtml(_helperRulesText(facts.harness)) + '</td>' +
|
|
3490
|
+
'<td>' + escHtml('v' + _helperRulesText(row.label_version)) + '</td>' +
|
|
3491
|
+
'<td>' + escHtml(_helperRulesText(row.created_at)) + '</td>' +
|
|
3492
|
+
'</tr>';
|
|
3493
|
+
}).join('');
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3496
|
+
/** The extra `<tr>` under an opened cell: the cell's trailing outcome window as a nested table. */
|
|
3497
|
+
function _helperRulesOutcomesRow(cellKey) {
|
|
3498
|
+
if (!_helperRulesOutcomes[cellKey]) return '';
|
|
3499
|
+
return '<tr><td colspan="7" style="background:rgba(122,162,247,.06);">' +
|
|
3500
|
+
'<table style="width:100%;border-collapse:collapse;font-size:10px;"><thead><tr>' +
|
|
3501
|
+
'<th style="text-align:left;">Seq</th><th style="text-align:left;">Decision / label</th><th style="text-align:left;">Report rows</th>' +
|
|
3502
|
+
'<th style="text-align:left;">Terminal</th><th style="text-align:left;">Source</th><th style="text-align:left;">Wait</th>' +
|
|
3503
|
+
'<th style="text-align:left;">Harness</th><th style="text-align:left;">Version</th><th style="text-align:left;">Created</th>' +
|
|
3504
|
+
'</tr></thead><tbody>' + _helperRulesOutcomeRows(cellKey) + '</tbody></table></td></tr>';
|
|
3505
|
+
}
|
|
3506
|
+
|
|
3507
|
+
/** Open/close one cell's disclosure, fetching its window once per open. */
|
|
3508
|
+
function _helperRulesToggleOutcomes(cellKey) {
|
|
3509
|
+
if (_helperRulesOutcomes[cellKey]) {
|
|
3510
|
+
delete _helperRulesOutcomes[cellKey];
|
|
3511
|
+
_renderRoutingWorkflows();
|
|
3512
|
+
return null;
|
|
3513
|
+
}
|
|
3514
|
+
_helperRulesOutcomes[cellKey] = { rows: null, error: null };
|
|
3515
|
+
_renderRoutingWorkflows();
|
|
3516
|
+
return fetch('/api/wall-e/helper-rules/cells/' + encodeURIComponent(cellKey) + '/outcomes?limit=20')
|
|
3517
|
+
.then(function(res) { return res.json(); })
|
|
3518
|
+
.then(function(data) {
|
|
3519
|
+
_helperRulesOutcomes[cellKey] = { rows: (data && data.outcomes) || [], error: null };
|
|
3520
|
+
_renderRoutingWorkflows();
|
|
3521
|
+
})
|
|
3522
|
+
.catch(function(err) {
|
|
3523
|
+
_helperRulesOutcomes[cellKey] = { rows: [], error: (err && err.message) || 'Failed to load outcomes' };
|
|
3524
|
+
_renderRoutingWorkflows();
|
|
3525
|
+
});
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
function _routingHelperRulesMarkup() {
|
|
3529
|
+
if (!_helperRulesCells) {
|
|
3530
|
+
return '<div style="font-size:11px;color:var(--fg-dim,#565f89);">' + escHtml(_helperRulesError || 'Loading helper rules...') + '</div>';
|
|
3531
|
+
}
|
|
3532
|
+
var rows = _helperRulesCells.map(function(cell) {
|
|
3533
|
+
return '<tr data-helper-cell="' + escHtml(cell.cell_key) + '"' + (cell.collecting ? ' style="opacity:.58;"' : '') + '>' +
|
|
3534
|
+
'<td style="overflow-wrap:anywhere;">' + escHtml(cell.cell_key) + '</td>' +
|
|
3535
|
+
'<td>' + escHtml(cell.kind || '-') + '</td>' +
|
|
3536
|
+
'<td>' + _helperRulesStateChip(cell) + '</td>' +
|
|
3537
|
+
'<td>' + Number(cell.n_window || 0) + '</td>' +
|
|
3538
|
+
'<td>' + escHtml(_helperRulesRate(cell)) + '</td>' +
|
|
3539
|
+
'<td>' + _helperRulesLastEvent(cell) + '</td>' +
|
|
3540
|
+
'<td>' + _helperRulesActions(cell) + '</td></tr>' +
|
|
3541
|
+
_helperRulesOutcomesRow(cell.cell_key);
|
|
3542
|
+
}).join('');
|
|
3543
|
+
return '<div style="font-size:11px;color:var(--fg-dim,#565f89);margin-bottom:9px;">The two routing rule cells: the wait-watch wake and the exploration hand-off. A veto is final until you enable the cell again.</div>' +
|
|
3544
|
+
'<div style="overflow-x:auto;"><table style="width:100%;border-collapse:collapse;font-size:11px;"><thead><tr><th>Cell</th><th>Kind</th><th>State</th><th>n</th><th>Precision / fallback</th><th>Last event</th><th>Action</th></tr></thead><tbody>' +
|
|
3545
|
+
(rows || '<tr><td colspan="7">No rule cells yet.</td></tr>') + '</tbody></table></div>' +
|
|
3546
|
+
(_helperRulesError ? '<div style="font-size:10px;color:#f7768e;margin-top:7px;">' + escHtml(_helperRulesError) + '</div>' : '');
|
|
3547
|
+
}
|
|
3548
|
+
|
|
3549
|
+
function _loadHelperRules() {
|
|
3550
|
+
_helperRulesError = null;
|
|
3551
|
+
return fetch('/api/wall-e/helper-rules/cells').then(function(res) { return res.json(); }).then(function(data) {
|
|
3552
|
+
_helperRulesCells = (data && data.cells) || [];
|
|
3553
|
+
_renderRoutingWorkflows();
|
|
3554
|
+
}).catch(function(err) {
|
|
3555
|
+
_helperRulesCells = null;
|
|
3556
|
+
_helperRulesError = (err && err.message) || 'Failed to load helper rules';
|
|
3557
|
+
_renderRoutingWorkflows();
|
|
3558
|
+
});
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
function _helperRulesSetState(cellKey, action) {
|
|
3562
|
+
var label = action === 'veto' ? 'Veto' : 'Enable';
|
|
3563
|
+
return _routingConfirm(label + ' helper rule', label + ' ' + cellKey + '?', label).then(function(ok) {
|
|
3564
|
+
if (!ok) { _renderRoutingWorkflows(); return null; } // re-enable the button the click disabled
|
|
3565
|
+
return fetch('/api/wall-e/helper-rules/cells/' + encodeURIComponent(cellKey) + '/' + action, { method: 'POST' })
|
|
3566
|
+
.then(function(res) { return res.json(); })
|
|
3567
|
+
.then(function(data) {
|
|
3568
|
+
if (!data || data.ok === false) throw new Error((data && data.error) || 'request failed');
|
|
3569
|
+
return _loadHelperRules();
|
|
3570
|
+
})
|
|
3571
|
+
.catch(function(err) {
|
|
3572
|
+
_helperRulesError = cellKey + ': ' + ((err && err.message) || 'request failed');
|
|
3573
|
+
_renderRoutingWorkflows();
|
|
3574
|
+
});
|
|
3575
|
+
});
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3161
3578
|
function _renderRoutingWorkflows() {
|
|
3162
3579
|
var el = document.getElementById('models-routing-workflows'); if (!el) return;
|
|
3163
3580
|
var body = _routingWorkflowPill === 'measurements' ? _routingMeasurementsMarkup()
|
|
3164
|
-
: (
|
|
3165
|
-
|
|
3581
|
+
: (_routingWorkflowPill === 'helper-rules' ? _routingHelperRulesMarkup()
|
|
3582
|
+
: (_routingWorkflowView === 'editor' ? _routingWorkflowEditorMarkup(_routingWorkflowSelected()) : _routingWorkflowLibraryMarkup()));
|
|
3583
|
+
el.innerHTML = DOMPurify.sanitize('<section>' + _routingWorkflowPills() + body + '</section>', { ADD_TAGS: ['article','fieldset','legend'], ADD_ATTR: ['style','data-routing-pill','data-routing-new','data-routing-import','data-routing-edit','data-routing-duplicate','data-routing-export','data-routing-dryrun','data-routing-run','data-routing-back','data-routing-save','data-routing-editor-test','data-node-field','data-node-remove','data-node-add','data-routing-default-policy','data-routing-measure-workflow','data-routing-load-measure','data-routing-refresh-suggestions','data-suggestion-action','data-suggestion-id','data-run-rating','data-run-control','data-run-id','data-run-node','data-run-attempt','data-run-type','data-run-choice','data-policy-fields','data-policy-arm','data-policy-index','data-arm-field','data-arm-saved','data-policy-sample','data-policy-auto','data-policy-cost-lambda','data-policy-latency-budget','data-policy-exploration-budget','data-routing-launch-mode','data-routing-bandit-preview','data-routing-bandit-apply','data-bandit-readiness','data-routing-bandit-readiness-save','data-helper-cell','data-helper-action','data-helper-outcomes','aria-label','role','rows','placeholder','value','selected','disabled','checked','min','max','step','type','title'] });
|
|
3166
3584
|
_routingBindArmModelFilters(el);
|
|
3167
3585
|
var launchAutoOption = el.querySelector('[data-routing-launch-mode] option[value="auto"]');
|
|
3168
3586
|
if (launchAutoOption) launchAutoOption.disabled = !(_routingLaunchState && (_routingLaunchState.ready || _routingLaunchState.mode === 'auto'));
|
|
3169
|
-
el.querySelectorAll('[data-routing-pill]').forEach(function(btn) { btn.onclick = function() { _routingWorkflowPill = btn.dataset.routingPill; if (_routingWorkflowPill === 'policies') { var routes = document.getElementById('models-task-routes'); if (routes) routes.scrollIntoView({ block: 'start' }); } _renderRoutingWorkflows(); }; });
|
|
3587
|
+
el.querySelectorAll('[data-routing-pill]').forEach(function(btn) { btn.onclick = function() { _routingWorkflowPill = btn.dataset.routingPill; if (_routingWorkflowPill === 'policies') { var routes = document.getElementById('models-task-routes'); if (routes) routes.scrollIntoView({ block: 'start' }); } _renderRoutingWorkflows(); if (_routingWorkflowPill === 'helper-rules' && !_helperRulesCells) _loadHelperRules(); }; });
|
|
3588
|
+
el.querySelectorAll('[data-helper-action]').forEach(function(btn) { btn.onclick = function() { var cellKey = btn.dataset.helperCell; var action = btn.dataset.helperAction; btn.disabled = true; _helperRulesSetState(cellKey, action); }; });
|
|
3589
|
+
el.querySelectorAll('[data-helper-outcomes]').forEach(function(btn) { btn.onclick = function() { _helperRulesToggleOutcomes(btn.dataset.helperOutcomes); }; });
|
|
3170
3590
|
el.querySelectorAll('[data-routing-edit]').forEach(function(btn) { btn.onclick = function() { _routingWorkflowId = btn.dataset.routingEdit; _routingWorkflowView = 'editor'; _renderRoutingWorkflows(); }; });
|
|
3171
3591
|
var back = el.querySelector('[data-routing-back]'); if (back) back.onclick = function() { _routingWorkflowView = 'library'; _renderRoutingWorkflows(); };
|
|
3172
3592
|
var add = el.querySelector('[data-routing-new]'); if (add) add.onclick = function() { var id = 'wf_new-' + Date.now(); _routingWorkflows.push({ id:id,name:'New workflow',summary:'Describe when this workflow should run.',category:'coding',version:0,source:'user',enabled:true,autoMatch:true,matchThreshold:.62,defaultPolicy:{type:'inherit'},nodes:[] }); _routingWorkflowId=id; _routingWorkflowView='editor'; _renderRoutingWorkflows(); };
|
|
@@ -3473,8 +3893,11 @@ function _delegatedWorkerSkillButtonMarkup(agentId, plan) {
|
|
|
3473
3893
|
return '<button type="button" data-install-cli-skill="' + escHtml(agentId) + '"' + extra + ' style="padding:4px 10px;border-radius:5px;border:1px solid var(--border,#414868);background:transparent;color:var(--fg,#c0caf5);cursor:pointer;font-size:11px;">' + escHtml(label) + '</button>';
|
|
3474
3894
|
}
|
|
3475
3895
|
|
|
3896
|
+
// One agent's row, anchored by `data-delegated-worker-skill-row="<agentId>"` so a
|
|
3897
|
+
// reader (or a spec) can scope to THIS row instead of a bare text match that any
|
|
3898
|
+
// unrelated "unavailable"/version string elsewhere in the section also satisfies.
|
|
3476
3899
|
function _delegatedWorkerSkillRowMarkup(agentId, agentName, plan) {
|
|
3477
|
-
return '<div style="display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap;padding:3px 0;">' +
|
|
3900
|
+
return '<div data-delegated-worker-skill-row="' + escHtml(agentId) + '" style="display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap;padding:3px 0;">' +
|
|
3478
3901
|
'<div style="font-size:11px;color:var(--fg-dim,#565f89);">delegate · ' + escHtml(agentName) + '</div>' +
|
|
3479
3902
|
'<div style="display:flex;gap:8px;align-items:center;">' +
|
|
3480
3903
|
'<span style="font-size:10px;color:var(--fg-dim,#565f89);">' + escHtml(_delegatedWorkerSkillPlanLabel(plan)) + '</span>' +
|
|
@@ -4281,6 +4704,54 @@ function _codingAgentUpgradeRenderJobDialog(job) {
|
|
|
4281
4704
|
};
|
|
4282
4705
|
}
|
|
4283
4706
|
|
|
4707
|
+
// WP-2 fix (B): the card is rebuilt with `el.innerHTML = …`, so a legitimate repaint
|
|
4708
|
+
// (flow moved on, account changed) also throws away whatever the user had typed into
|
|
4709
|
+
// the sign-in code box, its focus and its caret. Capture the drafts before the swap
|
|
4710
|
+
// and put them back on the matching card after the bindings are attached. Pure DOM,
|
|
4711
|
+
// no timers: a card whose new markup has no code box (the flow closed) drops its draft.
|
|
4712
|
+
function _modelsCodingAgentCaptureSignInDrafts(el) {
|
|
4713
|
+
var drafts = [];
|
|
4714
|
+
if (!el || typeof el.querySelectorAll !== 'function') return drafts;
|
|
4715
|
+
var doc = el.ownerDocument || (typeof document !== 'undefined' ? document : null);
|
|
4716
|
+
el.querySelectorAll('[data-coding-agent-card]').forEach(function(card) {
|
|
4717
|
+
var code = typeof card.querySelector === 'function' ? card.querySelector('[data-sign-in-code]') : null;
|
|
4718
|
+
if (!code) return;
|
|
4719
|
+
var error = typeof card.querySelector === 'function' ? card.querySelector('[data-sign-in-error]') : null;
|
|
4720
|
+
drafts.push({
|
|
4721
|
+
cardId: (card.dataset && card.dataset.codingAgentCard) || '',
|
|
4722
|
+
value: code.value,
|
|
4723
|
+
selectionStart: typeof code.selectionStart === 'number' ? code.selectionStart : null,
|
|
4724
|
+
selectionEnd: typeof code.selectionEnd === 'number' ? code.selectionEnd : null,
|
|
4725
|
+
focused: !!(doc && doc.activeElement && doc.activeElement === code),
|
|
4726
|
+
error: error ? error.textContent : null,
|
|
4727
|
+
});
|
|
4728
|
+
});
|
|
4729
|
+
return drafts;
|
|
4730
|
+
}
|
|
4731
|
+
|
|
4732
|
+
function _modelsCodingAgentRestoreSignInDrafts(el, drafts) {
|
|
4733
|
+
if (!el || !drafts || !drafts.length) return;
|
|
4734
|
+
if (typeof el.querySelectorAll !== 'function') return;
|
|
4735
|
+
var byCard = {};
|
|
4736
|
+
drafts.forEach(function(draft) { byCard[draft.cardId] = draft; });
|
|
4737
|
+
el.querySelectorAll('[data-coding-agent-card]').forEach(function(card) {
|
|
4738
|
+
var draft = byCard[(card.dataset && card.dataset.codingAgentCard) || ''];
|
|
4739
|
+
if (!draft) return;
|
|
4740
|
+
var code = typeof card.querySelector === 'function' ? card.querySelector('[data-sign-in-code]') : null;
|
|
4741
|
+
if (!code) return;
|
|
4742
|
+
if (typeof draft.value === 'string') code.value = draft.value;
|
|
4743
|
+
if (typeof draft.error === 'string') {
|
|
4744
|
+
var error = typeof card.querySelector === 'function' ? card.querySelector('[data-sign-in-error]') : null;
|
|
4745
|
+
if (error) error.textContent = draft.error;
|
|
4746
|
+
}
|
|
4747
|
+
if (!draft.focused) return;
|
|
4748
|
+
if (typeof code.focus === 'function') code.focus();
|
|
4749
|
+
if (typeof code.setSelectionRange === 'function' && draft.selectionStart !== null && draft.selectionEnd !== null) {
|
|
4750
|
+
code.setSelectionRange(draft.selectionStart, draft.selectionEnd);
|
|
4751
|
+
}
|
|
4752
|
+
});
|
|
4753
|
+
}
|
|
4754
|
+
|
|
4284
4755
|
function renderModelsCodingAgentRoutes(providers, models) {
|
|
4285
4756
|
var el = document.getElementById('models-coding-agents-section');
|
|
4286
4757
|
if (!el) return;
|
|
@@ -4392,7 +4863,7 @@ function renderModelsCodingAgentRoutes(providers, models) {
|
|
|
4392
4863
|
_modelsCodingAgentMeta('CLI', cliLabel, status.cliReady ? '#9ece6a' : '#e0af68') +
|
|
4393
4864
|
_modelsCodingAgentOtherInstallsHtml(versionInfo) +
|
|
4394
4865
|
_modelsCodingAgentMeta('Version', upgradeRunning ? _codingAgentUpgradePhaseText(upgradeJob) : _modelsCodingAgentVersionText(versionInfo), upgradeRunning ? '#7aa2f7' : ((versionInfo && versionInfo.hasUpdate) ? '#e0af68' : 'var(--fg,#c0caf5)'), upgradeRunning ? null : { title: _modelsCodingAgentVersionTitle(versionInfo), dim: _modelsCodingAgentVersionDim(versionInfo) }) +
|
|
4395
|
-
(_modelsProviderIdForPreset(preset) ? _modelsCodingAgentMeta('Account', _modelsCodingAgentAccountText(preset), _modelsCodingAgentAccountColor(preset)) : '') +
|
|
4866
|
+
(_modelsProviderIdForPreset(preset) ? _modelsCodingAgentMeta('Account', _modelsCodingAgentAccountText(preset), _modelsCodingAgentAccountColor(preset), { title: _modelsCodingAgentAccountTitle(preset) }) : '') +
|
|
4396
4867
|
_modelsCodingAgentMeta('CTM Status', hookLabel, (status.hooksSupported === false) ? (status.cliReady ? '#9ece6a' : 'var(--fg-dim,#565f89)') : (status.hookReady ? '#9ece6a' : '#e0af68')) +
|
|
4397
4868
|
((preset.id === 'codex' || preset.id === 'claude-code') && status.hooksSupported !== false ? _modelsCodingAgentMeta('OTLP telemetry', _modelsOtelReceiptText((((_modelsAgentStatus || {}).hooks || {}).agents || {})[preset.id]), 'var(--fg-dim,#565f89)') : '') +
|
|
4398
4869
|
_modelsCodingAgentMeta('Model Source', preset.modelSource) +
|
|
@@ -4435,9 +4906,12 @@ function renderModelsCodingAgentRoutes(providers, models) {
|
|
|
4435
4906
|
'</div>' +
|
|
4436
4907
|
_delegatedWorkersGroupMarkup(providers, models, _delegatedWorkerStatus) +
|
|
4437
4908
|
'</section>';
|
|
4909
|
+
// WP-2 fix (B): whatever the user had typed into a sign-in code box survives this
|
|
4910
|
+
// rebuild — captured here, put back once the new markup is bound below.
|
|
4911
|
+
var signInDrafts = _modelsCodingAgentCaptureSignInDrafts(el);
|
|
4438
4912
|
el.innerHTML = DOMPurify.sanitize(h, {
|
|
4439
4913
|
ADD_TAGS: ['article', 'code', 'select', 'option'],
|
|
4440
|
-
ADD_ATTR: ['style', 'data-coding-agent-card', 'data-agent-state', 'data-agent-update', 'data-agent-update-banner', 'data-agent-upgrade-job', 'data-install-agent-hooks', 'data-install-missing-agent-hooks', 'data-install-outdated-agent-hooks', 'data-live-status-update-banner', 'data-live-status-missing-banner', 'data-refresh-agent-status', 'data-upgrade-agent', 'data-agent-auto-update-toggle', 'data-agent-other-installs', 'data-agent-auto-attempt', 'checked', 'data-upgrade-all-agents', 'data-view-upgrade-job', 'data-view-upgrade-batch', 'data-review-agent-updates', 'data-dismiss-agent-updates', 'data-delegated-worker-route', 'data-delegated-worker-route-filter', 'data-delegated-worker-effective', 'placeholder', 'aria-label', 'autocomplete', 'data-delegated-workers-group', 'data-install-cli-skill', 'data-install-cli-overwrite', 'type', 'disabled', 'title', 'id', 'for', 'value', 'selected', 'data-sign-in-agent', 'data-show-sign-in-tab', 'data-open-sign-in-page', 'data-sign-in-hint', 'data-sign-in-failed', 'href', 'target', 'rel'],
|
|
4914
|
+
ADD_ATTR: ['style', 'data-coding-agent-card', 'data-agent-state', 'data-agent-update', 'data-agent-update-banner', 'data-agent-upgrade-job', 'data-install-agent-hooks', 'data-install-missing-agent-hooks', 'data-install-outdated-agent-hooks', 'data-live-status-update-banner', 'data-live-status-missing-banner', 'data-refresh-agent-status', 'data-upgrade-agent', 'data-agent-auto-update-toggle', 'data-agent-other-installs', 'data-agent-auto-attempt', 'checked', 'data-upgrade-all-agents', 'data-view-upgrade-job', 'data-view-upgrade-batch', 'data-review-agent-updates', 'data-dismiss-agent-updates', 'data-delegated-worker-route', 'data-delegated-worker-route-filter', 'data-delegated-worker-effective', 'placeholder', 'aria-label', 'autocomplete', 'data-delegated-workers-group', 'data-delegated-worker-skill-row', 'data-install-cli-skill', 'data-install-cli-overwrite', 'type', 'disabled', 'title', 'id', 'for', 'value', 'selected', 'data-sign-in-agent', 'data-show-sign-in-tab', 'data-open-sign-in-page', 'data-sign-in-hint', 'data-sign-in-failed', 'data-sign-in-user-code', 'data-sign-in-copy-code', 'data-sign-in-code', 'data-sign-in-code-submit', 'data-sign-in-error', 'inputmode', 'spellcheck', 'href', 'target', 'rel'],
|
|
4441
4915
|
});
|
|
4442
4916
|
el.querySelectorAll('[data-delegated-worker-route]').forEach(function(select) {
|
|
4443
4917
|
var filter = select.parentNode.querySelector('[data-delegated-worker-route-filter]');
|
|
@@ -4623,6 +5097,42 @@ function renderModelsCodingAgentRoutes(providers, models) {
|
|
|
4623
5097
|
try { activateTab(sessionId); } catch (e) { /* expected: an already-closed tab cannot be activated */ }
|
|
4624
5098
|
});
|
|
4625
5099
|
});
|
|
5100
|
+
// The code entry (WP-2): the submit button and Enter in the box both POST the
|
|
5101
|
+
// pasted value to the flow's provider, resolved from the card the markup sits in.
|
|
5102
|
+
el.querySelectorAll('[data-sign-in-code-submit], [data-sign-in-code]').forEach(function(node) {
|
|
5103
|
+
var submit = function() {
|
|
5104
|
+
var card = node.closest('[data-coding-agent-card]');
|
|
5105
|
+
var preset = card ? _modelsCodingAgentPresetById(card.dataset.codingAgentCard) : null;
|
|
5106
|
+
var providerId = preset ? _modelsProviderIdForPreset(preset) : '';
|
|
5107
|
+
var submitBtn = node.hasAttribute('data-sign-in-code-submit')
|
|
5108
|
+
? node
|
|
5109
|
+
: node.parentNode.querySelector('[data-sign-in-code-submit]');
|
|
5110
|
+
_modelsProviderLoginSubmitCode(
|
|
5111
|
+
providerId,
|
|
5112
|
+
node.hasAttribute('data-sign-in-code') ? node : node.parentNode.querySelector('[data-sign-in-code]'),
|
|
5113
|
+
node.parentNode.querySelector('[data-sign-in-error]'),
|
|
5114
|
+
submitBtn,
|
|
5115
|
+
);
|
|
5116
|
+
};
|
|
5117
|
+
if (node.hasAttribute('data-sign-in-code-submit')) {
|
|
5118
|
+
node.addEventListener('click', submit);
|
|
5119
|
+
return;
|
|
5120
|
+
}
|
|
5121
|
+
node.addEventListener('keydown', function(ev) {
|
|
5122
|
+
if (ev.key !== 'Enter') return;
|
|
5123
|
+
ev.preventDefault();
|
|
5124
|
+
submit();
|
|
5125
|
+
});
|
|
5126
|
+
});
|
|
5127
|
+
el.querySelectorAll('[data-sign-in-copy-code]').forEach(function(btn) {
|
|
5128
|
+
btn.addEventListener('click', function() {
|
|
5129
|
+
var codeEl = btn.parentNode.querySelector('[data-sign-in-user-code]');
|
|
5130
|
+
if (codeEl) _modelsProviderLoginCopyCode(codeEl.textContent, btn);
|
|
5131
|
+
});
|
|
5132
|
+
});
|
|
5133
|
+
// WP-2 fix (B): the bindings are attached — a draft the user was typing survives the
|
|
5134
|
+
// rebuild above, focus and caret included.
|
|
5135
|
+
_modelsCodingAgentRestoreSignInDrafts(el, signInDrafts);
|
|
4626
5136
|
// Resumes the 2 s poll after a re-render while a flow is still open.
|
|
4627
5137
|
_modelsProviderLoginEnsurePoll();
|
|
4628
5138
|
if (!_codingAgentUpgradeHasRunningJob()) _maybePromptCodingAgentHookSetupFromAgentsTab();
|