create-walle 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +6 -4
- package/package.json +1 -1
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +55 -17
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +1 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +2 -2
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +4 -2
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +902 -239
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +6 -4
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
|
@@ -94,7 +94,11 @@ function _projectSessionParked(s, options) {
|
|
|
94
94
|
? `${idleMin ? 'Paused after ' + idleMin + ' minutes of inactivity. ' : 'Paused after inactivity. '}Your conversation and working directory are preserved.`
|
|
95
95
|
: reason === 'cap' || reason === 'prewarm-cap' || reason === 'interactive-preempt'
|
|
96
96
|
? 'Paused to keep the live-session limit available. Your conversation and working directory are preserved.'
|
|
97
|
-
:
|
|
97
|
+
// Hub WP-6: a box-owned session the hub cannot reach shows its last known state; the box
|
|
98
|
+
// still owns (and may still be running) it.
|
|
99
|
+
: reason === 'remote-mirror'
|
|
100
|
+
? `Runs on ${String(s.meta?.machineName || s.meta?.machine_name || '') || 'another machine'}, which is not reachable right now. This is its last known state; it updates when that machine is back.`
|
|
101
|
+
: 'Paused to relieve system memory pressure. Your conversation and working directory are preserved.';
|
|
98
102
|
_projectSessionLifecycle(s, 'parked', { title: 'Session parked', detail, blocked });
|
|
99
103
|
}
|
|
100
104
|
|
|
@@ -172,6 +172,11 @@
|
|
|
172
172
|
// D-2 (transcript-history-fidelity WP-0): carry the server's human-readable refusal
|
|
173
173
|
// cause alongside the code, so the toast can say WHY, not just which code refused.
|
|
174
174
|
err.reason = (body && body.reason) || '';
|
|
175
|
+
// source-missing diagnosis: the raw-Codex lane reports WHY in `coverage.reason`/`meta.reason`
|
|
176
|
+
// (`base(state, generation, reason)` in lib/raw-codex-history-window.js), never in a top-level
|
|
177
|
+
// `reason`, so that cause used to reach the entry-failure beacon as nothing at all. Carried on
|
|
178
|
+
// its OWN field: `err.reason` drives the toast copy and stays exactly as it is.
|
|
179
|
+
err.coverageReason = String((body && ((body.coverage && body.coverage.reason) || (body.meta && body.meta.reason))) || '');
|
|
175
180
|
throw err;
|
|
176
181
|
}
|
|
177
182
|
const Pages = historyTranscriptPages();
|
|
@@ -215,12 +220,12 @@
|
|
|
215
220
|
if (c._continuousSegment && index === 0) {
|
|
216
221
|
if (body.newerCursor) return rebaseSeamPage(c, rows.length);
|
|
217
222
|
landSeamPage(c, body, { reason: (opts && opts.reason) || 'refetch', cursor: opts && opts.cursor }); // D-19: a seam refresh lands as 'refresh'
|
|
218
|
-
if (direction === 'older' && (done || stuck)) c._transcriptDone = true;
|
|
223
|
+
if (direction === 'older' && (done || stuck)) { c._transcriptDone = true; if (stuck) c._transcriptModel.reachedStart = true; }
|
|
219
224
|
return { ok: true, rows: rows.length, bytes: c._transcriptModel.bytes.get(index) || 0, shift: documentRows(c) - before };
|
|
220
225
|
}
|
|
221
226
|
const snap = hs.captureAnchor(c);
|
|
222
227
|
Pages.insertPage(model, index, body);
|
|
223
|
-
if (direction === 'older' && (done || stuck)) c._transcriptDone = true;
|
|
228
|
+
if (direction === 'older' && (done || stuck)) { c._transcriptDone = true; if (stuck) model.reachedStart = true; }
|
|
224
229
|
const target = hs.anchoredScrollTop(c, snap);
|
|
225
230
|
const win = hs.neededRowWindow(c, target);
|
|
226
231
|
// Eviction floor = the fetch window itself (viewport +/- 1 pane is inside it): a page the
|
|
@@ -1183,13 +1188,27 @@
|
|
|
1183
1188
|
}
|
|
1184
1189
|
|
|
1185
1190
|
// One retry timer at most (a no-op while pending).
|
|
1191
|
+
// Clock-free tests (D-2/D-4, WP-6): the ladder's own progress is readable from the page -- `window.TerminalHistoryViewport.get(id)`
|
|
1192
|
+
// is this `c` -- so a test waits on the loop's state instead of sleeping through a window at least as long as its period:
|
|
1193
|
+
// _seamRetryAttempts -- monotone: +1 per step whose timer FIRED (the loop's attempt to re-ask). Counted before the ask is
|
|
1194
|
+
// tried, so a step that skips the ask (a request is in flight, or the reader is gone) still counts as
|
|
1195
|
+
// an attempt; `_seamRefreshes` counts the requests that actually started (null/undefined before the
|
|
1196
|
+
// first landing that armed the ladder).
|
|
1197
|
+
// _seamRetryScheduled -- true while a step's timer is pending, false once it has fired or been cleared (also false/undefined
|
|
1198
|
+
// with no ladder).
|
|
1199
|
+
// _seamRetryStopped -- true once resetSeamFollow ran: a landing proved or overlapped the join (or the reader exited), so no
|
|
1200
|
+
// further attempt will be made. Set false again only by a landing that is still `none` and re-arms it.
|
|
1186
1201
|
function armSeamBehindRetry(c) {
|
|
1187
1202
|
const step = Number(c._seamBehindStep) || 0;
|
|
1188
1203
|
if (c._seamRetryTimer) return;
|
|
1189
1204
|
c._seamBehindStep = Math.min(step + 1, SEAM_BEHIND_RETRY_MS.length);
|
|
1205
|
+
c._seamRetryAttempts = Number(c._seamRetryAttempts) || 0; // a number from the first arm on, so a reader never has to tell 0 from "no ladder"
|
|
1206
|
+
c._seamRetryScheduled = true; c._seamRetryStopped = false;
|
|
1190
1207
|
/* deadline-exempt: bounded transcript-behind retry (SEAM_BEHIND_RETRY_MS: 1, 2, 4 s, then 10 s) that re-asks for page 0; cleared by a landing that proves or overlaps and on exit by resetSeamFollow; not a recovery/activation deadline */
|
|
1191
1208
|
c._seamRetryTimer = setTimeout(() => {
|
|
1192
1209
|
c._seamRetryTimer = null;
|
|
1210
|
+
c._seamRetryScheduled = false;
|
|
1211
|
+
c._seamRetryAttempts = (Number(c._seamRetryAttempts) || 0) + 1; // the step fired: this is the attempt, whatever the ask below does
|
|
1193
1212
|
if (!c.active || !c._hs) return;
|
|
1194
1213
|
if (!refreshSeamPage(c)) armSeamBehindRetry(c); // a request is in flight: look again next step
|
|
1195
1214
|
}, SEAM_BEHIND_RETRY_MS[Math.min(step, SEAM_BEHIND_RETRY_MS.length - 1)]);
|
|
@@ -1199,6 +1218,8 @@
|
|
|
1199
1218
|
function resetSeamFollow(c) {
|
|
1200
1219
|
if (c._seamRetryTimer) { clearTimeout(c._seamRetryTimer); c._seamRetryTimer = null; }
|
|
1201
1220
|
c._seamBehindStep = 0;
|
|
1221
|
+
c._seamRetryScheduled = false;
|
|
1222
|
+
c._seamRetryStopped = true; // D-18/WP-6: a landing that proved or overlapped, or an exit: the ladder is stopped for good
|
|
1202
1223
|
}
|
|
1203
1224
|
|
|
1204
1225
|
// D-17: a page 0 that still has a newer neighbour is not the transcript's tail (the file grew past
|
|
@@ -1344,6 +1365,9 @@
|
|
|
1344
1365
|
const err = new Error(code);
|
|
1345
1366
|
err.code = code;
|
|
1346
1367
|
err.reason = (body && body.reason) || '';
|
|
1368
|
+
// Same as applyTranscriptWindowBody: the server's own WHY (coverage.reason / meta.reason),
|
|
1369
|
+
// kept on its own field so the entry-failure beacon can report it without touching the toast.
|
|
1370
|
+
err.coverageReason = String((body && ((body.coverage && body.coverage.reason) || (body.meta && body.meta.reason))) || '');
|
|
1347
1371
|
return failEntry(err);
|
|
1348
1372
|
}
|
|
1349
1373
|
if (!Array.isArray(body.rows) || body.rows.length === 0) {
|
|
@@ -79,6 +79,21 @@
|
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
// Clock-free tests (D-2/D-4, WP-6): the recorder's sample counter and the samples it is holding uncommitted travel next to
|
|
83
|
+
// `revision` on the frame's painted field, so a test waits on them instead of sleeping a window. `samples` is the recorder's
|
|
84
|
+
// monotone observe count (it moves on EVERY sample, including one that changes nothing). The frame carries the recorder's `hold`
|
|
85
|
+
// descriptor ({ kind, rows, top }: the samples it rejected and did not commit, null when it holds none -- the same fact as the
|
|
86
|
+
// recorder's boolean `held`, which does not travel on the wire); this store publishes it as `held`, its one store, so `held` here
|
|
87
|
+
// is unambiguously the descriptor. An older host (and today's /painted-rows route) sends neither: both read as null.
|
|
88
|
+
function observedOf(painted) {
|
|
89
|
+
const samples = Number.isSafeInteger(painted.samples) && painted.samples >= 0 ? painted.samples : null;
|
|
90
|
+
const h = painted.hold;
|
|
91
|
+
const held = h && typeof h === 'object'
|
|
92
|
+
? { kind: typeof h.kind === 'string' ? h.kind : null, rows: Number.isSafeInteger(h.rows) && h.rows >= 0 ? h.rows : 0, top: Number.isSafeInteger(h.top) ? h.top : null }
|
|
93
|
+
: null;
|
|
94
|
+
return { samples, held };
|
|
95
|
+
}
|
|
96
|
+
|
|
82
97
|
// `painted`: the validated frame field { epoch, top, pinned, floor, revision, breaks[, revisedFrom][, from, rows] }, or null (an older
|
|
83
98
|
// host, a normal-buffer surface: no painted state; the rows already held stay until a state with another epoch or revision arrives).
|
|
84
99
|
function noteFrame(session, painted) {
|
|
@@ -95,7 +110,7 @@
|
|
|
95
110
|
else if (painted.revisedFrom !== undefined) dropFrom(store, painted.revisedFrom);
|
|
96
111
|
else if (revision > store.revision) clearRows(store); // a keyframe or a missed delta: the rows revised are unknown
|
|
97
112
|
store.revision = revision;
|
|
98
|
-
store.state = { epoch: painted.epoch, top: painted.top, pinned: painted.pinned, floor: painted.floor, revision, breaks: painted.breaks || [], below: Number.isSafeInteger(painted.below) && painted.below > 0 ? painted.below : 0 }; // R-F2: rows the app holds below its screen; an older host sends none, and that is 0
|
|
113
|
+
store.state = { epoch: painted.epoch, top: painted.top, pinned: painted.pinned, floor: painted.floor, revision, breaks: painted.breaks || [], below: Number.isSafeInteger(painted.below) && painted.below > 0 ? painted.below : 0, ...observedOf(painted) }; // R-F2: rows the app holds below its screen; an older host sends none, and that is 0
|
|
99
114
|
if (Array.isArray(painted.rows) && Number.isSafeInteger(painted.from)) putRows(store, painted.from, painted.rows);
|
|
100
115
|
trim(store);
|
|
101
116
|
}
|
|
@@ -106,7 +121,7 @@
|
|
|
106
121
|
function stateOf(sessionId) {
|
|
107
122
|
const store = stores.get(String(sessionId));
|
|
108
123
|
const st = store && store.state;
|
|
109
|
-
return st ? { epoch: st.epoch, top: st.top, pinned: st.pinned, floor: st.floor, revision: st.revision, breaks: st.breaks.map((b) => ({ at: b.at, reason: b.reason })), below: Number.isSafeInteger(st.below) ? st.below : 0 } : null;
|
|
124
|
+
return st ? { epoch: st.epoch, top: st.top, pinned: st.pinned, floor: st.floor, revision: st.revision, breaks: st.breaks.map((b) => ({ at: b.at, reason: b.reason })), below: Number.isSafeInteger(st.below) ? st.below : 0, samples: Number.isSafeInteger(st.samples) && st.samples >= 0 ? st.samples : null, held: st.held || null } : null;
|
|
110
125
|
}
|
|
111
126
|
|
|
112
127
|
// Rows [from, to) as stored; `undefined` where a row is not resident.
|
|
@@ -178,7 +178,19 @@
|
|
|
178
178
|
c._renderTranscript();
|
|
179
179
|
const rh = Number(c.rowHeight) > 0 ? Number(c.rowHeight) : 17;
|
|
180
180
|
const offset = Pages.offsetOfPage(c._transcriptModel, index) + (Number(bookmark.rowOffsetInPage) || 0);
|
|
181
|
-
|
|
181
|
+
// reader-scroll-write beacon: a resume that lands more than one pane from where the reader was is a
|
|
182
|
+
// movement nobody scrolled, so it names itself (`resume`). The write is the same one it was.
|
|
183
|
+
if (c.scrollEl) {
|
|
184
|
+
const target = offset * rh; // WP-2: one coordinate for every source (the native scroller included)
|
|
185
|
+
const hs = scroller(); // resolved at call time, like resumePaintedRow's
|
|
186
|
+
const before = Number(c.scrollEl.scrollTop) || 0;
|
|
187
|
+
c.scrollEl.scrollTop = target;
|
|
188
|
+
const after = Number(c.scrollEl.scrollTop) || 0;
|
|
189
|
+
if (c._hs) c._hs.lastTop = after;
|
|
190
|
+
if (hs && typeof hs.noteBigScroll === 'function' && Math.abs(after - before) > (Number(c.scrollEl.clientHeight) || 0)) {
|
|
191
|
+
hs.noteBigScroll(c, 'resume', before, after, target);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
182
194
|
return true;
|
|
183
195
|
}
|
|
184
196
|
|
|
@@ -126,10 +126,7 @@
|
|
|
126
126
|
function setSpacerHeightAnchored(c, nextHeightPx, deltaAbovePx) {
|
|
127
127
|
if (c && c.spacerEl) c.spacerEl.style.height = (Number(nextHeightPx) || 0) + 'px';
|
|
128
128
|
const delta = Number(deltaAbovePx) || 0;
|
|
129
|
-
if (delta && c && c.scrollEl)
|
|
130
|
-
c.scrollEl.scrollTop = (Number(c.scrollEl.scrollTop) || 0) + delta;
|
|
131
|
-
if (c._hs) c._hs.lastTop = Number(c.scrollEl.scrollTop) || 0;
|
|
132
|
-
}
|
|
129
|
+
if (delta && c && c.scrollEl) writeScrollTop(c, 'spacer', (Number(c.scrollEl.scrollTop) || 0) + delta);
|
|
133
130
|
}
|
|
134
131
|
|
|
135
132
|
// D-3 (unified-scrollbar track wheel, keys): deltaMode 0 = px, 1 = lines (x row height),
|
|
@@ -144,11 +141,166 @@
|
|
|
144
141
|
const scroller = c && c.scrollEl;
|
|
145
142
|
if (!scroller) return false;
|
|
146
143
|
const top = deltaPx(c, deltaY, deltaMode);
|
|
144
|
+
const before = Number(scroller.scrollTop) || 0;
|
|
147
145
|
if (typeof scroller.scrollBy === 'function') scroller.scrollBy({ top });
|
|
148
|
-
else scroller.scrollTop =
|
|
146
|
+
else scroller.scrollTop = before + top;
|
|
147
|
+
const after = Number(scroller.scrollTop) || 0;
|
|
148
|
+
noteBigScrollIfPane(c, 'scrollBy', before, after, after); // scrollBy clamps the delta itself: there is no separate target to report
|
|
149
149
|
return true;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// reader-scroll-write (2026-10-25 incident: a light wheel-up jumped the reader ~5,800 rows to the
|
|
154
|
+
// top of its document and the D-2 chain then fetched 11 pages; telemetry named no write). INSTRUMENT
|
|
155
|
+
// ONLY: every write below is the same write it was before, the only additions are the two beacons
|
|
156
|
+
// `history-reader-scroll-write` (a movement bigger than one pane, with its site) and
|
|
157
|
+
// `history-reader-chain-advance` (a burst of chain advances). Both coalesce into bounded integers --
|
|
158
|
+
// no transcript text, no URLs, no cursors -- and every failure is swallowed: nothing in the scroll,
|
|
159
|
+
// anchor, fetch or park path reads any of this.
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
const SCROLL_WRITE_EVENT = 'history-reader-scroll-write';
|
|
162
|
+
const CHAIN_ADVANCE_EVENT = 'history-reader-chain-advance';
|
|
163
|
+
/* deadline-exempt: the scroll-write beacon's fixed coalescing window (one row per incident burst), not a recovery/activation deadline */
|
|
164
|
+
const SCROLL_WRITE_COALESCE_MS = 1100;
|
|
165
|
+
const CHAIN_WINDOW_MS = 1000; // a chain-advance burst is this many advances inside this sliding window
|
|
166
|
+
const CHAIN_BURST = 4;
|
|
167
|
+
const CHAIN_STAMP_CAP = 16;
|
|
168
|
+
const SCROLL_WRITE_ENTRY_CAP = 4; // the first four entries name the burst; the rest are counted
|
|
169
|
+
const SCROLL_WRITE_ENTRY_CHARS = 40; // the server keeps 40 chars per entry
|
|
170
|
+
const TARGET_EPSILON_PX = 1; // above this the browser did not land where it was told (it clamped)
|
|
171
|
+
|
|
172
|
+
// The ONE write path: the same scrollTop assignment every instrumented site made before, plus the
|
|
173
|
+
// measurement that names it. `target` is what was asked for, the return value what the browser
|
|
174
|
+
// clamped to (a clamped write is itself the interesting case).
|
|
175
|
+
function writeScrollTop(c, site, target) {
|
|
176
|
+
const scroller = c && c.scrollEl;
|
|
177
|
+
if (!scroller) return 0;
|
|
178
|
+
const before = Number(scroller.scrollTop) || 0;
|
|
179
|
+
scroller.scrollTop = target;
|
|
180
|
+
const after = Number(scroller.scrollTop) || 0;
|
|
181
|
+
if (c._hs) c._hs.lastTop = after; // programmatic: never counted as travel
|
|
182
|
+
noteBigScrollIfPane(c, site, before, after, target);
|
|
183
|
+
return after;
|
|
184
|
+
}
|
|
185
|
+
function noteBigScrollIfPane(c, site, before, after, target) {
|
|
186
|
+
const scroller = c && c.scrollEl;
|
|
187
|
+
if (!scroller) return;
|
|
188
|
+
if (Math.abs(Number(after) - Number(before)) > (Number(scroller.clientHeight) || 0)) noteBigScroll(c, site, before, after, target);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function scrollWriteState(c) {
|
|
192
|
+
if (!c._bigScrollDiag) c._bigScrollDiag = { count: 0, entries: [], firstSite: '', lastSite: '', before: 0, after: 0, timer: null };
|
|
193
|
+
return c._bigScrollDiag;
|
|
194
|
+
}
|
|
195
|
+
// `tag.class` (first class only) of whatever holds the keyboard: the one hint a `native` movement cannot
|
|
196
|
+
// otherwise carry. Never an id, a value or any text the element holds.
|
|
197
|
+
function activeElementTagClass() {
|
|
198
|
+
const el = typeof document !== 'undefined' ? document.activeElement : null;
|
|
199
|
+
if (!el) return '';
|
|
200
|
+
const tag = String(el.tagName || '').toLowerCase();
|
|
201
|
+
if (!tag) return '';
|
|
202
|
+
const cls = (typeof el.className === 'string' ? el.className.trim().split(/\s+/)[0] : '') || '';
|
|
203
|
+
return '@' + (cls ? tag + '.' + cls : tag);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Coalesced: the first 4 entries (in order) plus the count and the geometry that places them, one
|
|
207
|
+
// beacon per episode. Called per big write -- never per scroll event.
|
|
208
|
+
function noteBigScroll(c, site, before, after, target) {
|
|
209
|
+
if (!c || typeof c.sendDiag !== 'function') return; // no diag channel: nothing to record, and no timer to arm for it
|
|
210
|
+
try {
|
|
211
|
+
const state = scrollWriteState(c);
|
|
212
|
+
const b = Math.round(Number(before) || 0);
|
|
213
|
+
const a = Math.round(Number(after) || 0);
|
|
214
|
+
let entry = site + ':' + b + '>' + a;
|
|
215
|
+
if (Math.abs((Number(target) || 0) - (Number(after) || 0)) > TARGET_EPSILON_PX) entry += '(t=' + Math.round(Number(target) || 0) + ')';
|
|
216
|
+
if (site === 'native') entry += activeElementTagClass();
|
|
217
|
+
if (state.count === 0) { state.before = b; state.firstSite = site; }
|
|
218
|
+
state.count += 1;
|
|
219
|
+
state.after = a;
|
|
220
|
+
state.lastSite = site;
|
|
221
|
+
if (state.entries.length < SCROLL_WRITE_ENTRY_CAP) state.entries.push(entry.slice(0, SCROLL_WRITE_ENTRY_CHARS));
|
|
222
|
+
if (state.timer == null) state.timer = setTimeout(function () { flushBigScroll(c); }, SCROLL_WRITE_COALESCE_MS);
|
|
223
|
+
} catch { /* expected: diag is best-effort */ }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// The geometry every beacon carries, read once at flush time (`_hs` is gone after a park, so restPx/
|
|
227
|
+
// spacerPx/sinceMountMs read 0 then -- the entries still name the movement).
|
|
228
|
+
function scrollDiagFacts(c) {
|
|
229
|
+
const hint = c && c._hs;
|
|
230
|
+
const model = c && c._transcriptModel;
|
|
231
|
+
const Pages = historyTranscriptPages();
|
|
232
|
+
const scroller = c && c.scrollEl;
|
|
233
|
+
let totalRows = 0;
|
|
234
|
+
let oldest = -1;
|
|
235
|
+
if (Pages && model) {
|
|
236
|
+
totalRows = Math.round(Number(Pages.totalRows(model, { separator: true })) || 0);
|
|
237
|
+
const known = Pages.oldestKnownIndex(model);
|
|
238
|
+
if (known !== null && known !== undefined) oldest = known;
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
scrollTopPx: Math.round(Number(scroller && scroller.scrollTop) || 0),
|
|
242
|
+
panePx: Math.round(Number(scroller && scroller.clientHeight) || 0),
|
|
243
|
+
restPx: hint ? Math.round(restOf(c)) : 0,
|
|
244
|
+
spacerPx: hint ? Math.round(spacerHeightOf(c)) : 0,
|
|
245
|
+
totalRows,
|
|
246
|
+
oldestPage: oldest,
|
|
247
|
+
residentPages: model && model.pages ? model.pages.size : 0,
|
|
248
|
+
sinceMountMs: hint && Number(hint.mountedAt) ? Math.max(0, Math.round(Date.now() - Number(hint.mountedAt))) : 0,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Sends the one beacon for the episode just ended and clears it (synchronously, from unmountScroller
|
|
253
|
+
// too, so a jump right before a park/exit is not lost). The state is cleared BEFORE the send: a
|
|
254
|
+
// re-entrant write from inside sendDiag starts a fresh episode rather than extending this one.
|
|
255
|
+
function flushBigScroll(c) {
|
|
256
|
+
const state = c && c._bigScrollDiag;
|
|
257
|
+
if (!state) return;
|
|
258
|
+
if (state.timer != null) clearTimeout(state.timer);
|
|
259
|
+
c._bigScrollDiag = null;
|
|
260
|
+
if (typeof c.sendDiag !== 'function') return;
|
|
261
|
+
try {
|
|
262
|
+
c.sendDiag(Object.assign({
|
|
263
|
+
count: state.count, entries: state.entries, firstSite: state.firstSite, lastSite: state.lastSite,
|
|
264
|
+
before: state.before, after: state.after,
|
|
265
|
+
chainAdv1s: chainAdvancesWithin(c, Date.now()), // was the D-2 chain running while the viewport moved?
|
|
266
|
+
}, scrollDiagFacts(c)), SCROLL_WRITE_EVENT);
|
|
267
|
+
} catch { /* expected: diag is best-effort */ }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// The chain advances inside the last CHAIN_WINDOW_MS, as of `nowMs` (pure; Beacon 1 reads it).
|
|
271
|
+
function chainAdvancesWithin(c, nowMs) {
|
|
272
|
+
const stamps = c && Array.isArray(c._chainAdvanceAt) ? c._chainAdvanceAt : [];
|
|
273
|
+
const now = Number(nowMs) || 0;
|
|
274
|
+
let count = 0;
|
|
275
|
+
for (let i = stamps.length - 1; i >= 0; i -= 1) {
|
|
276
|
+
if (now - (Number(stamps[i]) || 0) > CHAIN_WINDOW_MS) break;
|
|
277
|
+
count += 1;
|
|
278
|
+
}
|
|
279
|
+
return count;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Beacon 2: one chain advance started a fetch (the stamps are a sliding window, so an old burst never
|
|
283
|
+
// inflates a new one). The fourth inside the window reports once; the flag clears when the window has
|
|
284
|
+
// fully aged out, so a later burst reports again. No change to WHEN the chain advances.
|
|
285
|
+
function noteChainAdvance(c, where) {
|
|
286
|
+
if (!c) return;
|
|
287
|
+
try {
|
|
288
|
+
const now = Date.now();
|
|
289
|
+
const kept = (Array.isArray(c._chainAdvanceAt) ? c._chainAdvanceAt : []).filter((at) => now - (Number(at) || 0) <= CHAIN_WINDOW_MS);
|
|
290
|
+
if (kept.length === 0) c._chainAdvanceBurstSent = false; // the previous burst's window has cleared
|
|
291
|
+
kept.push(now);
|
|
292
|
+
c._chainAdvanceAt = kept.slice(-CHAIN_STAMP_CAP);
|
|
293
|
+
if (kept.length < CHAIN_BURST || c._chainAdvanceBurstSent || typeof c.sendDiag !== 'function') return;
|
|
294
|
+
c._chainAdvanceBurstSent = true; // set before the send: a throwing sendDiag must not re-report
|
|
295
|
+
c.sendDiag(Object.assign({
|
|
296
|
+
count: kept.length,
|
|
297
|
+
topRow: Math.round(Number(where && where.topRow) || 0),
|
|
298
|
+
oldestPage: where && where.oldestPage !== null && where.oldestPage !== undefined ? where.oldestPage : -1,
|
|
299
|
+
oldestFrom: Math.round(Number(where && where.oldestFrom) || 0),
|
|
300
|
+
}, scrollDiagFacts(c)), CHAIN_ADVANCE_EVENT);
|
|
301
|
+
} catch { /* expected: diag is best-effort */ }
|
|
302
|
+
}
|
|
303
|
+
|
|
152
304
|
function liveRowsOf(c) {
|
|
153
305
|
const live = c && c.getLive && c.getLive();
|
|
154
306
|
return Math.max(1, Number(live && live.term && live.term.rows) || 1);
|
|
@@ -208,8 +360,9 @@
|
|
|
208
360
|
function applyAnchor(c, target) {
|
|
209
361
|
const scroller = c && c.scrollEl;
|
|
210
362
|
if (!scroller) return false;
|
|
211
|
-
|
|
212
|
-
if (
|
|
363
|
+
// The 0.01 px guard is the write-skip that was always here: a sub-pixel "move" is not a write at all.
|
|
364
|
+
if (Math.abs((Number(scroller.scrollTop) || 0) - target) > 0.01) writeScrollTop(c, 'anchor', target);
|
|
365
|
+
else if (c._hs) c._hs.lastTop = Number(scroller.scrollTop) || 0; // programmatic: never counted as travel
|
|
213
366
|
return true;
|
|
214
367
|
}
|
|
215
368
|
|
|
@@ -304,6 +457,24 @@
|
|
|
304
457
|
seam.fetchTranscriptPage(c, index, plan.cursor, plan.direction, { attempt: 1, maxRows: plan.maxRows });
|
|
305
458
|
slots -= 1; started += 1;
|
|
306
459
|
}
|
|
460
|
+
// D-2: the window lies above what the chain can serve (`pagesForRows` named only "virtual" indices past
|
|
461
|
+
// `oldest + 1`, whose plan is null by construction; nothing landed, so no scroll event follows either --
|
|
462
|
+
// the anchor holds the viewport's distance invariant). Advance the chain one page toward the window; each
|
|
463
|
+
// landing schedules the next frame, and `planPageChain` answers null once reachedStart/_transcriptDone is set.
|
|
464
|
+
if (started === 0 && slots > 0) {
|
|
465
|
+
const oldest = Pages.oldestKnownIndex(model);
|
|
466
|
+
const range = oldest === null ? null : Pages.rangeOfPage(model, oldest);
|
|
467
|
+
const next = oldest === null ? null : oldest + 1;
|
|
468
|
+
if (range && win.topRow < range.from && !model.pages.has(next) && !c._transcriptAborters.has(next) && !seam.pageRetryPending(c, next)) {
|
|
469
|
+
const plan = seam.planPageFetch(c, next);
|
|
470
|
+
if (plan) {
|
|
471
|
+
seam.clearFailedPage(c, next);
|
|
472
|
+
seam.fetchTranscriptPage(c, next, plan.cursor, plan.direction, { attempt: 1, maxRows: plan.maxRows });
|
|
473
|
+
noteChainAdvance(c, { topRow: win.topRow, oldestPage: oldest, oldestFrom: range.from }); // the burst beacon; the advance itself is unchanged
|
|
474
|
+
slots -= 1; started += 1;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
307
478
|
return started + fetchPaintedHoles(c, win, viewTop, slots);
|
|
308
479
|
}
|
|
309
480
|
|
|
@@ -457,7 +628,7 @@
|
|
|
457
628
|
const rh = rowHeightOf(c);
|
|
458
629
|
if (e.key === 'Home') {
|
|
459
630
|
e.preventDefault();
|
|
460
|
-
|
|
631
|
+
writeScrollTop(c, 'home', 0); // the reader spells Home the same way it wrote it before (`scrollTo({top:0})` on a scroller whose scroll-behavior is the default `auto`)
|
|
461
632
|
return true;
|
|
462
633
|
}
|
|
463
634
|
const by = { PageUp: -page, PageDown: page, ArrowUp: -rh, ArrowDown: rh }[e.key];
|
|
@@ -543,6 +714,8 @@
|
|
|
543
714
|
};
|
|
544
715
|
c._hs = state;
|
|
545
716
|
c._skeletonMs = 0; c._skelSince = 0; c._travelPx = 0; c._winPx = null; c._lastFetchTop = undefined; c._seamRefreshes = 0; // WP-3 D-15 / D-20 counters, per open
|
|
717
|
+
c._bigScrollDiag = null; c._chainAdvanceAt = []; c._chainAdvanceBurstSent = false; // the two beacons' state is per open
|
|
718
|
+
state.mountedAt = Date.now(); // sinceMountMs places a jump in the open's own timeline
|
|
546
719
|
c._seamBehindStep = 0; // D-19: the transcript-behind retry ladder, per open
|
|
547
720
|
try {
|
|
548
721
|
const viewportModuleRef = viewportModule();
|
|
@@ -594,6 +767,9 @@
|
|
|
594
767
|
state.onScroll = function onReaderScroll() {
|
|
595
768
|
const top = Number(scroller.scrollTop) || 0;
|
|
596
769
|
c._travelPx = (Number(c._travelPx) || 0) + Math.abs(top - state.lastTop); // D-15 travelPx
|
|
770
|
+
// Every instrumented write sets lastTop itself, so a movement past one pane here is one none of
|
|
771
|
+
// them made: the browser moved the scroller (wheel, focus, CSS anchoring, a reflow).
|
|
772
|
+
noteBigScrollIfPane(c, 'native', state.lastTop, top, top);
|
|
597
773
|
state.lastTop = top;
|
|
598
774
|
if (isAtRest(c)) { exitReader(c, 'scroll'); return; } // D-5: the only scroll-driven exit
|
|
599
775
|
syncSkeleton(c);
|
|
@@ -615,7 +791,7 @@
|
|
|
615
791
|
paintSkeletonTile(c);
|
|
616
792
|
applyClip(c); // the pinned rows are a count of rows: their px follow the row height
|
|
617
793
|
c._renderTranscript();
|
|
618
|
-
|
|
794
|
+
writeScrollTop(c, 'remeasure', next.scrollTop);
|
|
619
795
|
});
|
|
620
796
|
c.ro.observe(scroller);
|
|
621
797
|
}
|
|
@@ -632,6 +808,7 @@
|
|
|
632
808
|
function unmountScroller(c) {
|
|
633
809
|
const state = c && c._hs;
|
|
634
810
|
if (!state) return false;
|
|
811
|
+
flushBigScroll(c); // a jump right before a park/exit is not lost; the episode's timer is cleared here, never left pending
|
|
635
812
|
if (c._skelSince) { c._skeletonMs = (Number(c._skeletonMs) || 0) + Date.now() - c._skelSince; c._skelSince = 0; } // D-15: kept on `c` for the exit beacon
|
|
636
813
|
c._hs = null;
|
|
637
814
|
cancelFetchAhead(c);
|
|
@@ -657,6 +834,7 @@
|
|
|
657
834
|
return Object.freeze({
|
|
658
835
|
ensureTermScroller, mountScroller, unmountScroller, isMounted, isMountedFor, isAtRest, clipPx, restOf, applyClip, commitPainted,
|
|
659
836
|
setSpacerHeightAnchored, scrollByPx, neededRowWindow, scheduleFetchAhead, scheduleRender, cancelRender, scheduleFrame, cancelFrame, RENDER_FALLBACK_MS, runFetchAhead, liveWheelVeto,
|
|
837
|
+
noteBigScroll, chainAdvancesWithin, // reader-scroll-write beacons: the park/resume path and the tests call these
|
|
660
838
|
handleKeydown, typedKeyData, leaveAndType, captureAnchor, anchoredScrollTop, applyAnchor, refreshLiveRows, syncSkeleton, skeletonMs, REST_EPSILON, MAX_IN_FLIGHT,
|
|
661
839
|
});
|
|
662
840
|
});
|
|
@@ -313,10 +313,11 @@
|
|
|
313
313
|
return Math.min(MAX_ESTIMATE_ROWS, Math.max(live, est));
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
+
// D-8/R-2 (WP-2): the OLDEST known page index in `rowCounts` (index k+1 is older than k), resident or not, or null while nothing is known.
|
|
317
|
+
const oldestKnownIndex = (model) => { let oldest = null; for (const index of model.rowCounts.keys()) if (oldest === null || index > oldest) oldest = index; return oldest; };
|
|
316
318
|
function _estimate(model, liveRows) {
|
|
317
319
|
if (model.rowCounts.size === 0 || model.reachedStart) return 0;
|
|
318
|
-
|
|
319
|
-
for (const index of model.rowCounts.keys()) if (oldest === null || index > oldest) oldest = index;
|
|
320
|
+
const oldest = oldestKnownIndex(model);
|
|
320
321
|
const cursor = model.cursors.get(oldest);
|
|
321
322
|
if (!cursor || cursor.olderCursor == null) return 0;
|
|
322
323
|
// Pages of the same source chunk report identical (start, end): count each distinct byte range
|
|
@@ -354,8 +355,7 @@
|
|
|
354
355
|
function _layout(model, liveRows) {
|
|
355
356
|
const live = Math.max(1, Math.floor(Number(liveRows) || Number(model.liveRows) || 1));
|
|
356
357
|
const est = _estimate(model, live);
|
|
357
|
-
|
|
358
|
-
for (const index of model.rowCounts.keys()) if (oldest === null || index > oldest) oldest = index;
|
|
358
|
+
const oldest = oldestKnownIndex(model);
|
|
359
359
|
const entries = [];
|
|
360
360
|
const byIndex = new Map();
|
|
361
361
|
let cursor = est;
|
|
@@ -495,7 +495,7 @@
|
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
return Object.freeze({
|
|
498
|
-
createModel,
|
|
498
|
+
createModel, oldestKnownIndex,
|
|
499
499
|
promptAtOrAbove,
|
|
500
500
|
insertPage,
|
|
501
501
|
pageKinds,
|