create-walle 0.10.2 → 0.10.3
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 +3 -1
- package/lib/release-schema.json +2 -2
- package/lib/runtime-closure-policy.json +8 -7
- package/package.json +1 -1
- package/template/coding-task-manager/api-prompts.js +45 -7
- package/template/coding-task-manager/bin/claude-hook.js +55 -1
- package/template/coding-task-manager/bin/ctm-relay-client.js +35 -12
- package/template/coding-task-manager/bin/land.js +2069 -0
- package/template/coding-task-manager/bin/memory-census.js +4 -2
- package/template/coding-task-manager/bin/memory-sync-verify.js +151 -0
- package/template/coding-task-manager/bin/probe-refusal-scope.js +530 -0
- package/template/coding-task-manager/db.js +156 -32
- package/template/coding-task-manager/lib/acp/acp-client.js +383 -0
- package/template/coding-task-manager/lib/acp/dsh-context-truth.js +176 -0
- package/template/coding-task-manager/lib/acp/dsh-launch-model.js +302 -0
- package/template/coding-task-manager/lib/acp/dsh-mcp-servers.js +194 -0
- package/template/coding-task-manager/lib/acp/dsh-prompt-lane.js +616 -0
- package/template/coding-task-manager/lib/acp/dsh-route-patch.js +308 -0
- package/template/coding-task-manager/lib/acp/dsh-session-runtime.js +522 -0
- package/template/coding-task-manager/lib/acp/dsh-transcript.js +395 -0
- package/template/coding-task-manager/lib/acp/dsh-usage-log.js +162 -0
- package/template/coding-task-manager/lib/acp/ndjson-stdio-transport.js +225 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +47 -11
- package/template/coding-task-manager/lib/adopted-launch-environment.js +123 -0
- package/template/coding-task-manager/lib/agent-auto-update-runtime.js +0 -3
- package/template/coding-task-manager/lib/agent-auto-update.js +26 -10
- package/template/coding-task-manager/lib/agent-bundle/build.js +657 -0
- package/template/coding-task-manager/lib/agent-bundle/codex-install.js +558 -0
- package/template/coding-task-manager/lib/agent-bundle/drift.js +120 -0
- package/template/coding-task-manager/lib/agent-bundle/gc.js +522 -0
- package/template/coding-task-manager/lib/agent-bundle/inventory.js +346 -0
- package/template/coding-task-manager/lib/agent-bundle/push.js +717 -0
- package/template/coding-task-manager/lib/agent-bundle/skill-transfer.js +724 -0
- package/template/coding-task-manager/lib/agent-bundle/spawn.js +119 -0
- package/template/coding-task-manager/lib/agent-bundle/store.js +568 -0
- package/template/coding-task-manager/lib/agent-capabilities.js +142 -12
- package/template/coding-task-manager/lib/agent-cli-cache.js +30 -5
- package/template/coding-task-manager/lib/agent-definitions.js +19 -0
- package/template/coding-task-manager/lib/agent-hooks-codex-toml.js +28 -16
- package/template/coding-task-manager/lib/agent-hooks-codex-workspace.js +9 -1
- package/template/coding-task-manager/lib/agent-hooks-installer.js +23 -8
- package/template/coding-task-manager/lib/agent-hooks-prune.js +37 -11
- package/template/coding-task-manager/lib/agent-hooks-shim.js +105 -0
- package/template/coding-task-manager/lib/agent-presets.js +84 -1
- package/template/coding-task-manager/lib/agent-upgrade-jobs.js +12 -1
- package/template/coding-task-manager/lib/agent-version-service.js +74 -11
- package/template/coding-task-manager/lib/all-sessions-query.js +6 -2
- package/template/coding-task-manager/lib/api/agent-bundles.js +436 -0
- package/template/coding-task-manager/lib/api/backup-retention.js +83 -0
- package/template/coding-task-manager/lib/api/conversation-sync-routes.js +124 -0
- package/template/coding-task-manager/lib/api/diagnostics.js +549 -69
- package/template/coding-task-manager/lib/api/fleet.js +118 -0
- package/template/coding-task-manager/lib/api/hub-bridge.js +243 -0
- package/template/coding-task-manager/lib/api/ingress.js +9 -1
- package/template/coding-task-manager/lib/api/landing.js +403 -0
- package/template/coding-task-manager/lib/api/machines.js +691 -2
- package/template/coding-task-manager/lib/api/memory-sync-routes.js +335 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +8 -3
- package/template/coding-task-manager/lib/api/remote-sessions.js +1326 -0
- package/template/coding-task-manager/lib/api/session-attach.js +623 -0
- package/template/coding-task-manager/lib/api/session-messages.js +1384 -0
- package/template/coding-task-manager/lib/api/sessions.js +77 -51
- package/template/coding-task-manager/lib/api/setup-network.js +544 -16
- package/template/coding-task-manager/lib/api/setup-wizard-handlers.js +884 -0
- package/template/coding-task-manager/lib/api/setup.js +829 -10
- package/template/coding-task-manager/lib/api/walle-bridge.js +9 -1
- package/template/coding-task-manager/lib/attachment-reconciler-wiring.js +5 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +23 -0
- package/template/coding-task-manager/lib/auth-rules.js +292 -21
- package/template/coding-task-manager/lib/background-stop.js +369 -0
- package/template/coding-task-manager/lib/best-of-attempts.js +4 -1
- package/template/coding-task-manager/lib/best-of-launch-plan.js +52 -0
- package/template/coding-task-manager/lib/box-keep-awake.js +89 -0
- package/template/coding-task-manager/lib/broadcast-reason-stats.js +152 -0
- package/template/coding-task-manager/lib/broadcast-serialize.js +5 -0
- package/template/coding-task-manager/lib/build-info.js +4 -2
- package/template/coding-task-manager/lib/claude-model-truth.js +13 -2
- package/template/coding-task-manager/lib/claude-transcript-terminal-renderer.js +17 -13
- package/template/coding-task-manager/lib/client-diag-handler.js +64 -2
- package/template/coding-task-manager/lib/codex-app-server-client.js +14 -16
- package/template/coding-task-manager/lib/codex-configuration-history.js +55 -0
- package/template/coding-task-manager/lib/codex-harness-qualification.js +43 -20
- package/template/coding-task-manager/lib/codex-rollout-history.js +743 -0
- package/template/coding-task-manager/lib/coding-agent-models.js +27 -12
- package/template/coding-task-manager/lib/coding-cli-skill-installer.js +44 -14
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +43 -2
- package/template/coding-task-manager/lib/coding-session-model-owner.js +1 -1
- package/template/coding-task-manager/lib/coding-session-model-public.js +7 -1
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +23 -4
- package/template/coding-task-manager/lib/coding-session-model-scan.js +31 -0
- package/template/coding-task-manager/lib/coding-session-model-state.js +7 -0
- package/template/coding-task-manager/lib/conversation-freshness-diagnostics.js +280 -0
- package/template/coding-task-manager/lib/conversation-item-clock.js +261 -0
- package/template/coding-task-manager/lib/conversation-source-registry.js +5 -0
- package/template/coding-task-manager/lib/conversation-store-v2.js +44 -0
- package/template/coding-task-manager/lib/conversation-sync.js +355 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +96 -12
- package/template/coding-task-manager/lib/create/worker-role-profile.js +4 -4
- package/template/coding-task-manager/lib/create-intent-lease.js +51 -0
- package/template/coding-task-manager/lib/ctm-session-context-api.js +97 -6
- package/template/coding-task-manager/lib/db-domain-tables.js +1 -0
- package/template/coding-task-manager/lib/db-domains.js +1 -0
- package/template/coding-task-manager/lib/db-owner-dispatch-probe.js +32 -0
- package/template/coding-task-manager/lib/db-owner-request-counts.js +178 -0
- package/template/coding-task-manager/lib/db-owner-worker-client.js +68 -14
- package/template/coding-task-manager/lib/db-schema-source-files.js +5 -0
- package/template/coding-task-manager/lib/deferred-restore-attempt.js +6 -2
- package/template/coding-task-manager/lib/feature-manifest.js +4 -0
- package/template/coding-task-manager/lib/fleet-conversation-route.js +97 -0
- package/template/coding-task-manager/lib/fleet-fanout.js +78 -0
- package/template/coding-task-manager/lib/fleet-hub.js +762 -0
- package/template/coding-task-manager/lib/fleet-origin-follower.js +252 -0
- package/template/coding-task-manager/lib/fleet-resolver-effects.js +147 -0
- package/template/coding-task-manager/lib/fleet-resolver-tick.js +148 -0
- package/template/coding-task-manager/lib/fleet-resolver.js +454 -0
- package/template/coding-task-manager/lib/fleet-session-list-routes.js +114 -0
- package/template/coding-task-manager/lib/fleet-session-lists.js +672 -0
- package/template/coding-task-manager/lib/fleet-update.js +798 -0
- package/template/coding-task-manager/lib/fs-watcher-root-watch.js +141 -0
- package/template/coding-task-manager/lib/fs-watcher.js +58 -42
- package/template/coding-task-manager/lib/harness-history-transition.js +50 -9
- package/template/coding-task-manager/lib/headless-term-service.js +84 -8
- package/template/coding-task-manager/lib/hermetic-agent-launch-guard.js +10 -0
- package/template/coding-task-manager/lib/history-transition-read-op.js +175 -8
- package/template/coding-task-manager/lib/host-cpu-categories.js +310 -0
- package/template/coding-task-manager/lib/host-fseventsd-sampler.js +399 -0
- package/template/coding-task-manager/lib/host-handoff.js +16 -19
- package/template/coding-task-manager/lib/host-stats.js +150 -3
- package/template/coding-task-manager/lib/hosted-sync-worker.js +43 -320
- package/template/coding-task-manager/lib/hub-bridge-access.js +798 -0
- package/template/coding-task-manager/lib/hub-bridge-box.js +409 -0
- package/template/coding-task-manager/lib/hub-bridge-mcp.js +380 -0
- package/template/coding-task-manager/lib/hub-bridge-mesh.js +313 -0
- package/template/coding-task-manager/lib/hub-bridge-ops.js +721 -0
- package/template/coding-task-manager/lib/hub-bridge.js +398 -0
- package/template/coding-task-manager/lib/idle-notify.js +491 -0
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +8 -0
- package/template/coding-task-manager/lib/instance-manifest.js +5 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +18 -8
- package/template/coding-task-manager/lib/landing/agent-rule.txt +1 -0
- package/template/coding-task-manager/lib/landing/batch-runner.js +366 -0
- package/template/coding-task-manager/lib/landing/config.js +536 -0
- package/template/coding-task-manager/lib/landing/ctm-view.js +256 -0
- package/template/coding-task-manager/lib/landing/gate.js +360 -0
- package/template/coding-task-manager/lib/landing/git.js +344 -0
- package/template/coding-task-manager/lib/landing/lease.js +247 -0
- package/template/coding-task-manager/lib/landing/merge-delta.js +380 -0
- package/template/coding-task-manager/lib/landing/proof.js +223 -0
- package/template/coding-task-manager/lib/landing/queue.js +998 -0
- package/template/coding-task-manager/lib/landing/radar.js +489 -0
- package/template/coding-task-manager/lib/landing/resolve-cli.js +424 -0
- package/template/coding-task-manager/lib/landing/state.js +263 -0
- package/template/coding-task-manager/lib/landing/stop.js +49 -0
- package/template/coding-task-manager/lib/landing/sync-cli.js +475 -0
- package/template/coding-task-manager/lib/landing/sync.js +456 -0
- package/template/coding-task-manager/lib/landing/train.js +885 -0
- package/template/coding-task-manager/lib/landing/window.js +57 -0
- package/template/coding-task-manager/lib/launch-environment.js +121 -0
- package/template/coding-task-manager/lib/launch-model-override.js +36 -10
- package/template/coding-task-manager/lib/launch-plan-pool.js +2 -1
- package/template/coding-task-manager/lib/launch-plan-warm-cache.js +6 -0
- package/template/coding-task-manager/lib/lead-model-observer.js +57 -1
- package/template/coding-task-manager/lib/lead-model-options.js +160 -3
- package/template/coding-task-manager/lib/lead-model-restore-reconciliation.js +106 -24
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +352 -68
- package/template/coding-task-manager/lib/lead-model-switch.js +114 -10
- package/template/coding-task-manager/lib/lead-model-transition-runtime.js +14 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +24 -6
- package/template/coding-task-manager/lib/lead-route-preflight.js +179 -0
- package/template/coding-task-manager/lib/lead-switch-history-mode.js +110 -0
- package/template/coding-task-manager/lib/lead-wire-agent.js +7 -0
- package/template/coding-task-manager/lib/lifecycle-wake-experiment.js +9 -2
- package/template/coding-task-manager/lib/live-defer-announce.js +45 -0
- package/template/coding-task-manager/lib/machine-registry.js +750 -5
- package/template/coding-task-manager/lib/macos-capabilities.js +32 -15
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +433 -53
- package/template/coding-task-manager/lib/mainloop-observability.js +14 -9
- package/template/coding-task-manager/lib/media-draft-owner.js +16 -3
- package/template/coding-task-manager/lib/memory-join.js +337 -0
- package/template/coding-task-manager/lib/memory-sync-verify.js +393 -0
- package/template/coding-task-manager/lib/memory-sync.js +565 -0
- package/template/coding-task-manager/lib/migrations/v57-delegate-pref-mirror-opencode.js +68 -0
- package/template/coding-task-manager/lib/migrations/v58-subagent-launch-native-subagents.js +42 -0
- package/template/coding-task-manager/lib/migrations/v59-coding-session-model-state-dsh.js +73 -0
- package/template/coding-task-manager/lib/migrations/v60-delegate-pref-mirror-dsh.js +78 -0
- package/template/coding-task-manager/lib/migrations/v61-conversation-item-clock.js +71 -0
- package/template/coding-task-manager/lib/model-availability.js +727 -0
- package/template/coding-task-manager/lib/model-execution-recipe-metadata.js +4 -6
- package/template/coding-task-manager/lib/model-host-receipt.js +6 -3
- package/template/coding-task-manager/lib/model-id-rule.js +19 -0
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/auto-mode-review.js +110 -23
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/generation-probe.js +60 -17
- package/template/coding-task-manager/lib/model-proxy/historical-tool-declarations.js +37 -0
- package/template/coding-task-manager/lib/model-proxy/lead-request-validation.js +1 -0
- package/template/coding-task-manager/lib/model-proxy/lead-token-admin.js +130 -0
- package/template/coding-task-manager/lib/model-proxy/refusal-scope.js +151 -0
- package/template/coding-task-manager/lib/model-proxy/request-budget-store.js +11 -2
- package/template/coding-task-manager/lib/model-proxy/tokens.js +69 -5
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-agent-model-args.js +25 -22
- package/template/coding-task-manager/lib/native-history-control.js +6 -4
- package/template/coding-task-manager/lib/native-lead-settings-client.js +44 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +173 -36
- package/template/coding-task-manager/lib/online-backup-worker-client.js +2 -0
- package/template/coding-task-manager/lib/opencode-cli.js +480 -0
- package/template/coding-task-manager/lib/opencode-launch-model.js +471 -0
- package/template/coding-task-manager/lib/opencode-v1-plugin/model-carrier.mjs +35 -0
- package/template/coding-task-manager/lib/opencode-v2-plugin/server.js +118 -0
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +1 -1
- package/template/coding-task-manager/lib/park-composer-draft.js +54 -0
- package/template/coding-task-manager/lib/park-fresh-relaunch.js +41 -10
- package/template/coding-task-manager/lib/perf-phase-trace.js +72 -0
- package/template/coding-task-manager/lib/perf-summary.js +7 -0
- package/template/coding-task-manager/lib/perf-tracker.js +63 -2
- package/template/coding-task-manager/lib/project-config.js +7 -0
- package/template/coding-task-manager/lib/prompt-purge-v2.js +52 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +72 -15
- package/template/coding-task-manager/lib/provider-login-tab.js +10 -2
- package/template/coding-task-manager/lib/read-pool-client.js +89 -2
- package/template/coding-task-manager/lib/read-pool-worker-handle.js +29 -4
- package/template/coding-task-manager/lib/recent-catalog-query.js +15 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +67 -10
- package/template/coding-task-manager/lib/recovery-evidence.js +26 -11
- package/template/coding-task-manager/lib/relay-client.js +57 -3
- package/template/coding-task-manager/lib/relink-audit.js +34 -5
- package/template/coding-task-manager/lib/remote-machine-catalog.js +321 -26
- package/template/coding-task-manager/lib/remote-machine-create.js +576 -36
- package/template/coding-task-manager/lib/remote-machine-link.js +546 -59
- package/template/coding-task-manager/lib/remote-machine-proxy.js +143 -9
- package/template/coding-task-manager/lib/remote-session-forward.js +65 -7
- package/template/coding-task-manager/lib/remote-terminal-target.js +9 -2
- package/template/coding-task-manager/lib/restart-guard.js +18 -6
- package/template/coding-task-manager/lib/restore-seed-modes.js +87 -0
- package/template/coding-task-manager/lib/restored-scrollback-hydration-runtime.js +22 -2
- package/template/coding-task-manager/lib/resume-admission.js +17 -3
- package/template/coding-task-manager/lib/review-repo-registry.js +58 -19
- package/template/coding-task-manager/lib/root-delivery-runtime.js +2 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +1 -1
- package/template/coding-task-manager/lib/runtime-contract.js +3 -1
- package/template/coding-task-manager/lib/schema-indexes.js +1 -0
- package/template/coding-task-manager/lib/session-context-locator.js +742 -0
- package/template/coding-task-manager/lib/session-create/attachment.js +2 -2
- package/template/coding-task-manager/lib/session-create/create-phases.js +118 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +86 -16
- package/template/coding-task-manager/lib/session-create/dsh-session.js +930 -0
- package/template/coding-task-manager/lib/session-create/lead-route-launch.js +186 -13
- package/template/coding-task-manager/lib/session-create/native-lead-lifetime.js +55 -3
- package/template/coding-task-manager/lib/session-create/opencode-lead-provider.js +50 -0
- package/template/coding-task-manager/lib/session-create/prepared.js +162 -38
- package/template/coding-task-manager/lib/session-create/provider-process.js +160 -28
- package/template/coding-task-manager/lib/session-create/response.js +7 -7
- package/template/coding-task-manager/lib/session-create/structured-session.js +27 -0
- package/template/coding-task-manager/lib/session-create/subagent-pick-table.js +3 -1
- package/template/coding-task-manager/lib/session-create/subagent-pick.js +458 -9
- package/template/coding-task-manager/lib/session-create/transcript.js +1 -1
- package/template/coding-task-manager/lib/session-create/worker-budget-setup.js +21 -2
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +7 -1
- package/template/coding-task-manager/lib/session-create/worker-launch-sandbox.js +39 -10
- package/template/coding-task-manager/lib/session-create/worker-observability.js +2 -2
- package/template/coding-task-manager/lib/session-empty.js +13 -10
- package/template/coding-task-manager/lib/session-host-manager.js +60 -0
- package/template/coding-task-manager/lib/session-jobs.js +3 -1
- package/template/coding-task-manager/lib/session-lifecycle.js +10 -4
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +6 -2
- package/template/coding-task-manager/lib/session-model-intent-contract.js +11 -8
- package/template/coding-task-manager/lib/session-park.js +738 -0
- package/template/coding-task-manager/lib/session-path-grant.js +13 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +106 -4
- package/template/coding-task-manager/lib/session-transport.js +17 -0
- package/template/coding-task-manager/lib/session-workspace-projection.js +54 -5
- package/template/coding-task-manager/lib/session-workspace-tracking-runtime.js +213 -1
- package/template/coding-task-manager/lib/skill-autocomplete-query.js +120 -3
- package/template/coding-task-manager/lib/skill-autocomplete.js +15 -1
- package/template/coding-task-manager/lib/sqlite-file-set.js +39 -0
- package/template/coding-task-manager/lib/standup-search-adapter.js +16 -2
- package/template/coding-task-manager/lib/state-sync/client-ledger.js +12 -0
- package/template/coding-task-manager/lib/state-sync/frame-emitter.js +319 -100
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +4 -1
- package/template/coding-task-manager/lib/storage/delegate-pref-mirror-store.js +32 -9
- package/template/coding-task-manager/lib/structured-session-boot-sweep.js +235 -0
- package/template/coding-task-manager/lib/submission-ack.js +90 -2
- package/template/coding-task-manager/lib/systemd-scope.js +115 -0
- package/template/coding-task-manager/lib/telemetry-receiver.js +39 -0
- package/template/coding-task-manager/lib/terminal-attach-geometry.js +985 -0
- package/template/coding-task-manager/lib/terminal-bootstrap.js +30 -0
- package/template/coding-task-manager/lib/terminal-draft-operation.js +357 -0
- package/template/coding-task-manager/lib/terminal-input-admission.js +17 -1
- package/template/coding-task-manager/lib/terminal-input-prepared.js +563 -0
- package/template/coding-task-manager/lib/transcript-cache-temps.js +171 -0
- package/template/coding-task-manager/lib/transcript-frame-cache.js +8 -3
- package/template/coding-task-manager/lib/transcript-source.js +36 -4
- package/template/coding-task-manager/lib/transcript-store.js +9 -0
- package/template/coding-task-manager/lib/typing-interaction-trace.js +106 -3
- package/template/coding-task-manager/lib/usage-ledger/backfill.js +40 -5
- package/template/coding-task-manager/lib/usage-ledger/client.js +4 -1
- package/template/coding-task-manager/lib/usage-ledger/dsh-parse.js +152 -0
- package/template/coding-task-manager/lib/usage-ledger/dsh-read.js +73 -0
- package/template/coding-task-manager/lib/usage-ledger/ingest.js +34 -6
- package/template/coding-task-manager/lib/usage-ledger/live.js +35 -8
- package/template/coding-task-manager/lib/usage-ledger/read.js +29 -20
- package/template/coding-task-manager/lib/usage-ledger/schema.js +61 -1
- package/template/coding-task-manager/lib/usage-ledger/task-coordinator.js +4 -2
- package/template/coding-task-manager/lib/wake-skip-reasons.js +1 -0
- package/template/coding-task-manager/lib/walle/turn.js +1 -1
- package/template/coding-task-manager/lib/walle-history-serve.js +838 -0
- package/template/coding-task-manager/lib/walle-kill-authority.js +2 -2
- package/template/coding-task-manager/lib/walle-log-rotation.js +164 -1
- package/template/coding-task-manager/lib/walle-mcp-auto-config.js +56 -2
- package/template/coding-task-manager/lib/walle-row-history.js +495 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +33 -14
- package/template/coding-task-manager/lib/watch-worker-client.js +203 -0
- package/template/coding-task-manager/lib/worker-terminal-output.js +5 -2
- package/template/coding-task-manager/lib/ws/hub-bridge.js +35 -0
- package/template/coding-task-manager/lib/ws/lifecycle.js +6 -11
- package/template/coding-task-manager/lib/ws/misc.js +1 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +106 -4
- package/template/coding-task-manager/lib/ws/terminal-attach.js +91 -0
- package/template/coding-task-manager/oauth-proxy.js +112 -115
- package/template/coding-task-manager/package-lock.json +10 -94
- package/template/coding-task-manager/package.json +4 -3
- package/template/coding-task-manager/protocol/message-table.json +10 -0
- package/template/coding-task-manager/protocol/messages.js +10 -0
- package/template/coding-task-manager/protocol/ws-schema.json +20 -0
- package/template/coding-task-manager/protocol/ws-schema.md +2 -0
- package/template/coding-task-manager/public/css/app.css +170 -0
- package/template/coding-task-manager/public/css/walle-session.css +4 -0
- package/template/coding-task-manager/public/index.html +473 -243
- package/template/coding-task-manager/public/js/agent-command.js +86 -0
- package/template/coding-task-manager/public/js/app/backups-panel.js +111 -5
- package/template/coding-task-manager/public/js/app/coding-agent-upgrade.js +103 -4
- package/template/coding-task-manager/public/js/app/machines-page.js +1328 -8
- package/template/coding-task-manager/public/js/app/models-tab.js +113 -38
- package/template/coding-task-manager/public/js/app/restart-banner.js +53 -0
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +184 -2
- package/template/coding-task-manager/public/js/background-work.js +196 -27
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +138 -10
- package/template/coding-task-manager/public/js/core/active-session-groups.js +179 -0
- package/template/coding-task-manager/public/js/core/pending-create.js +238 -0
- package/template/coding-task-manager/public/js/core/recent-machine-source.js +228 -0
- package/template/coding-task-manager/public/js/core/session-commands.js +180 -14
- package/template/coding-task-manager/public/js/dashboard-client-function-order.json +8 -0
- package/template/coding-task-manager/public/js/document-review-links.js +9 -1
- package/template/coding-task-manager/public/js/file-resolution-client.js +52 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +22 -2
- package/template/coding-task-manager/public/js/machine-pool-shared.js +558 -3
- package/template/coding-task-manager/public/js/message-renderer.js +4 -3
- package/template/coding-task-manager/public/js/model-picker.js +3 -1
- package/template/coding-task-manager/public/js/native-subagent-review.js +15 -2
- package/template/coding-task-manager/public/js/new-session-agent-grid.js +346 -0
- package/template/coding-task-manager/public/js/pasted-content.js +236 -0
- package/template/coding-task-manager/public/js/pe-private-content-lifetime.js +39 -7
- package/template/coding-task-manager/public/js/private-model-lifetime.js +6 -2
- package/template/coding-task-manager/public/js/prompts.js +11 -10
- package/template/coding-task-manager/public/js/protocol.js +10 -0
- package/template/coding-task-manager/public/js/restart-banner-policy.js +29 -1
- package/template/coding-task-manager/public/js/session-model-picker.js +447 -57
- package/template/coding-task-manager/public/js/session-search-utils.js +18 -2
- package/template/coding-task-manager/public/js/session-usage-view.js +2 -1
- package/template/coding-task-manager/public/js/session-workspace-tracking.js +51 -1
- package/template/coding-task-manager/public/js/state-sync-client.js +10 -1
- package/template/coding-task-manager/public/js/stream-view.js +6 -5
- package/template/coding-task-manager/public/js/terminal/conv-only-session.js +287 -0
- package/template/coding-task-manager/public/js/terminal/runtime-09.js +2 -0
- package/template/coding-task-manager/public/js/terminal/runtime-10.js +5 -5
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +8 -1
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +1 -1
- package/template/coding-task-manager/public/js/terminal-attachment-draft.js +67 -13
- package/template/coding-task-manager/public/js/terminal-image-orchestration.js +52 -6
- package/template/coding-task-manager/public/js/terminal-wheel.js +23 -3
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +4 -4
- package/template/coding-task-manager/public/js/walle.js +6 -0
- package/template/coding-task-manager/public/js/ws/live-dispatch.js +10 -0
- package/template/coding-task-manager/public/m/app.css +140 -0
- package/template/coding-task-manager/public/m/app.js +507 -68
- package/template/coding-task-manager/public/m/index.html +17 -0
- package/template/coding-task-manager/public/m/machines.js +838 -4
- package/template/coding-task-manager/public/m/private-api.js +31 -1
- package/template/coding-task-manager/public/usage.html +1 -0
- package/template/coding-task-manager/scripts/dev-route-fixture/synthetic-route-upstream.js +104 -0
- package/template/coding-task-manager/scripts/dev-route-fixture.js +339 -0
- package/template/coding-task-manager/scripts/opencode-lead-route-probe.js +195 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/fake-anthropic.js +168 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe/probe-plugin/server.js +95 -0
- package/template/coding-task-manager/scripts/opencode-v2-contract-probe.js +673 -0
- package/template/coding-task-manager/server.js +1950 -11679
- package/template/coding-task-manager/session-integrity.js +64 -4
- package/template/coding-task-manager/workers/db-owner-worker.js +19 -2
- package/template/coding-task-manager/workers/online-backup-worker.js +1 -0
- package/template/coding-task-manager/workers/read-pool-model-collector.js +51 -3
- package/template/coding-task-manager/workers/read-pool-worker.js +76 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +6 -6
- package/template/coding-task-manager/workers/session-host-process.js +5 -5
- package/template/coding-task-manager/workers/watch-worker.js +105 -0
- package/template/coding-task-manager/workers/worktree-worker.js +168 -33
- package/template/ctm-relay/lib/protocol.js +14 -1
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/shared/backup-retention.js +82 -0
- package/template/shared/conversation-admission.js +2 -0
- package/template/shared/conversation-provenance.js +3 -7
- package/template/shared/conversation-storage-v2-contract.js +5 -0
- package/template/shared/linked-worktree.js +51 -0
- package/template/shared/macos-fda-target.js +57 -0
- package/template/shared/orphan-parents.js +55 -0
- package/template/shared/release-schema.json +2 -2
- package/template/shared/storage/contract.js +3 -0
- package/template/wall-e/adapters/imessage.js +12 -0
- package/template/wall-e/agent.js +71 -4
- package/template/wall-e/api-walle.js +21 -1
- package/template/wall-e/bin/train-gemma-e4b-tooluse.js +2 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +5 -5
- package/template/wall-e/brain/brain-join.js +859 -0
- package/template/wall-e/brain/brain-sync-membership.js +20 -0
- package/template/wall-e/brain/brain-sync-store.js +131 -77
- package/template/wall-e/brain/brain-sync-v2-schema.js +203 -0
- package/template/wall-e/brain/brain-sync-v2.js +578 -0
- package/template/wall-e/brain/delegate-model-prefs-store.js +13 -4
- package/template/wall-e/brain/deterministic-id.js +51 -0
- package/template/wall-e/brain/memories.js +2 -2
- package/template/wall-e/brain/migrations.js +40 -6
- package/template/wall-e/brain/model-identity-migration.js +1 -1
- package/template/wall-e/brain/owner-call-whitelist.js +23 -7
- package/template/wall-e/brain/schema.js +45 -85
- package/template/wall-e/brain.js +171 -35
- package/template/wall-e/chat.js +3 -3
- package/template/wall-e/coding/agent-shell-env.js +7 -2
- package/template/wall-e/coding/prompt-bundle.js +66 -21
- package/template/wall-e/config/main-loop-exemptions.json +2 -2
- package/template/wall-e/http/admin-api.js +37 -0
- package/template/wall-e/http/gws-api.js +4 -0
- package/template/wall-e/http/helper-rules-api.js +7 -1
- package/template/wall-e/http/model-admin.js +8 -1
- package/template/wall-e/http/model-delegate-pref-admin.js +3 -3
- package/template/wall-e/http/model-proxy-providers.js +174 -1
- package/template/wall-e/http/model-route-health.js +157 -0
- package/template/wall-e/http/sync-api.js +278 -464
- package/template/wall-e/jobs/job-runner.js +28 -1
- package/template/wall-e/lib/brain-owner-op-priority.js +9 -1
- package/template/wall-e/lib/ctm-data-dir.js +26 -0
- package/template/wall-e/lib/derivation-home.js +147 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +50 -9
- package/template/wall-e/lib/helper-rules/grade.js +51 -8
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +38 -5
- package/template/wall-e/lib/helper-rules/store.js +4 -2
- package/template/wall-e/lib/landing-mcp-tools.js +170 -0
- package/template/wall-e/lib/mcp-client-config.js +133 -14
- package/template/wall-e/lib/mcp-gateway-migrate.js +28 -64
- package/template/wall-e/lib/mcp-integration.js +58 -13
- package/template/wall-e/lib/parent-death.js +7 -1
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -4
- package/template/wall-e/llm/delegate-lead-prefs.js +16 -1
- package/template/wall-e/llm/delegate-vendor-default.js +12 -5
- package/template/wall-e/llm/model-roles.js +1 -1
- package/template/wall-e/llm/native-delegate-selection.js +56 -8
- package/template/wall-e/llm/worker-delegate-args.js +72 -7
- package/template/wall-e/llm/worker-mcp-routing.js +66 -17
- package/template/wall-e/loops/brain-custom-writes.js +19 -0
- package/template/wall-e/loops/ingest.js +17 -1
- package/template/wall-e/loops/think.js +19 -4
- package/template/wall-e/mcp-contract.js +222 -6
- package/template/wall-e/mcp-protocol-contract.js +40 -5
- package/template/wall-e/mcp-server.js +128 -29
- package/template/wall-e/mcp-worker-schemas.js +5 -5
- package/template/wall-e/memory/ctm-context-client.js +85 -0
- package/template/wall-e/memory/ctm-session-context.js +9 -3
- package/template/wall-e/memory/hub-bridge-client.js +388 -0
- package/template/wall-e/memory/replica-origin.js +56 -0
- package/template/wall-e/memory/session-pool.js +135 -0
- package/template/wall-e/runtime/live-capabilities.js +8 -3
- package/template/wall-e/server.js +4 -2
- package/template/wall-e/shared/release-schema.json +2 -2
- package/template/wall-e/shared/sqlite-file-set.js +39 -0
- package/template/wall-e/shared/storage/contract.js +3 -0
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +7 -1
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +4 -4
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +6 -6
- package/template/wall-e/skills/_templates/fleet-sync/VERSION +1 -0
- package/template/wall-e/skills/_templates/fleet-sync/released-sha256.json +16 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/claude/SKILL.md +64 -0
- package/template/wall-e/skills/_templates/fleet-sync/templates/codex/SKILL.md +64 -0
- package/template/wall-e/tools/chrome-automation.js +6 -0
- package/template/wall-e/training/setup-cuda-train-env.sh +2 -2
- package/template/wall-e/workers/brain-owner-worker.js +18 -4
- package/template/wall-e/workers/mcp-gateway-process.js +5 -5
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Landing-throughput WP-6 shard S8 (design doc §5 D-10 "move-only", §6 "Shard
|
|
4
|
+
// module seam"): the nine Wall-E history-serving functions move out of server.js
|
|
5
|
+
// VERBATIM into this module behind the same configure(deps) seam as
|
|
6
|
+
// lib/api/session-messages.js (S3), lib/api/session-attach.js and
|
|
7
|
+
// lib/terminal-attach-geometry.js (S6). It registers NO route and NO socket
|
|
8
|
+
// handler: lib/ws/walle-control.js (wsWalleControlApi) and lib/ws/state-sync.js
|
|
9
|
+
// (wsStateSyncApi) keep their tables and now receive this module's exports, the two
|
|
10
|
+
// session-create configure() closures (identity/transcript) likewise, and server.js
|
|
11
|
+
// keeps no wrapper -- the only surviving reference there is the by-value
|
|
12
|
+
// walleHistoryServe.handleWalleHistoryRequest handed to wsWalleControlApi. Bodies
|
|
13
|
+
// are identical to server.js's declarations except for the `_deps.` prefix on every
|
|
14
|
+
// identifier that used to resolve to a server.js top-level binding (D-10 rule 1),
|
|
15
|
+
// proven by `node bin/move-only-check.js`. Seven inline `require('./lib/...')` calls
|
|
16
|
+
// are rebased to this module's own sibling paths and one
|
|
17
|
+
// `require('./public/js/...')` to `../public/js/...` (S1/S3/S6 precedent: injecting
|
|
18
|
+
// server.js's `require` is a loader-value transfer the public runtime closure guard
|
|
19
|
+
// refuses) -- the one deviation from a pure move-only diff.
|
|
20
|
+
//
|
|
21
|
+
// The module deliberately lives at lib/walle-history-serve.js and NOT under lib/ws/:
|
|
22
|
+
// this is not a router handler (two of the functions take the socket as their first
|
|
23
|
+
// parameter, the other seven are payload/lifecycle helpers), and lib/ws/*.js is the
|
|
24
|
+
// ws-router handler directory whose contract (tests/ws-router-parity) allows socket
|
|
25
|
+
// access only through ctx.
|
|
26
|
+
//
|
|
27
|
+
// The episode/cursor lifecycles SPLIT across this seam on purpose: the bodies that
|
|
28
|
+
// OWN the state stay in server.js -- `_walleHistoryCatchUpEpisodes`,
|
|
29
|
+
// `_walleHistoryCursorExpiredDiagnosticAt`, `_resetWalleHistoryCatchUpEpisode`,
|
|
30
|
+
// `_sweepWalleHistoryCatchUpEpisodes` and the two `_scheduleWalle*` schedulers --
|
|
31
|
+
// and are injected here by reference, so the maps keep one identity.
|
|
32
|
+
//
|
|
33
|
+
// Injected deps, per function:
|
|
34
|
+
// _walleHistoryForSessionUi: _capToolCallsForDisplay, normalizeWalleDisplayContent
|
|
35
|
+
// _walleHistoryKeyRange: (none)
|
|
36
|
+
// _walleHistoryPayload: CTM_CONV_ORDER_AUTHORITY_ENABLED, _publicTimelineIdentity,
|
|
37
|
+
// _resolveSessionTimelineIdentity, _resolveWalleHistorySource,
|
|
38
|
+
// _walleHistoryCorrelationFields, _wallePromptEntriesForSessionUi, publicHistoryMessage
|
|
39
|
+
// _noteWalleHistoryCatchUp: _scheduleWalleSessionRowsCatchUp,
|
|
40
|
+
// _walleHistoryCatchUpEpisodes, recordSessionDiagnostic
|
|
41
|
+
// _noteWalleHistoryCursorExpired: _walleHistoryCursorExpiredDiagnosticAt,
|
|
42
|
+
// recordSessionDiagnostic
|
|
43
|
+
// _sendWalleHistoryReply: ADMISSION_RESULTS, CTM_WS_SOLICITED_REPLY_INTERACTIVE_ENABLED,
|
|
44
|
+
// _WS_ADMISSION_COUNTER_KEY, _wsSend, _wsSolicitedReplyCounters, errorSink,
|
|
45
|
+
// recordSessionDiagnostic
|
|
46
|
+
// _sendWalleHistoryErrorFrame: ADMISSION_RESULTS, _walleHistoryCorrelationFields
|
|
47
|
+
// _sendWalleSessionHistory: WALLE_HISTORY_SERIALIZE_MAX_MESSAGES, _perfTracker,
|
|
48
|
+
// _resetWalleHistoryCatchUpEpisode, _resolveWalleHistorySourceOffThread,
|
|
49
|
+
// _scheduleWalleProjectionRepair, _scheduleWalleSessionRowsCatchUp,
|
|
50
|
+
// _walleHistoryCorrelationFields, _walleHistoryForReview,
|
|
51
|
+
// _walleOpenTurnActivityForNewestPage, _wallePromptEntriesForSessionUi,
|
|
52
|
+
// _walleRowHistoryForCtmId, _walleSessionRowsFreshness, createHistoryLaneBudget,
|
|
53
|
+
// recordSessionDiagnostic, sessions
|
|
54
|
+
// handleWalleHistoryRequest: _hydrateRuntimeGoalProjectionForSocket,
|
|
55
|
+
// _sendRuntimeWorkStateToSocket, _subscribeStateSyncClient,
|
|
56
|
+
// _walleHistoryCorrelationFields, isWalleLikeSession, recordSessionDiagnostic,
|
|
57
|
+
// sessionEvents, sessions, subscribeWalleHistoryRequestClient
|
|
58
|
+
//
|
|
59
|
+
// No moved body assigns server.js state (D-10 rule 2), so nothing is injected as a
|
|
60
|
+
// getter: every dep is a by-value reference. The two per-session Maps, the
|
|
61
|
+
// admission counters and the sessions map are mutated in place, never rebound.
|
|
62
|
+
|
|
63
|
+
let _deps = null;
|
|
64
|
+
|
|
65
|
+
function configure(deps = {}) {
|
|
66
|
+
_deps = deps;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function _walleHistoryForSessionUi(history, baseIndex = 0) {
|
|
70
|
+
const offset = Number.isFinite(Number(baseIndex)) ? Number(baseIndex) : 0;
|
|
71
|
+
return (Array.isArray(history) ? history : []).map((m, index) => {
|
|
72
|
+
const role = m.role;
|
|
73
|
+
const content = m.content || m.text || '';
|
|
74
|
+
const projected = {
|
|
75
|
+
role,
|
|
76
|
+
content: role === 'assistant' ? _deps.normalizeWalleDisplayContent(content) : content,
|
|
77
|
+
model: m.model_id || m.model || '',
|
|
78
|
+
model_id: m.model_id || m.model || '',
|
|
79
|
+
latency_ms: m.latency_ms || m.latencyMs || 0,
|
|
80
|
+
timestamp: m.timestamp || m.created_at || m.createdAt || 0,
|
|
81
|
+
created_at: m.created_at || m.timestamp || m.createdAt || 0,
|
|
82
|
+
toolCalls: _deps._capToolCallsForDisplay(m.toolCalls),
|
|
83
|
+
codingSummary: m.codingSummary || undefined,
|
|
84
|
+
metadata: m.metadata || undefined,
|
|
85
|
+
runtimeDiagnostic: m.runtimeDiagnostic || undefined,
|
|
86
|
+
liveActivity: !!m.liveActivity,
|
|
87
|
+
agentLabel: m.agentLabel || undefined,
|
|
88
|
+
attachments: m.attachments || undefined,
|
|
89
|
+
// Append-only tree edges for the session view's flag-gated branch projection.
|
|
90
|
+
// displayParentUuid bridges the intervening tool_call/tool_result records so the
|
|
91
|
+
// client tree's edges land assistant->user (computed server-side in readWalleCtmHistory).
|
|
92
|
+
uuid: m.uuid || undefined,
|
|
93
|
+
historyRowUuid: m.historyRowUuid || m.uuid || undefined,
|
|
94
|
+
parentUuid: m.parentUuid != null ? m.parentUuid : undefined,
|
|
95
|
+
historyIndex: Number.isFinite(Number(m.historyIndex)) ? Number(m.historyIndex) : offset + index,
|
|
96
|
+
messageIndex: Number.isFinite(Number(m.messageIndex)) ? Number(m.messageIndex) : offset + index,
|
|
97
|
+
orderKey: m.orderKey || m.order_key || undefined, kind: m.kind || undefined, provenance: m.provenance || undefined, turnId: m.turnId != null ? String(m.turnId) : undefined,
|
|
98
|
+
};
|
|
99
|
+
if (m.displayParentUuid !== undefined) projected.displayParentUuid = m.displayParentUuid;
|
|
100
|
+
return projected;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function _walleHistoryKeyRange(messages) {
|
|
105
|
+
let first = null;
|
|
106
|
+
let last = null;
|
|
107
|
+
for (const message of Array.isArray(messages) ? messages : []) {
|
|
108
|
+
const key = message && (message.orderKey != null ? message.orderKey : message.order_key);
|
|
109
|
+
if (typeof key !== 'string' || key === '') continue;
|
|
110
|
+
if (first === null || key < first) first = key;
|
|
111
|
+
if (last === null || key > last) last = key;
|
|
112
|
+
}
|
|
113
|
+
return first === null ? null : { first, last };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function _walleHistoryPayload(sessionOrId, history, options = {}, extra = {}) {
|
|
117
|
+
const source = _deps._resolveWalleHistorySource(sessionOrId);
|
|
118
|
+
const id = source?.ctmSessionId || (typeof sessionOrId === 'object' ? sessionOrId?.id : sessionOrId);
|
|
119
|
+
const windowStart = Number.isFinite(extra.windowStart) ? Number(extra.windowStart) : 0;
|
|
120
|
+
const messages = _walleHistoryForSessionUi(history, windowStart).map(_deps.publicHistoryMessage);
|
|
121
|
+
const promptEntries = Array.isArray(extra.promptEntries)
|
|
122
|
+
? extra.promptEntries
|
|
123
|
+
: _deps._wallePromptEntriesForSessionUi(history, windowStart);
|
|
124
|
+
const turnFields = require('./walle-turn-projection').walleTurnResponseFields(messages, {
|
|
125
|
+
scope: extra.mode || options.mode ? 'page' : 'full',
|
|
126
|
+
});
|
|
127
|
+
const historyIntegrity = require('../public/js/walle-history-integrity')
|
|
128
|
+
.buildWalleHistoryState(messages, {
|
|
129
|
+
headUuid: extra.headUuid || '',
|
|
130
|
+
hasOlder: extra.hasMore === true,
|
|
131
|
+
projectionValid: extra.projection?.valid === true,
|
|
132
|
+
});
|
|
133
|
+
const correlation = _deps._walleHistoryCorrelationFields({
|
|
134
|
+
...options,
|
|
135
|
+
mode: extra.mode || options.mode,
|
|
136
|
+
});
|
|
137
|
+
const payload = {
|
|
138
|
+
contractVersion: 2,
|
|
139
|
+
type: 'walle-history',
|
|
140
|
+
id,
|
|
141
|
+
messages,
|
|
142
|
+
promptEntries,
|
|
143
|
+
promptCount: Number.isFinite(extra.promptCount) ? Number(extra.promptCount) : promptEntries.length,
|
|
144
|
+
integrity: {
|
|
145
|
+
schemaVersion: 1,
|
|
146
|
+
counts: historyIntegrity.counts,
|
|
147
|
+
activeHeadUuid: historyIntegrity.activeHeadUuid || '',
|
|
148
|
+
diagnosticEventIds: historyIntegrity.diagnosticEvents
|
|
149
|
+
.map((message) => message.uuid || message.id || '')
|
|
150
|
+
.filter(Boolean),
|
|
151
|
+
},
|
|
152
|
+
...turnFields,
|
|
153
|
+
...correlation,
|
|
154
|
+
request: {
|
|
155
|
+
mode: correlation.historyMode,
|
|
156
|
+
requestedCursor: correlation.requestedCursor,
|
|
157
|
+
requestedGeneration: correlation.requestedGeneration,
|
|
158
|
+
requestedOrderingGeneration: correlation.requestedOrderingGeneration,
|
|
159
|
+
},
|
|
160
|
+
source: extra.source || options.source || 'walle-history',
|
|
161
|
+
cacheFresh: extra.cacheFresh,
|
|
162
|
+
stale: extra.stale,
|
|
163
|
+
// Windowing metadata (OpenCode-style): the client renders this page and lazy-loads older on
|
|
164
|
+
// scroll-up. `mode` 'replace' (initial/newest) vs 'prepend' (older page). Absent total ⇒ a
|
|
165
|
+
// legacy (non-windowed) serve; the client treats it as the full set.
|
|
166
|
+
total: Number.isFinite(extra.total) ? extra.total : undefined,
|
|
167
|
+
hasMore: extra.hasMore === true ? true : (extra.total != null ? false : undefined),
|
|
168
|
+
offset: Number.isFinite(extra.offset) ? extra.offset : undefined,
|
|
169
|
+
mode: extra.mode || undefined,
|
|
170
|
+
...require('./session-messages-page').walleHistoryPageFields(extra),
|
|
171
|
+
};
|
|
172
|
+
const projection = require('./session-messages-projection');
|
|
173
|
+
const coverage = projection.conversationPageCoverage({
|
|
174
|
+
offset: payload.offset,
|
|
175
|
+
has_more: payload.hasMore,
|
|
176
|
+
olderCursor: payload.olderCursor,
|
|
177
|
+
newerCursor: payload.newerCursor,
|
|
178
|
+
projectionEpoch: payload.projection?.epoch,
|
|
179
|
+
orderingEpoch: payload.projection?.orderingEpoch,
|
|
180
|
+
settled: extra.degraded === true ? false : extra.settled,
|
|
181
|
+
partial: extra.partial,
|
|
182
|
+
stale: payload.stale,
|
|
183
|
+
catchingUp: extra.catchingUp === true,
|
|
184
|
+
// D-2/S-4 (WP-0): a lag-only catch-up page carries its measured lag so WP-1's
|
|
185
|
+
// conversationPageCoverage can render the catch-up lifecycle from a declared lag instead
|
|
186
|
+
// of a synthesized gap.
|
|
187
|
+
lag: extra.lag || null,
|
|
188
|
+
degraded: extra.degraded,
|
|
189
|
+
degradedReason: extra.degradedReason,
|
|
190
|
+
readiness: extra.readiness,
|
|
191
|
+
}, messages);
|
|
192
|
+
const identity = _deps._publicTimelineIdentity(_deps._resolveSessionTimelineIdentity(id));
|
|
193
|
+
payload.coverage = coverage;
|
|
194
|
+
payload.timelineIdentity = identity;
|
|
195
|
+
Object.assign(payload, projection.conversationLifecycleEnvelope({
|
|
196
|
+
...payload,
|
|
197
|
+
coverage,
|
|
198
|
+
timelineIdentity: identity,
|
|
199
|
+
catchingUp: extra.catchingUp,
|
|
200
|
+
degraded: extra.degraded,
|
|
201
|
+
degradedReason: extra.degradedReason,
|
|
202
|
+
settled: extra.degraded === true ? false : extra.settled,
|
|
203
|
+
readiness: extra.readiness,
|
|
204
|
+
}));
|
|
205
|
+
// WP-3 (D-5, §6): the envelope gains keyRange so the client can render the gap pill
|
|
206
|
+
// from a DECLARED range instead of inferring it. Flag-gated: kill-switch OFF keeps the
|
|
207
|
+
// envelope byte-shape unchanged (no keyRange field at all).
|
|
208
|
+
if (_deps.CTM_CONV_ORDER_AUTHORITY_ENABLED) payload.keyRange = _walleHistoryKeyRange(messages);
|
|
209
|
+
return payload;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function _noteWalleHistoryCatchUp(source, lag, turnOpen) {
|
|
213
|
+
const id = source?.ctmSessionId;
|
|
214
|
+
if (!id) return;
|
|
215
|
+
const now = Date.now();
|
|
216
|
+
let episode = _deps._walleHistoryCatchUpEpisodes.get(id);
|
|
217
|
+
if (!episode) {
|
|
218
|
+
episode = { firstSeenMs: now, lastRecordedAt: 0, lastStallLoggedAt: 0, lastTouchedMs: now };
|
|
219
|
+
_deps._walleHistoryCatchUpEpisodes.set(id, episode);
|
|
220
|
+
}
|
|
221
|
+
episode.lastTouchedMs = now;
|
|
222
|
+
if (now - episode.lastRecordedAt >= 30_000) {
|
|
223
|
+
episode.lastRecordedAt = now;
|
|
224
|
+
_deps.recordSessionDiagnostic(id, 'walle-history-catchup', {
|
|
225
|
+
lagBytes: Number(lag?.bytes) || 0,
|
|
226
|
+
lagSeconds: Number(lag?.seconds) || 0,
|
|
227
|
+
turnOpen: !!turnOpen,
|
|
228
|
+
firstSeenMs: episode.firstSeenMs,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (turnOpen) return;
|
|
232
|
+
_deps._scheduleWalleSessionRowsCatchUp(source, 'walle-history-catchup');
|
|
233
|
+
if (now - episode.firstSeenMs >= 60_000 && now - episode.lastStallLoggedAt >= 300_000) {
|
|
234
|
+
episode.lastStallLoggedAt = now;
|
|
235
|
+
console.error(`[walle-history] catch-up stalled session=${String(id).slice(0, 8)} `
|
|
236
|
+
+ `lagBytes=${Number(lag?.bytes) || 0} lagSeconds=${Number(lag?.seconds) || 0} `
|
|
237
|
+
+ `sinceMs=${now - episode.firstSeenMs}`);
|
|
238
|
+
_deps._scheduleWalleSessionRowsCatchUp(source, 'walle-history-catchup-stalled');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function _noteWalleHistoryCursorExpired(sessionId, details) {
|
|
243
|
+
if (!sessionId) return;
|
|
244
|
+
const now = Date.now();
|
|
245
|
+
const lastAt = _deps._walleHistoryCursorExpiredDiagnosticAt.get(sessionId) || 0;
|
|
246
|
+
if (now - lastAt < 30_000) return;
|
|
247
|
+
_deps._walleHistoryCursorExpiredDiagnosticAt.set(sessionId, now);
|
|
248
|
+
_deps.recordSessionDiagnostic(sessionId, 'walle-history-cursor-expired', details);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function _sendWalleHistoryReply(ws, payload, sessionId = '') {
|
|
252
|
+
const id = String(sessionId || payload?.id || '').trim();
|
|
253
|
+
const result = _deps._wsSend(ws, payload, _deps.CTM_WS_SOLICITED_REPLY_INTERACTIVE_ENABLED ? {
|
|
254
|
+
class: 'interactive',
|
|
255
|
+
channel: 'walle-history',
|
|
256
|
+
sessionId: id,
|
|
257
|
+
} : { channel: 'walle-history', sessionId: id });
|
|
258
|
+
const counterKey = _deps._WS_ADMISSION_COUNTER_KEY[result];
|
|
259
|
+
if (counterKey) _deps._wsSolicitedReplyCounters[counterKey] += 1;
|
|
260
|
+
if (result !== _deps.ADMISSION_RESULTS.SENT && id) {
|
|
261
|
+
_deps.recordSessionDiagnostic(id, 'walle-history-reply-dropped', {
|
|
262
|
+
result,
|
|
263
|
+
channel: 'walle-history',
|
|
264
|
+
});
|
|
265
|
+
_deps.errorSink.report('walle-history:reply-dropped', Object.assign(new Error(result), {
|
|
266
|
+
code: 'CTM_WALLE_HISTORY_REPLY_DROPPED',
|
|
267
|
+
}), { sessionId: id, result });
|
|
268
|
+
}
|
|
269
|
+
return result;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function _sendWalleHistoryErrorFrame(ws, sessionId, options = {}, error = null) {
|
|
273
|
+
if (!ws || ws.readyState !== 1) return _deps.ADMISSION_RESULTS.DROPPED_BACKPRESSURE;
|
|
274
|
+
const id = String(sessionId || '').trim();
|
|
275
|
+
const code = String(error?.code || error?.message || 'walle_history_failed');
|
|
276
|
+
const correlation = _deps._walleHistoryCorrelationFields(options);
|
|
277
|
+
return _sendWalleHistoryReply(ws, JSON.stringify({
|
|
278
|
+
type: 'walle-history',
|
|
279
|
+
id,
|
|
280
|
+
messages: [],
|
|
281
|
+
...correlation,
|
|
282
|
+
mode: correlation.historyMode,
|
|
283
|
+
request: {
|
|
284
|
+
mode: correlation.historyMode,
|
|
285
|
+
requestedCursor: correlation.requestedCursor,
|
|
286
|
+
requestedGeneration: correlation.requestedGeneration,
|
|
287
|
+
requestedOrderingGeneration: correlation.requestedOrderingGeneration,
|
|
288
|
+
},
|
|
289
|
+
source: options.source || 'walle-history',
|
|
290
|
+
error: code,
|
|
291
|
+
degraded: true,
|
|
292
|
+
degradedReason: 'internal_error',
|
|
293
|
+
projection: {
|
|
294
|
+
valid: true,
|
|
295
|
+
revalidating: true,
|
|
296
|
+
status: 'missing',
|
|
297
|
+
error: '',
|
|
298
|
+
staleReason: 'no_verdict',
|
|
299
|
+
epoch: 0,
|
|
300
|
+
},
|
|
301
|
+
}), id);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async function _sendWalleSessionHistory(ws, session, options = {}) {
|
|
305
|
+
if (!ws || ws.readyState !== 1 || !session) return false;
|
|
306
|
+
const budget = _deps.createHistoryLaneBudget(options.deadlineMs);
|
|
307
|
+
const source = await _deps._resolveWalleHistorySourceOffThread(session);
|
|
308
|
+
if (!source) {
|
|
309
|
+
const correlation = _deps._walleHistoryCorrelationFields(options);
|
|
310
|
+
_sendWalleHistoryReply(ws, JSON.stringify({
|
|
311
|
+
type: 'walle-history',
|
|
312
|
+
id: typeof session === 'object' ? session.id : session,
|
|
313
|
+
messages: [],
|
|
314
|
+
...correlation,
|
|
315
|
+
request: {
|
|
316
|
+
mode: correlation.historyMode,
|
|
317
|
+
requestedCursor: correlation.requestedCursor,
|
|
318
|
+
requestedGeneration: correlation.requestedGeneration,
|
|
319
|
+
requestedOrderingGeneration: correlation.requestedOrderingGeneration,
|
|
320
|
+
},
|
|
321
|
+
source: options.source || 'walle-history',
|
|
322
|
+
error: 'not_walle_session',
|
|
323
|
+
degraded: true,
|
|
324
|
+
degradedReason: 'not_walle_session',
|
|
325
|
+
projection: {
|
|
326
|
+
valid: true,
|
|
327
|
+
revalidating: true,
|
|
328
|
+
status: 'missing',
|
|
329
|
+
error: '',
|
|
330
|
+
staleReason: 'no_verdict',
|
|
331
|
+
epoch: 0,
|
|
332
|
+
},
|
|
333
|
+
}), typeof session === 'object' ? session.id : session);
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// OpenCode-style windowing: the client requests a small newest page (offset 0, limit ~60) and
|
|
338
|
+
// lazy-loads older pages (offset bumps, mode 'prepend') on scroll-up. Serializing just the page
|
|
339
|
+
// — not the whole ~23MB history — is what removes the main-loop JSON.stringify block measured in
|
|
340
|
+
// the /ctm-dev E2E. Missing or oversized limits are clamped to the bounded server page.
|
|
341
|
+
const offset = Math.max(0, Number(options.offset) || 0);
|
|
342
|
+
const historyParentAdoptionEnabled = process.env.WALLE_HISTORY_REPAIR !== '0';
|
|
343
|
+
const beforeRaw = String(options.before || '').trim();
|
|
344
|
+
// Preserve an over-limit value as invalid while bounding what crosses the
|
|
345
|
+
// read-pool boundary; decodeWalleHistoryCursor rejects anything over 2048.
|
|
346
|
+
const before = beforeRaw.length > 2048 ? beforeRaw.slice(0, 2049) : beforeRaw;
|
|
347
|
+
const afterCursorRaw = historyParentAdoptionEnabled ? String(options.afterCursor || '').trim() : '';
|
|
348
|
+
const afterCursor = afterCursorRaw.length > 2048 ? afterCursorRaw.slice(0, 2049) : afterCursorRaw;
|
|
349
|
+
const around = historyParentAdoptionEnabled ? String(options.around || '').trim().slice(0, 200) : '';
|
|
350
|
+
const afterRaw = String(options.historyWatermark || options.after || '').trim();
|
|
351
|
+
const after = afterRaw.length > 200 ? afterRaw.slice(0, 200) : afterRaw;
|
|
352
|
+
const projectionEpoch = Math.max(0, Number(options.projectionEpoch) || 0);
|
|
353
|
+
// Thread orderingEpoch end-to-end (D-1 ledger row 3): additive-only, same clamp as
|
|
354
|
+
// projectionEpoch, so getWalleHistoryDelta can fence an ordering-epoch change without
|
|
355
|
+
// refusing on a plain projection-epoch bump.
|
|
356
|
+
const orderingEpoch = Math.max(0, Number(options.orderingEpoch) || 0);
|
|
357
|
+
const requestedLimit = Number.isFinite(Number(options.limit)) ? Number(options.limit) : 0;
|
|
358
|
+
const limit = Math.min(_deps.WALLE_HISTORY_SERIALIZE_MAX_MESSAGES,
|
|
359
|
+
requestedLimit > 0 ? requestedLimit : _deps.WALLE_HISTORY_SERIALIZE_MAX_MESSAGES);
|
|
360
|
+
const requestedMode = options.mode === 'prepend'
|
|
361
|
+
? 'prepend'
|
|
362
|
+
: (options.mode === 'around' && around
|
|
363
|
+
? 'around'
|
|
364
|
+
: (options.mode === 'newer' && afterCursor
|
|
365
|
+
? 'newer'
|
|
366
|
+
: (options.mode === 'append' && after && projectionEpoch > 0 ? 'append' : 'replace')));
|
|
367
|
+
const projectionLag = _deps._walleSessionRowsFreshness(source);
|
|
368
|
+
const sendHistory = (history, src, extra = {}) => {
|
|
369
|
+
if (ws.readyState !== 1) return;
|
|
370
|
+
const payloadExtra = { ...extra };
|
|
371
|
+
const prewindowed = payloadExtra.prewindowed === true;
|
|
372
|
+
delete payloadExtra.prewindowed;
|
|
373
|
+
const suppliedPromptEntries = payloadExtra.promptEntries;
|
|
374
|
+
delete payloadExtra.promptEntries;
|
|
375
|
+
const suppliedPromptCount = payloadExtra.promptCount;
|
|
376
|
+
delete payloadExtra.promptCount;
|
|
377
|
+
const responseMode = payloadExtra.responseMode || requestedMode;
|
|
378
|
+
delete payloadExtra.responseMode;
|
|
379
|
+
const promptEntries = Array.isArray(suppliedPromptEntries)
|
|
380
|
+
? suppliedPromptEntries
|
|
381
|
+
: _deps._wallePromptEntriesForSessionUi(history);
|
|
382
|
+
let win;
|
|
383
|
+
if (prewindowed) {
|
|
384
|
+
win = {
|
|
385
|
+
window: Array.isArray(history) ? history : [],
|
|
386
|
+
total: Math.max(0, Number(payloadExtra.total) || 0),
|
|
387
|
+
hasMore: payloadExtra.hasMore === true,
|
|
388
|
+
offset: Math.max(0, Number(payloadExtra.offset) || 0),
|
|
389
|
+
start: Math.max(0, Number(payloadExtra.windowStart) || 0),
|
|
390
|
+
};
|
|
391
|
+
} else {
|
|
392
|
+
const pageHelpers = require('./session-messages-page');
|
|
393
|
+
const { buildProjectionManifest, WALLE_HISTORY_PROJECTOR_VERSION } = require('./walle-history-projection');
|
|
394
|
+
const sourceRows = Array.isArray(history) ? history : [];
|
|
395
|
+
const sourceManifest = buildProjectionManifest(_deps._walleHistoryForReview(sourceRows));
|
|
396
|
+
payloadExtra.projection = {
|
|
397
|
+
valid: sourceManifest.valid,
|
|
398
|
+
revalidating: false,
|
|
399
|
+
status: 'source',
|
|
400
|
+
version: WALLE_HISTORY_PROJECTOR_VERSION,
|
|
401
|
+
epoch: 0,
|
|
402
|
+
rowCount: sourceManifest.rowCount,
|
|
403
|
+
identityDigest: sourceManifest.identityDigest,
|
|
404
|
+
error: sourceManifest.error || '',
|
|
405
|
+
staleReason: '',
|
|
406
|
+
};
|
|
407
|
+
if (sourceManifest.valid === false) {
|
|
408
|
+
_deps._scheduleWalleProjectionRepair(source.ctmSessionId, 'walle-history-source-structural');
|
|
409
|
+
}
|
|
410
|
+
// Invalid topology is still paginated: the projection metadata forces the
|
|
411
|
+
// client into audit mode, while the cursor lets a large damaged transcript
|
|
412
|
+
// reveal every event without one unbounded main-loop serialization.
|
|
413
|
+
const sourceWindow = pageHelpers.getWalleSourceHistoryWindow(sourceRows, {
|
|
414
|
+
sessionId: source.ctmSessionId,
|
|
415
|
+
offset,
|
|
416
|
+
limit,
|
|
417
|
+
before,
|
|
418
|
+
afterCursor,
|
|
419
|
+
around,
|
|
420
|
+
});
|
|
421
|
+
win = {
|
|
422
|
+
window: sourceWindow.messages,
|
|
423
|
+
total: sourceWindow.total,
|
|
424
|
+
hasMore: sourceWindow.hasMore,
|
|
425
|
+
offset: sourceWindow.offset,
|
|
426
|
+
start: sourceWindow.windowStart,
|
|
427
|
+
};
|
|
428
|
+
Object.assign(payloadExtra, pageHelpers.walleHistoryPageFields(sourceWindow));
|
|
429
|
+
}
|
|
430
|
+
const openActivity = _deps._walleOpenTurnActivityForNewestPage(
|
|
431
|
+
typeof session === 'object' && session ? session : _deps.sessions.get(String(session || '')),
|
|
432
|
+
source,
|
|
433
|
+
{ mode: responseMode, offset: win.offset, before, around, hasMoreNewer: payloadExtra.hasMoreNewer },
|
|
434
|
+
);
|
|
435
|
+
if (openActivity) win = { ...win, window: [...win.window, openActivity] };
|
|
436
|
+
let serializedChars = 0;
|
|
437
|
+
const serialized = _deps._perfTracker.runSyncProbed('walleWsHistory:serialize', () => {
|
|
438
|
+
const json = JSON.stringify(_walleHistoryPayload(session, win.window, options, {
|
|
439
|
+
source: options.source || src,
|
|
440
|
+
cacheFresh: payloadExtra.cacheFresh !== undefined
|
|
441
|
+
? payloadExtra.cacheFresh
|
|
442
|
+
: payloadExtra.settled === true,
|
|
443
|
+
total: win.total,
|
|
444
|
+
hasMore: win.hasMore,
|
|
445
|
+
offset: win.offset,
|
|
446
|
+
windowStart: win.start,
|
|
447
|
+
promptEntries,
|
|
448
|
+
promptCount: Number.isFinite(Number(suppliedPromptCount))
|
|
449
|
+
? Number(suppliedPromptCount)
|
|
450
|
+
: promptEntries.length,
|
|
451
|
+
mode: responseMode,
|
|
452
|
+
historyParentAdoptionEnabled,
|
|
453
|
+
// One-release compatibility for clients predating the terminology fix.
|
|
454
|
+
historyRepairEnabled: historyParentAdoptionEnabled,
|
|
455
|
+
projectionLagBytes: Math.max(0, Number(projectionLag.lagBytes || 0)),
|
|
456
|
+
projectionLagSeconds: Math.max(0, Number(projectionLag.lagSeconds || 0)),
|
|
457
|
+
...payloadExtra,
|
|
458
|
+
}));
|
|
459
|
+
serializedChars = json.length;
|
|
460
|
+
return json;
|
|
461
|
+
}, { context: () => ({
|
|
462
|
+
msgs: Array.isArray(win.window) ? win.window.length : 0,
|
|
463
|
+
total: win.total,
|
|
464
|
+
src,
|
|
465
|
+
serializedChars,
|
|
466
|
+
}) });
|
|
467
|
+
return _sendWalleHistoryReply(ws, serialized, source.ctmSessionId);
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// (1) Durable row store under the canonical ctm id — fresh ⇒ serve without touching the JSONL.
|
|
471
|
+
// D-12: degradedReason is honesty about what actually happened during THIS
|
|
472
|
+
// read, not a precomputed guess seeded from options.noCache — a client
|
|
473
|
+
// passing noCache:true (WP-4's auto-retry does exactly this) is asking to
|
|
474
|
+
// skip the fresh row-store lane below, not asserting that the read is
|
|
475
|
+
// degraded. Only a real miss (rowHistory.__miss / stale.__miss) sets this now.
|
|
476
|
+
let degradedReason = '';
|
|
477
|
+
if (options.noCache !== true) {
|
|
478
|
+
// D-4 (WP-0): the P11 byte-identical retry that used to sit here (a second, identical
|
|
479
|
+
// off-thread read whenever the first came back watermarkStale) is deleted -- D-1 makes
|
|
480
|
+
// getWalleHistoryDelta resolve the anchor before ever refusing, so a repeat read with the
|
|
481
|
+
// SAME inputs could only ever reproduce the SAME reply. It never healed anything; it only
|
|
482
|
+
// doubled read cost and hid the true cause behind a generic degraded page.
|
|
483
|
+
const rowHistory = await _deps._walleRowHistoryForCtmId(source, {
|
|
484
|
+
offset,
|
|
485
|
+
limit,
|
|
486
|
+
before,
|
|
487
|
+
afterCursor: requestedMode === 'newer' ? afterCursor : '',
|
|
488
|
+
around: requestedMode === 'around' ? around : '',
|
|
489
|
+
after: requestedMode === 'append' ? after : '',
|
|
490
|
+
projectionEpoch,
|
|
491
|
+
orderingEpoch: requestedMode === 'append' ? orderingEpoch : 0,
|
|
492
|
+
budget,
|
|
493
|
+
});
|
|
494
|
+
if (rowHistory?.__miss) degradedReason = rowHistory.__miss;
|
|
495
|
+
if (limit > 0 && rowHistory && Array.isArray(rowHistory.messages)) {
|
|
496
|
+
// S-8 (WP-0): a cursor/watermark expiry is a THIRD lane, distinct from both catching-up
|
|
497
|
+
// and complete -- it must not enter the catch-up lifecycle (no _noteWalleHistoryCatchUp,
|
|
498
|
+
// no _resetWalleHistoryCatchUpEpisode: an expiry says nothing about lag) and must not
|
|
499
|
+
// report settled:true (nothing was actually served).
|
|
500
|
+
const expired = rowHistory.cursorStale === true || rowHistory.error === 'cursor_expired';
|
|
501
|
+
// D-2/S-4 (WP-0): rowHistory.catchingUp === true means catchUpKind classified this v2
|
|
502
|
+
// window as 'lag' -- renderable, complete-to-its-cursor history that is not a miss. It
|
|
503
|
+
// gets the SAME extras as a complete page except for the catch-up lifecycle markers
|
|
504
|
+
// below; a fresh (non-catching-up) page closes out any open lag episode for the session.
|
|
505
|
+
const catchingUp = !expired && rowHistory.catchingUp === true;
|
|
506
|
+
if (expired) {
|
|
507
|
+
_noteWalleHistoryCursorExpired(source.ctmSessionId, {
|
|
508
|
+
expiredReason: rowHistory.expiredReason,
|
|
509
|
+
requestedEpoch: projectionEpoch,
|
|
510
|
+
servedEpoch: rowHistory.projection?.epoch,
|
|
511
|
+
});
|
|
512
|
+
} else if (catchingUp) {
|
|
513
|
+
// D-3 review fix: the production call site (handleWalleHistoryRequest) passes a bare
|
|
514
|
+
// session id STRING here, not the session object -- this function already branches on
|
|
515
|
+
// `typeof session === 'object'` above for exactly that reason. Resolve the LIVE session
|
|
516
|
+
// from the session map so turnOpen reflects reality instead of always reading undefined
|
|
517
|
+
// off a string.
|
|
518
|
+
const liveSession = typeof session === 'object' && session
|
|
519
|
+
? session
|
|
520
|
+
: _deps.sessions.get(String(session || ''));
|
|
521
|
+
_noteWalleHistoryCatchUp(source, rowHistory.lag, !!liveSession?.abortController);
|
|
522
|
+
} else {
|
|
523
|
+
_deps._resetWalleHistoryCatchUpEpisode(source.ctmSessionId);
|
|
524
|
+
}
|
|
525
|
+
sendHistory(rowHistory.messages, 'walle-session-rows', {
|
|
526
|
+
prewindowed: true,
|
|
527
|
+
total: rowHistory.total,
|
|
528
|
+
hasMore: rowHistory.hasMore,
|
|
529
|
+
offset: rowHistory.offset,
|
|
530
|
+
windowStart: rowHistory.windowStart,
|
|
531
|
+
promptEntries: rowHistory.promptEntries,
|
|
532
|
+
promptCount: rowHistory.promptCount,
|
|
533
|
+
olderCursor: rowHistory.olderCursor,
|
|
534
|
+
newerCursor: rowHistory.newerCursor,
|
|
535
|
+
hasMoreNewer: rowHistory.hasMoreNewer === true,
|
|
536
|
+
windowEnd: rowHistory.windowEnd,
|
|
537
|
+
firstMessageIndex: rowHistory.firstMessageIndex,
|
|
538
|
+
lastMessageIndex: rowHistory.lastMessageIndex,
|
|
539
|
+
// S-32b: getWalleHistoryDelta's watermark-miss reply (append/newer mode) sets
|
|
540
|
+
// watermarkStale/error:'watermark_stale' — a DIFFERENT field than the cursor-miss
|
|
541
|
+
// cursorStale/error:'cursor_stale' the client's stale-recovery branches already key off
|
|
542
|
+
// (handleHistoryPrepend, and WP-6's handleHistoryAppend). Fold it into the same signal
|
|
543
|
+
// the client understands instead of silently shipping an empty "loaded" page.
|
|
544
|
+
cursorStale: expired || require('./session-messages-page').walleReplyCursorStale(rowHistory),
|
|
545
|
+
expiredReason: rowHistory.expiredReason || undefined,
|
|
546
|
+
resume: rowHistory.resume || undefined,
|
|
547
|
+
epochAdvanced: rowHistory.epochAdvanced === true || undefined,
|
|
548
|
+
newerRemaining: Math.max(0, Number(rowHistory.newerRemaining) || 0),
|
|
549
|
+
projection: rowHistory.projection,
|
|
550
|
+
// WP-5 (S-29): honest fallback marker — set when the served store's cutover is not
|
|
551
|
+
// 'active' (getSelectedWalleHistoryWindow), null/undefined otherwise.
|
|
552
|
+
importProgress: rowHistory.importProgress || undefined,
|
|
553
|
+
error: rowHistory.error || undefined,
|
|
554
|
+
// H1b-v2 (§10.22): forward ONLY the producer's own conditional observation properties.
|
|
555
|
+
...(Object.hasOwn(rowHistory, 'historyViewProof') ? { historyViewProof: rowHistory.historyViewProof } : {}),
|
|
556
|
+
...(Object.hasOwn(rowHistory, 'historyViewProofError') ? { historyViewProofError: rowHistory.historyViewProofError } : {}),
|
|
557
|
+
...(Object.hasOwn(rowHistory, 'resumeHistoryViewProof') ? { resumeHistoryViewProof: rowHistory.resumeHistoryViewProof } : {}),
|
|
558
|
+
...(Object.hasOwn(rowHistory, 'resumeHistoryViewProofError') ? { resumeHistoryViewProofError: rowHistory.resumeHistoryViewProofError } : {}),
|
|
559
|
+
responseMode: rowHistory.mode === 'append' ? 'append' : requestedMode,
|
|
560
|
+
promptMode: rowHistory.mode === 'append' ? 'append' : requestedMode,
|
|
561
|
+
...(expired
|
|
562
|
+
? {
|
|
563
|
+
settled: false,
|
|
564
|
+
cacheFresh: false,
|
|
565
|
+
stale: false,
|
|
566
|
+
catchingUp: false,
|
|
567
|
+
degraded: false,
|
|
568
|
+
readiness: { reason: 'cursor_expired' },
|
|
569
|
+
}
|
|
570
|
+
: catchingUp
|
|
571
|
+
? {
|
|
572
|
+
settled: false,
|
|
573
|
+
cacheFresh: false,
|
|
574
|
+
stale: true,
|
|
575
|
+
catchingUp: true,
|
|
576
|
+
degraded: false,
|
|
577
|
+
readiness: { reason: 'rows_behind' },
|
|
578
|
+
lag: { bytes: rowHistory.lag.bytes, seconds: rowHistory.lag.seconds },
|
|
579
|
+
}
|
|
580
|
+
: {
|
|
581
|
+
settled: true,
|
|
582
|
+
readiness: { reason: 'complete' },
|
|
583
|
+
}),
|
|
584
|
+
});
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
if (Array.isArray(rowHistory) && rowHistory.length > 0) {
|
|
588
|
+
sendHistory(rowHistory, 'walle-session-rows', {
|
|
589
|
+
settled: true,
|
|
590
|
+
readiness: { reason: 'complete' },
|
|
591
|
+
});
|
|
592
|
+
return true;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// (2) Stale/missing rows: render the last committed page and schedule the
|
|
597
|
+
// uniform incremental source importer. A request path never parses an
|
|
598
|
+
// enrolled append log or writes a reconstructed snapshot.
|
|
599
|
+
try {
|
|
600
|
+
_deps._scheduleWalleSessionRowsCatchUp(source, 'walle-history-attach');
|
|
601
|
+
const stale = await _deps._walleRowHistoryForCtmId(source, {
|
|
602
|
+
offset,
|
|
603
|
+
limit,
|
|
604
|
+
before,
|
|
605
|
+
afterCursor: requestedMode === 'newer' ? afterCursor : '',
|
|
606
|
+
around: requestedMode === 'around' ? around : '',
|
|
607
|
+
after: requestedMode === 'append' ? after : '',
|
|
608
|
+
projectionEpoch,
|
|
609
|
+
orderingEpoch: requestedMode === 'append' ? orderingEpoch : 0,
|
|
610
|
+
allowStale: true,
|
|
611
|
+
budget,
|
|
612
|
+
budgetRung: 'stale',
|
|
613
|
+
});
|
|
614
|
+
if (stale?.__miss) degradedReason = stale.__miss; if (stale?.__miss === 'projection_empty' && Array.isArray(stale.fallbackRows) && stale.fallbackRows.length > 0) { sendHistory(stale.fallbackRows, 'walle-session-rows-syncing', { cacheFresh: false, settled: false, stale: true, catchingUp: true, degraded: true, degradedReason: 'projection_empty', readiness: { reason: 'rows_behind' } }); return true; } // P1-1: an empty v2 projection over a non-empty transcript serves the raw fold instead of the source_unavailable page below
|
|
615
|
+
if (limit > 0 && stale && Array.isArray(stale.messages)) {
|
|
616
|
+
// D-12: an honest label for a miss with no classified cause, not a
|
|
617
|
+
// borrowed 'freshness_gate' — that reason belongs to the freshness
|
|
618
|
+
// predicates in _walleRowHistoryForCtmId, which set degradedReason
|
|
619
|
+
// themselves (via __miss) when they actually fire.
|
|
620
|
+
const reason = degradedReason || 'unknown_miss';
|
|
621
|
+
// Fix round 1 (WP-0 review): the stale lane can ALSO serve an expired cursor/watermark
|
|
622
|
+
// (allowStale:true does not bypass D-1's own refusal reasons) -- a zero-row expiry here
|
|
623
|
+
// is exactly as much "not a lag frame" as it is in the fresh lane (D-6), so it must not
|
|
624
|
+
// be stamped catchingUp:true, and must carry expiredReason/resume for WP-1.
|
|
625
|
+
const staleExpired = stale.cursorStale === true || stale.error === 'cursor_expired';
|
|
626
|
+
sendHistory(stale.messages, 'walle-session-rows-syncing', {
|
|
627
|
+
prewindowed: true,
|
|
628
|
+
total: stale.total,
|
|
629
|
+
hasMore: stale.hasMore,
|
|
630
|
+
offset: stale.offset,
|
|
631
|
+
windowStart: stale.windowStart,
|
|
632
|
+
promptEntries: stale.promptEntries,
|
|
633
|
+
promptCount: stale.promptCount,
|
|
634
|
+
olderCursor: stale.olderCursor,
|
|
635
|
+
newerCursor: stale.newerCursor,
|
|
636
|
+
hasMoreNewer: stale.hasMoreNewer === true,
|
|
637
|
+
firstMessageIndex: stale.firstMessageIndex,
|
|
638
|
+
lastMessageIndex: stale.lastMessageIndex,
|
|
639
|
+
windowEnd: stale.windowEnd,
|
|
640
|
+
// S-32b: same watermarkStale->cursorStale fold as the fresh-row reply above.
|
|
641
|
+
cursorStale: staleExpired || require('./session-messages-page').walleReplyCursorStale(stale),
|
|
642
|
+
expiredReason: stale.expiredReason || undefined,
|
|
643
|
+
resume: stale.resume || undefined,
|
|
644
|
+
projection: stale.projection,
|
|
645
|
+
importProgress: stale.importProgress || undefined,
|
|
646
|
+
error: stale.error || undefined,
|
|
647
|
+
// H1b-v2 (§10.22): the same four OWN observation properties, forwarded from this lane's
|
|
648
|
+
// own page object. An unobserved page adds nothing here (no absent identity is minted).
|
|
649
|
+
...(Object.hasOwn(stale, 'historyViewProof') ? { historyViewProof: stale.historyViewProof } : {}),
|
|
650
|
+
...(Object.hasOwn(stale, 'historyViewProofError') ? { historyViewProofError: stale.historyViewProofError } : {}),
|
|
651
|
+
...(Object.hasOwn(stale, 'resumeHistoryViewProof') ? { resumeHistoryViewProof: stale.resumeHistoryViewProof } : {}),
|
|
652
|
+
...(Object.hasOwn(stale, 'resumeHistoryViewProofError') ? { resumeHistoryViewProofError: stale.resumeHistoryViewProofError } : {}),
|
|
653
|
+
cacheFresh: false,
|
|
654
|
+
settled: false,
|
|
655
|
+
// The source is being revalidated, but these committed rows are still
|
|
656
|
+
// a usable durable snapshot. Reserve source_unavailable for the branch
|
|
657
|
+
// below where no rows can be served at all.
|
|
658
|
+
readiness: { reason: staleExpired ? 'cursor_expired' : 'rows_behind' },
|
|
659
|
+
stale: true,
|
|
660
|
+
catchingUp: !staleExpired,
|
|
661
|
+
// WP-3 (D-5): degradedReason is honesty, not a feature — a stale/degraded page
|
|
662
|
+
// always carries the reason it's degraded so the client renders the gap pill
|
|
663
|
+
// from the declared range instead of guessing. Never flag-gated (the flag that
|
|
664
|
+
// used to gate this, CTM_WALLE_HISTORY_DEGRADED_HONESTY, is retired).
|
|
665
|
+
// I-2 (final review): an expiry is a THIRD lane, not a fault (D-2) — the stale
|
|
666
|
+
// lane must ship the same degraded:false/no-degradedReason contract the fresh
|
|
667
|
+
// lane already does, or the live degraded-rate metric this design is gated on
|
|
668
|
+
// (AC-1e/AC-4c) goes blind to every expiry that lands on this lane.
|
|
669
|
+
degraded: !staleExpired,
|
|
670
|
+
...(staleExpired ? {} : { degradedReason: reason }),
|
|
671
|
+
responseMode: requestedMode,
|
|
672
|
+
});
|
|
673
|
+
if (staleExpired) {
|
|
674
|
+
_noteWalleHistoryCursorExpired(source.ctmSessionId, {
|
|
675
|
+
expiredReason: stale.expiredReason,
|
|
676
|
+
requestedEpoch: projectionEpoch,
|
|
677
|
+
servedEpoch: stale.projection?.epoch,
|
|
678
|
+
});
|
|
679
|
+
} else {
|
|
680
|
+
_deps.recordSessionDiagnostic(source.ctmSessionId, 'walle-history-degraded', { reason });
|
|
681
|
+
}
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
const reason = stale?.__miss || degradedReason || budget.reason() || 'meta_unavailable';
|
|
685
|
+
sendHistory(Array.isArray(stale) ? stale : [], 'walle-session-rows-syncing', {
|
|
686
|
+
cacheFresh: false,
|
|
687
|
+
settled: false,
|
|
688
|
+
readiness: { reason: 'source_unavailable' },
|
|
689
|
+
stale: true,
|
|
690
|
+
catchingUp: true,
|
|
691
|
+
// WP-3 (D-5): see the matching comment on the rows_behind branch above — always on.
|
|
692
|
+
degraded: true,
|
|
693
|
+
degradedReason: reason,
|
|
694
|
+
responseMode: 'replace',
|
|
695
|
+
});
|
|
696
|
+
_deps.recordSessionDiagnostic(source.ctmSessionId, 'walle-history-degraded', { reason });
|
|
697
|
+
return true;
|
|
698
|
+
} catch (e) {
|
|
699
|
+
console.error('[walle-history] rehydrate error:', e.message);
|
|
700
|
+
_sendWalleHistoryErrorFrame(ws, source.ctmSessionId, options, e);
|
|
701
|
+
return false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
function handleWalleHistoryRequest(ws, msg = {}) {
|
|
706
|
+
const id = String(msg.id || '').trim();
|
|
707
|
+
const correlation = _deps._walleHistoryCorrelationFields(msg);
|
|
708
|
+
if (!id) {
|
|
709
|
+
if (ws?.readyState === 1) {
|
|
710
|
+
_sendWalleHistoryReply(ws, JSON.stringify({
|
|
711
|
+
type: 'walle-history',
|
|
712
|
+
id,
|
|
713
|
+
messages: [],
|
|
714
|
+
...correlation,
|
|
715
|
+
request: {
|
|
716
|
+
mode: correlation.historyMode,
|
|
717
|
+
requestedCursor: correlation.requestedCursor,
|
|
718
|
+
requestedGeneration: correlation.requestedGeneration,
|
|
719
|
+
requestedOrderingGeneration: correlation.requestedOrderingGeneration,
|
|
720
|
+
},
|
|
721
|
+
error: 'missing_session_id',
|
|
722
|
+
degraded: true,
|
|
723
|
+
degradedReason: 'internal_error',
|
|
724
|
+
}), id);
|
|
725
|
+
}
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
const hasOwn = (field) => Object.prototype.hasOwnProperty.call(msg, field);
|
|
729
|
+
// H2 controller incarnation: the marker is OPTIONAL (a markerless request stays accepted --
|
|
730
|
+
// unfenced compatibility with old/qualifying callers), but an explicitly supplied malformed
|
|
731
|
+
// one -- own undefined/null/zero/fraction/non-canonical text -- is a contract fault that keeps its own null
|
|
732
|
+
// sentinel, whatever contract version the caller declares. It is never newly REQUIRED.
|
|
733
|
+
if (hasOwn('historyControllerInstanceId')
|
|
734
|
+
&& correlation.historyControllerInstanceId === null) {
|
|
735
|
+
const error = Object.assign(new Error('invalid_history_contract'), {
|
|
736
|
+
code: 'invalid_history_contract',
|
|
737
|
+
});
|
|
738
|
+
_sendWalleHistoryErrorFrame(ws, id, msg, error);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
if (correlation.historyContractVersion >= 3
|
|
742
|
+
&& ((!hasOwn('historyRequestId')
|
|
743
|
+
|| !hasOwn('historyCycleId')
|
|
744
|
+
|| !hasOwn('historyMode')
|
|
745
|
+
|| !hasOwn('historyCursor')
|
|
746
|
+
|| !hasOwn('requestedGeneration')
|
|
747
|
+
|| !hasOwn('requestedOrderingGeneration'))
|
|
748
|
+
|| !correlation.historyRequestId
|
|
749
|
+
|| !correlation.historyCycleId
|
|
750
|
+
|| !['replace', 'prepend', 'append', 'newer', 'around'].includes(correlation.historyMode))) {
|
|
751
|
+
const error = Object.assign(new Error('invalid_history_contract'), {
|
|
752
|
+
code: 'invalid_history_contract',
|
|
753
|
+
});
|
|
754
|
+
_sendWalleHistoryErrorFrame(ws, id, msg, error);
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const session = _deps.sessions.get(id);
|
|
759
|
+
const isWalleLike = !!session && _deps.isWalleLikeSession(session);
|
|
760
|
+
// WI-3 (RC-2 fix): subscribe the ws as a client of ANY existing walle-like session —
|
|
761
|
+
// INCLUDING one still `_restoreDeferred` after a restart (see subscribeWalleHistoryRequestClient
|
|
762
|
+
// for why). work-state/`session:attached` stay gated on !_restoreDeferred below since they
|
|
763
|
+
// read state that isn't populated yet for a deferred session.
|
|
764
|
+
// I-6: no PTY/terminal to attach a worker to or reset a reconnect ladder for.
|
|
765
|
+
if (session && isWalleLike && _deps._subscribeStateSyncClient(ws, id, 'walle-history-request', { skipWorkerAttach: true })) {
|
|
766
|
+
_deps.subscribeWalleHistoryRequestClient(session, ws);
|
|
767
|
+
}
|
|
768
|
+
if (session && !session._restoreDeferred && session.type === 'walle') {
|
|
769
|
+
try { _deps._sendRuntimeWorkStateToSocket(ws, id, 'history'); } catch {}
|
|
770
|
+
_deps._hydrateRuntimeGoalProjectionForSocket(ws, id, 'history-goal-hydrated');
|
|
771
|
+
_deps.sessionEvents.emit('session:attached', { id, clientCount: session.clients.length, walle: true, historyOnly: true });
|
|
772
|
+
} else if (session?._restoreDeferred && isWalleLike) {
|
|
773
|
+
_deps.recordSessionDiagnostic(id, 'walle-history-request-deferred', {
|
|
774
|
+
source: msg.reason || msg.source || 'walle-history-request',
|
|
775
|
+
clients: Array.isArray(session.clients) ? session.clients.length : 0,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// H2 controller incarnation: forwarded ONLY when the caller supplied it own, and then VERBATIM
|
|
780
|
+
// (a valid number and the explicit null sentinel both survive; never truthiness, never a
|
|
781
|
+
// default of 0). The absence case carries no key at all -- an old internal caller stays
|
|
782
|
+
// unfenced compatibility rather than being given a fabricated identity.
|
|
783
|
+
const historyControllerMarker = hasOwn('historyControllerInstanceId')
|
|
784
|
+
? { historyControllerInstanceId: msg.historyControllerInstanceId }
|
|
785
|
+
: {};
|
|
786
|
+
_sendWalleSessionHistory(ws, session?.id || id, {
|
|
787
|
+
...historyControllerMarker,
|
|
788
|
+
limit: msg.limit,
|
|
789
|
+
offset: msg.offset,
|
|
790
|
+
before: msg.before,
|
|
791
|
+
afterCursor: msg.afterCursor,
|
|
792
|
+
around: msg.around,
|
|
793
|
+
mode: msg.mode,
|
|
794
|
+
historyWatermark: msg.historyWatermark,
|
|
795
|
+
projectionEpoch: msg.projectionEpoch,
|
|
796
|
+
orderingEpoch: msg.orderingEpoch,
|
|
797
|
+
noCache: msg.noCache === true,
|
|
798
|
+
deadlineMs: msg.deadlineMs,
|
|
799
|
+
historyRequestId: msg.historyRequestId || null,
|
|
800
|
+
historyContractVersion: msg.historyContractVersion,
|
|
801
|
+
historyCycleId: msg.historyCycleId,
|
|
802
|
+
historyMode: msg.historyMode || msg.mode,
|
|
803
|
+
historyCursor: msg.historyCursor,
|
|
804
|
+
requestedGeneration: msg.requestedGeneration,
|
|
805
|
+
requestedOrderingGeneration: msg.requestedOrderingGeneration,
|
|
806
|
+
source: msg.reason || msg.source || 'walle-history-request',
|
|
807
|
+
}).catch((error) => _sendWalleHistoryErrorFrame(ws, id, {
|
|
808
|
+
...historyControllerMarker,
|
|
809
|
+
historyRequestId: msg.historyRequestId || null,
|
|
810
|
+
historyContractVersion: msg.historyContractVersion,
|
|
811
|
+
historyCycleId: msg.historyCycleId,
|
|
812
|
+
historyMode: msg.historyMode || msg.mode,
|
|
813
|
+
historyCursor: msg.historyCursor,
|
|
814
|
+
requestedGeneration: msg.requestedGeneration,
|
|
815
|
+
requestedOrderingGeneration: msg.requestedOrderingGeneration,
|
|
816
|
+
source: msg.reason || msg.source || 'walle-history-request',
|
|
817
|
+
mode: msg.mode,
|
|
818
|
+
before: msg.before,
|
|
819
|
+
afterCursor: msg.afterCursor,
|
|
820
|
+
around: msg.around,
|
|
821
|
+
historyWatermark: msg.historyWatermark,
|
|
822
|
+
projectionEpoch: msg.projectionEpoch,
|
|
823
|
+
orderingEpoch: msg.orderingEpoch,
|
|
824
|
+
}, error));
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
module.exports = {
|
|
828
|
+
configure,
|
|
829
|
+
_walleHistoryForSessionUi,
|
|
830
|
+
_walleHistoryKeyRange,
|
|
831
|
+
_walleHistoryPayload,
|
|
832
|
+
_noteWalleHistoryCatchUp,
|
|
833
|
+
_noteWalleHistoryCursorExpired,
|
|
834
|
+
_sendWalleHistoryReply,
|
|
835
|
+
_sendWalleHistoryErrorFrame,
|
|
836
|
+
_sendWalleSessionHistory,
|
|
837
|
+
handleWalleHistoryRequest,
|
|
838
|
+
};
|