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,171 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Cache temp names and their reclaimer (design doc temp-file-leaks §5 D-1/D-3, §8 WP-1).
|
|
4
|
+
//
|
|
5
|
+
// A decoded frame is written to `<final>.tmp-<pid>-<threadId>-<hex>` and published with a rename, so a
|
|
6
|
+
// crash between the two strands a temp. The pid+THREAD pair is what makes one attributable: the read
|
|
7
|
+
// pool's worker threads share process.pid, and pool `worker.terminate()` stops a thread after its write
|
|
8
|
+
// and before its rename -- a dead-pid sweep alone cannot see that (this is the 63 GB incident, §1 L-1).
|
|
9
|
+
// Threads get their own module instance, so `threadId` here is this isolate's own id (0 = main thread).
|
|
10
|
+
// CACHE_TEMP_RE also matches the legacy `<final>.tmp-<pid>-<hex>` shape, which has no thread to blame.
|
|
11
|
+
//
|
|
12
|
+
// Extracted from lib/transcript-source.js (which was over its 1500-line new-file ceiling) and kept
|
|
13
|
+
// deliberately dependency-free: this module knows NOTHING about the data dir. Every entry point takes
|
|
14
|
+
// the cache root in `opts.cacheDir`, and transcript-source -- the one owner of the default root -- passes
|
|
15
|
+
// it. The only external dependency is the liveness probe, loaded lazily on first sweep.
|
|
16
|
+
|
|
17
|
+
const crypto = require('node:crypto');
|
|
18
|
+
const fs = require('node:fs');
|
|
19
|
+
const path = require('node:path');
|
|
20
|
+
const { threadId } = require('node:worker_threads');
|
|
21
|
+
|
|
22
|
+
const CACHE_TEMP_RE = /\.bin\.tmp-(\d+)-(?:(\d+)-)?[0-9a-f]{8,16}$/;
|
|
23
|
+
const CACHE_TEMP_STALE_MS = 30 * 60_000;
|
|
24
|
+
const CACHE_TEMP_SWEEP_INTERVAL_MS = 5 * 60_000;
|
|
25
|
+
let _cacheTempSweptAt = 0; // per-isolate sweep throttle; 0 = never swept
|
|
26
|
+
|
|
27
|
+
function cacheTempPath(finalPath) {
|
|
28
|
+
return `${finalPath}.tmp-${process.pid}-${threadId}-${crypto.randomBytes(8).toString('hex')}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The one cache-root rule here: the caller passes it. A missing root is a programming error, not a silent no-op. */
|
|
32
|
+
function _cacheRootOf(opts) {
|
|
33
|
+
const root = opts && opts.cacheDir;
|
|
34
|
+
if (typeof root !== 'string' || root === '') throw new TypeError('transcript-cache-temps: opts.cacheDir is required');
|
|
35
|
+
return root;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function _cacheKeyDirPaths(root, dirs) {
|
|
39
|
+
return dirs.filter((d) => d.isDirectory()).map((d) => path.join(root, d.name));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The `<key>` subdirectories of a cache root, or [] when the root does not exist yet. */
|
|
43
|
+
async function _cacheKeyDirsAsync(root) {
|
|
44
|
+
let dirs;
|
|
45
|
+
try {
|
|
46
|
+
dirs = await fs.promises.readdir(root, { withFileTypes: true });
|
|
47
|
+
} catch (err) {
|
|
48
|
+
if (err && err.code === 'ENOENT') return [];
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
return _cacheKeyDirPaths(root, dirs);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Every `*.bin.tmp-*` cache temp in `dir`: the one temp-shape rule (a published `.bin` never matches). */
|
|
55
|
+
function _cacheTempEntry(dir, name, match, st) {
|
|
56
|
+
return {
|
|
57
|
+
file: path.join(dir, name), pid: Number(match[1]),
|
|
58
|
+
threadId: match[2] === undefined ? null : Number(match[2]), size: st.size, mtimeMs: st.mtimeMs,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function _cacheTempsInDirAsync(dir) {
|
|
63
|
+
let names;
|
|
64
|
+
try {
|
|
65
|
+
names = await fs.promises.readdir(dir);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
if (err && err.code === 'ENOENT') return []; // expected: a concurrent prune took the whole key dir
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
const temps = [];
|
|
71
|
+
for (const name of names) {
|
|
72
|
+
const match = CACHE_TEMP_RE.exec(name);
|
|
73
|
+
if (!match) continue;
|
|
74
|
+
let st;
|
|
75
|
+
try {
|
|
76
|
+
st = await fs.promises.stat(path.join(dir, name));
|
|
77
|
+
} catch (err) {
|
|
78
|
+
if (err && err.code === 'ENOENT') continue; // expected: another reclaimer unlinked this temp first
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
temps.push(_cacheTempEntry(dir, name, match, st));
|
|
82
|
+
}
|
|
83
|
+
return temps;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function _unlinkCacheTempAsync(file) {
|
|
87
|
+
try {
|
|
88
|
+
await fs.promises.unlink(file);
|
|
89
|
+
return true;
|
|
90
|
+
} catch (err) {
|
|
91
|
+
if (err && err.code === 'ENOENT') return false; // expected: a concurrent reclaimer won the race
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** The per-temp sweep decision: a provably-gone OWNER, or simply age. The sweep calls only this. */
|
|
97
|
+
function _cacheTempIsReclaimable(temp, now, isProcessAlive) {
|
|
98
|
+
const ownerGone = temp.pid !== process.pid && !isProcessAlive(temp.pid);
|
|
99
|
+
return ownerGone || now - temp.mtimeMs >= CACHE_TEMP_STALE_MS;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** The per-temp thread claim (D-2): a legacy name has no threadId, so no thread can claim it. */
|
|
103
|
+
function _cacheTempIsOwnedByThread(temp, pid, threadId_) {
|
|
104
|
+
return temp.pid === pid && temp.threadId === threadId_;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** The sweep throttle + its inputs: null when this isolate already swept inside the interval. */
|
|
108
|
+
function _cacheTempSweepState(opts) {
|
|
109
|
+
const now = typeof opts.now === 'function' ? Number(opts.now())
|
|
110
|
+
: (Number.isFinite(opts.now) ? Number(opts.now) : Date.now());
|
|
111
|
+
if (!opts.force && now - _cacheTempSweptAt < CACHE_TEMP_SWEEP_INTERVAL_MS) return null;
|
|
112
|
+
_cacheTempSweptAt = now;
|
|
113
|
+
return {
|
|
114
|
+
now,
|
|
115
|
+
root: _cacheRootOf(opts),
|
|
116
|
+
isProcessAlive: typeof opts.isProcessAlive === 'function'
|
|
117
|
+
? opts.isProcessAlive
|
|
118
|
+
: require('./host-registry').isProcessAlive, // lazy: the probe is not needed on the decode path
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The one reclaimer for stranded decode temps (design §5 D-3): a temp goes when its OWNER is provably
|
|
124
|
+
* gone (dead pid -- the only evidence a terminated worker thread leaves behind) or when it is simply
|
|
125
|
+
* old, whatever wrote it. Never touches a `.bin`; tolerates ENOENT races; throttled per isolate.
|
|
126
|
+
*
|
|
127
|
+
* ASYNC-only on purpose: a live cache holds thousands of `<key>` dirs (measured 479 ms for one walk),
|
|
128
|
+
* so a synchronous form would stall whatever loop called it. Every caller -- server.js's interval and
|
|
129
|
+
* the read pool's exit listener -- can await, so no sync twin exists to drift from these rules.
|
|
130
|
+
*/
|
|
131
|
+
async function sweepStaleCacheTempsAsync(opts = {}) {
|
|
132
|
+
const result = { removed: 0, bytes: 0 };
|
|
133
|
+
const state = _cacheTempSweepState(opts);
|
|
134
|
+
if (!state) return result;
|
|
135
|
+
for (const dir of await _cacheKeyDirsAsync(state.root)) {
|
|
136
|
+
for (const temp of await _cacheTempsInDirAsync(dir)) {
|
|
137
|
+
if (!_cacheTempIsReclaimable(temp, state.now, state.isProcessAlive)) continue;
|
|
138
|
+
if (await _unlinkCacheTempAsync(temp.file)) {
|
|
139
|
+
result.removed += 1;
|
|
140
|
+
result.bytes += temp.size;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* D-2: reclaims what ONE dead thread left behind, by ownership (pid + threadId) instead of by age --
|
|
149
|
+
* the thread is gone, so no grace period is needed. Async for the same reason as the sweep above.
|
|
150
|
+
*/
|
|
151
|
+
async function removeCacheTempsForThreadAsync(pid, threadId_, opts = {}) {
|
|
152
|
+
const wantPid = Number(pid);
|
|
153
|
+
const wantThreadId = Number(threadId_);
|
|
154
|
+
let removed = 0;
|
|
155
|
+
for (const dir of await _cacheKeyDirsAsync(_cacheRootOf(opts))) {
|
|
156
|
+
for (const temp of await _cacheTempsInDirAsync(dir)) {
|
|
157
|
+
if (!_cacheTempIsOwnedByThread(temp, wantPid, wantThreadId)) continue;
|
|
158
|
+
if (await _unlinkCacheTempAsync(temp.file)) removed += 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return removed;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
module.exports = {
|
|
165
|
+
CACHE_TEMP_RE,
|
|
166
|
+
CACHE_TEMP_STALE_MS,
|
|
167
|
+
CACHE_TEMP_SWEEP_INTERVAL_MS,
|
|
168
|
+
cacheTempPath,
|
|
169
|
+
sweepStaleCacheTempsAsync,
|
|
170
|
+
removeCacheTempsForThreadAsync,
|
|
171
|
+
};
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// Async full-frame cache ownership. A pathname is only the publication/eviction name: readers own
|
|
4
4
|
// the opened inode through a refcounted lease, so a prune in another isolate cannot invalidate them.
|
|
5
5
|
// Admission is injected by transcript-source, sharing its two slots with bounded prefix decoders.
|
|
6
|
-
const crypto = require('node:crypto');
|
|
7
6
|
const fs = require('node:fs');
|
|
8
7
|
const path = require('node:path');
|
|
9
8
|
const { Transform } = require('node:stream');
|
|
@@ -27,8 +26,12 @@ function closedReceipt(stream) {
|
|
|
27
26
|
// the eviction order of multi-GB entries unchanged (fsevents-churn D-10b).
|
|
28
27
|
const TOUCH_MIN_INTERVAL_MS = 60_000;
|
|
29
28
|
|
|
30
|
-
function createDecodedFrameCache({ withDecoder, cacheRoot, cacheMax, now, frameFile, pruneCache, codeError }) {
|
|
29
|
+
function createDecodedFrameCache({ withDecoder, cacheRoot, cacheMax, now, frameFile, pruneCache, codeError, cacheTempPath }) {
|
|
31
30
|
const entries = new Map();
|
|
31
|
+
// D-1: the temp-naming rule lives in transcript-cache-temps.js (the sync writer in transcript-source
|
|
32
|
+
// shares it). It is injected at construction so the module graph stays acyclic; the lazy fallback is
|
|
33
|
+
// for direct constructors (tests) that call this factory without transcript-source in the loop.
|
|
34
|
+
const tempPathFor = cacheTempPath || require('./transcript-cache-temps').cacheTempPath;
|
|
32
35
|
|
|
33
36
|
function removeEntry(entry) {
|
|
34
37
|
if (entries.get(entry.key) === entry) entries.delete(entry.key);
|
|
@@ -96,7 +99,9 @@ function createDecodedFrameCache({ withDecoder, cacheRoot, cacheMax, now, frameF
|
|
|
96
99
|
entry.state = 'filling';
|
|
97
100
|
await fs.promises.mkdir(path.dirname(entry.file), { recursive: true });
|
|
98
101
|
throwIfAborted(signal);
|
|
99
|
-
|
|
102
|
+
// D-1: one naming rule for both writers, owned by transcript-cache-temps.js (pid + threadId), so a
|
|
103
|
+
// temp stranded by a terminated read-pool thread is attributable to the thread that wrote it.
|
|
104
|
+
entry.tmp = tempPathFor(entry.file);
|
|
100
105
|
const decoder = (entry.opts.decoderFactory || decodeFrame)(entry.archive.path, entry.frame);
|
|
101
106
|
const decoderClosed = closedReceipt(decoder);
|
|
102
107
|
let total = 0;
|
|
@@ -23,6 +23,7 @@ const zlib = require('node:zlib');
|
|
|
23
23
|
const { decodeFrame, waitForDecodedFrameClose, decompressParams } = require('./transcript-archive-codec');
|
|
24
24
|
const { getDataDir } = require('./data-dir');
|
|
25
25
|
const { createDecodedFrameCache, TOUCH_MIN_INTERVAL_MS } = require('./transcript-frame-cache');
|
|
26
|
+
const cacheTemps = require('./transcript-cache-temps');
|
|
26
27
|
|
|
27
28
|
const CACHE_DIR_NAME = 'transcript-archive-cache';
|
|
28
29
|
const DEFAULT_CACHE_MAX_BYTES = 4 * 1024 * 1024 * 1024;
|
|
@@ -91,6 +92,16 @@ function _frameFile(root, key, index) {
|
|
|
91
92
|
return path.join(root, key, `${index}.bin`);
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
// The cache root is this module's to know (CACHE_DIR_NAME under getDataDir()); every reclaimer entry
|
|
96
|
+
// point takes it as `cacheDir`. Delegated so the sweep's rules live in exactly one module.
|
|
97
|
+
const _cacheTempsOpts = (opts) => ({ ...opts, cacheDir: (opts && opts.cacheDir) || _cacheRoot(opts) });
|
|
98
|
+
const cacheTempPath = cacheTemps.cacheTempPath;
|
|
99
|
+
const CACHE_TEMP_RE = cacheTemps.CACHE_TEMP_RE;
|
|
100
|
+
const CACHE_TEMP_STALE_MS = cacheTemps.CACHE_TEMP_STALE_MS;
|
|
101
|
+
const CACHE_TEMP_SWEEP_INTERVAL_MS = cacheTemps.CACHE_TEMP_SWEEP_INTERVAL_MS;
|
|
102
|
+
const sweepStaleCacheTempsAsync = (opts = {}) => cacheTemps.sweepStaleCacheTempsAsync(_cacheTempsOpts(opts));
|
|
103
|
+
const removeCacheTempsForThreadAsync = (pid, tid, opts = {}) => cacheTemps.removeCacheTempsForThreadAsync(pid, tid, _cacheTempsOpts(opts));
|
|
104
|
+
|
|
94
105
|
// ---------------------------------------------------------------------------------------------
|
|
95
106
|
// Manifest lookup (the db handle sees the base database; guarded like the identity guard).
|
|
96
107
|
|
|
@@ -336,6 +347,7 @@ function _evictionList(files, max, keepFile) {
|
|
|
336
347
|
}
|
|
337
348
|
|
|
338
349
|
async function _pruneCache(opts, keepFile) {
|
|
350
|
+
await sweepStaleCacheTempsAsync(opts);
|
|
339
351
|
const doomed = _evictionList(await _listCache(_cacheRoot(opts)), _cacheMax(opts), keepFile);
|
|
340
352
|
for (const file of doomed) {
|
|
341
353
|
await fs.promises.unlink(file).catch((err) => {
|
|
@@ -391,7 +403,7 @@ async function _withDecoder(fn, signal) {
|
|
|
391
403
|
|
|
392
404
|
const { acquireDecodedFrame } = createDecodedFrameCache({
|
|
393
405
|
withDecoder: _withDecoder, cacheRoot: _cacheRoot, cacheMax: _cacheMax,
|
|
394
|
-
now: _now, frameFile: _frameFile, pruneCache: _pruneCache, codeError: _codeError,
|
|
406
|
+
now: _now, frameFile: _frameFile, pruneCache: _pruneCache, codeError: _codeError, cacheTempPath,
|
|
395
407
|
});
|
|
396
408
|
|
|
397
409
|
// ---------------------------------------------------------------------------------------------
|
|
@@ -1146,9 +1158,23 @@ function _decodeFrameSync(archive, index, opts, learnLength) {
|
|
|
1146
1158
|
if (!learnLength && bytes.length !== uLen) throw _codeError('ARCHIVE_VERIFY_FAILED', `frame ${index} decoded to ${bytes.length} bytes, expected ${uLen}`);
|
|
1147
1159
|
if (ledger && learnLength) _chargeLearnedDecoded(ledger, `${archive.cacheKey}:${index}`, bytes.length);
|
|
1148
1160
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
1149
|
-
const tmp =
|
|
1150
|
-
|
|
1151
|
-
|
|
1161
|
+
const tmp = cacheTempPath(file);
|
|
1162
|
+
try {
|
|
1163
|
+
fs.writeFileSync(tmp, bytes, { flag: 'wx' });
|
|
1164
|
+
fs.renameSync(tmp, file);
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
// D-4: this write is synchronous inside whatever isolate called it, so nothing else can clean up
|
|
1167
|
+
// after a failed publish -- and a caller killed right here (read pool terminate) never gets to.
|
|
1168
|
+
// Unlink the temp, then rethrow the ORIGINAL error unchanged.
|
|
1169
|
+
try {
|
|
1170
|
+
fs.unlinkSync(tmp);
|
|
1171
|
+
} catch (cleanupErr) {
|
|
1172
|
+
if (!cleanupErr || cleanupErr.code !== 'ENOENT') {
|
|
1173
|
+
console.warn(`[transcript-cache] temp cleanup failed for ${tmp}: ${cleanupErr?.message || cleanupErr}`);
|
|
1174
|
+
} // else: the write failed before creating the temp -- nothing to remove
|
|
1175
|
+
}
|
|
1176
|
+
throw err;
|
|
1177
|
+
}
|
|
1152
1178
|
const when = new Date(_now(opts));
|
|
1153
1179
|
fs.utimesSync(file, when, when);
|
|
1154
1180
|
_pruneCacheSync(opts, file);
|
|
@@ -1423,4 +1449,10 @@ module.exports = {
|
|
|
1423
1449
|
zstdContentSize,
|
|
1424
1450
|
MAX_RANGE_BYTES,
|
|
1425
1451
|
DEFAULT_CACHE_MAX_BYTES,
|
|
1452
|
+
cacheTempPath,
|
|
1453
|
+
CACHE_TEMP_RE,
|
|
1454
|
+
CACHE_TEMP_STALE_MS,
|
|
1455
|
+
CACHE_TEMP_SWEEP_INTERVAL_MS,
|
|
1456
|
+
sweepStaleCacheTempsAsync,
|
|
1457
|
+
removeCacheTempsForThreadAsync,
|
|
1426
1458
|
};
|
|
@@ -4314,6 +4314,11 @@ function catchUpTranscriptFiles(db, options = {}) {
|
|
|
4314
4314
|
for (;;) {
|
|
4315
4315
|
assertCatchUpLive();
|
|
4316
4316
|
if (Date.now() - startedAt > catchUpBudgetMs) { budgetExceeded = true; break; }
|
|
4317
|
+
// S-16 (D-11): a wall-clock budget alone lets this whole op (which blocks the serial
|
|
4318
|
+
// writer) run to its 5 s slice while an interactive request waits. The caller's
|
|
4319
|
+
// predicates are the same ones drainTranscriptByteBackfill already honours; a set
|
|
4320
|
+
// predicate ends the run as a partial result, exactly like budget expiry.
|
|
4321
|
+
if (options.shouldYieldToUrgent?.() || options.shouldYieldToPending?.()) { budgetExceeded = true; break; }
|
|
4317
4322
|
const promoted = backfillSessionRowsFromTranscriptEvents(db, {
|
|
4318
4323
|
limit: backfillLimit,
|
|
4319
4324
|
ctmSessionId: sessionId,
|
|
@@ -4334,6 +4339,10 @@ function catchUpTranscriptFiles(db, options = {}) {
|
|
|
4334
4339
|
for (const rawPath of filePaths) {
|
|
4335
4340
|
assertCatchUpLive();
|
|
4336
4341
|
if (Date.now() - startedAt > catchUpBudgetMs) { budgetExceeded = true; break; }
|
|
4342
|
+
// S-16 (D-11): same yield contract as the backfill loop above — one file per check, so a
|
|
4343
|
+
// pending interactive/urgent request is honoured within a single file's ingest here, not
|
|
4344
|
+
// only at the 5 s op budget.
|
|
4345
|
+
if (options.shouldYieldToUrgent?.() || options.shouldYieldToPending?.()) { budgetExceeded = true; break; }
|
|
4337
4346
|
if (filesProcessed >= maxFilesPerRun) { budgetExceeded = true; break; }
|
|
4338
4347
|
const filePath = path.resolve(String(rawPath || ''));
|
|
4339
4348
|
if (!filePath || seenPaths.has(filePath)) continue;
|
|
@@ -72,10 +72,13 @@ const STAGES = Object.freeze([
|
|
|
72
72
|
// new gate -- Gate 1 (§7) pins it.
|
|
73
73
|
// WP-2 (state-sync-delivery-path-reset-2026-09-18.html §5 D-9): the suppression/no-audience/
|
|
74
74
|
// client-fault gates were deleted from the emitter along with their latches -- the emitter now
|
|
75
|
-
// only refuses on
|
|
76
|
-
//
|
|
75
|
+
// only refuses on a full unacked window or the rate floor. `hidden`/`nudge`/`sync-hold`/`settle`
|
|
76
|
+
// are stamped by headless-term-service.js itself, not by the emitter's onRefused.
|
|
77
|
+
// WP-1 (docs/state-sync-pipelined-deltas-echo-never-waits-for-ack-2026-10-31.html §5 D-2, §6, §9
|
|
78
|
+
// S-9): the one-slot gates are replaced by `window-full`; the OLD names are kept at the end so rows
|
|
79
|
+
// written before WP-1 still parse.
|
|
77
80
|
const GATES = Object.freeze([
|
|
78
|
-
'in-flight-keyframe', 'in-flight-delta', 'rate', 'hidden', 'nudge', 'sync-hold', 'settle',
|
|
81
|
+
'window-full', 'in-flight-keyframe', 'in-flight-delta', 'rate', 'hidden', 'nudge', 'sync-hold', 'settle',
|
|
79
82
|
]);
|
|
80
83
|
const GATE_SET = new Set(GATES);
|
|
81
84
|
|
|
@@ -95,12 +98,23 @@ const OPTIONAL_STAGES = new Set([
|
|
|
95
98
|
// coalescer delivered before any keystroke was pending), so neither may end the boundary walk.
|
|
96
99
|
'frame-arrived', 'host-pty-data',
|
|
97
100
|
'echo-bytes', 'echo-cell',
|
|
101
|
+
// WP-0 (docs/state-sync-pipelined-deltas-echo-never-waits-for-ack-2026-10-31.html §5 D-5,
|
|
102
|
+
// §9 S-9): 'inflight-acked' is a REPORT-ONLY stamp on the interaction a matched ack unblocked --
|
|
103
|
+
// it is not a step in any interaction's sequence (it is not in STAGES at all), so it must never
|
|
104
|
+
// move `lastCompletedBoundary`/`missingBoundary`. Its record carries the acked frame's seq and
|
|
105
|
+
// both measured legs (see note()'s branch below); the interaction itself gains `heldBehind`.
|
|
106
|
+
'inflight-acked',
|
|
98
107
|
]);
|
|
99
108
|
const WORKLOAD_FIELDS = Object.freeze([
|
|
100
109
|
'rawBatchClass', 'synchronizedFrameCount', 'mirrorChangedRows', 'frameKind',
|
|
101
110
|
'frameBytes', 'queuedBytes', 'queueDepth', 'codexRepairActions',
|
|
102
111
|
'statusRenderSource', 'visibility', 'focused', 'activeLoafMs', 'gridRevision',
|
|
103
112
|
'frameSeq',
|
|
113
|
+
// WP-2 (docs/typing-delay-session-list-broadcast-storm-2026-11-01.html §6 WP-2, §5 OQ-3): the
|
|
114
|
+
// socket's bufferedAmount at the instant the frame carrying this key's echo was handed to it.
|
|
115
|
+
// Read on the `frame-sent` note (server.js's 'frame' fan-out); 0 at a slow frame is what rules
|
|
116
|
+
// socket backlog out and leaves browser task-queue time (OQ-3).
|
|
117
|
+
'socketBufferedBytes',
|
|
104
118
|
]);
|
|
105
119
|
|
|
106
120
|
function finite(value, fallback = 0) {
|
|
@@ -139,6 +153,15 @@ function percentile(values, pct) {
|
|
|
139
153
|
return sorted[Math.max(0, Math.ceil(sorted.length * pct) - 1)];
|
|
140
154
|
}
|
|
141
155
|
|
|
156
|
+
// WP-0 (S-9): one leg of an in-flight frame's round trip. A leg is a non-negative millisecond
|
|
157
|
+
// count, or the explicit "no evidence" sentinel -1 -- never a silent 0, which would read as an
|
|
158
|
+
// instant round trip and quietly flatter the very measurement this WP exists to make honest.
|
|
159
|
+
function rttMs(value, fallback = -1) {
|
|
160
|
+
const number = Number(value);
|
|
161
|
+
if (!Number.isFinite(number) || number < 0) return fallback;
|
|
162
|
+
return Math.floor(number);
|
|
163
|
+
}
|
|
164
|
+
|
|
142
165
|
function sanitizePublicContext(context = {}, fallback = {}) {
|
|
143
166
|
const source = { ...fallback, ...context };
|
|
144
167
|
return {
|
|
@@ -212,6 +235,10 @@ function buildSlowInteractionRow(row, ktpMs, lastStage) {
|
|
|
212
235
|
inFlightAgeMs: refused ? refused.inFlightAgeMs : 0,
|
|
213
236
|
rejectedSurfaceEpoch: refused ? refused.rejectedSurfaceEpoch : 0,
|
|
214
237
|
sweepSkipReason: refused ? refused.sweepSkipReason : '',
|
|
238
|
+
// WP-0 (S-9, §6 API specs): the in-flight frame this keystroke was held behind, with both
|
|
239
|
+
// measured round-trip legs and the relay remainder -- null for a keystroke that was never
|
|
240
|
+
// refused, or whose held frame's ack never landed.
|
|
241
|
+
heldBehind: row.heldBehind || null,
|
|
215
242
|
browserKeydownMs: stageMsFromKeydown(row, 'browser-keydown'),
|
|
216
243
|
serverReceivedMs: stageMsFromKeydown(row, 'server-received'),
|
|
217
244
|
ptyWrittenMs: stageMsFromKeydown(row, 'pty-written'),
|
|
@@ -310,6 +337,9 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
310
337
|
const slowThrottledBySession = new Map();
|
|
311
338
|
const worstByGroup = new Map();
|
|
312
339
|
const worstUnpaintedByGroup = new Map();
|
|
340
|
+
// WP-0 (S-9): the frame WINDOW size in force when the minute's acks landed (1 today, the gate's
|
|
341
|
+
// size after WP-1) -- keyed like the two maps above, last non-zero value wins, cleared per flush.
|
|
342
|
+
const windowFramesByGroup = new Map();
|
|
313
343
|
|
|
314
344
|
// Both new per-key maps are bounded/evicted exactly like lastSlowEmitAtBySession above: re-set
|
|
315
345
|
// an existing key at the tail, then drop the oldest keys past the shared cap.
|
|
@@ -378,6 +408,9 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
378
408
|
gate,
|
|
379
409
|
gateHoldMs,
|
|
380
410
|
clientId: row.clientId,
|
|
411
|
+
// WP-0 (S-9): this interaction's held-frame evidence (null when it was never refused, or the
|
|
412
|
+
// ack for its held seq never landed) -- flushRollups turns it into the three held*P95Ms fields.
|
|
413
|
+
heldBehind: row.heldBehind || null,
|
|
381
414
|
});
|
|
382
415
|
windowClosedHistory.push({ at: paintedAt, ktpMs, gate });
|
|
383
416
|
if (windowClosedHistory.length > WINDOW_HISTORY_CAP) windowClosedHistory.shift();
|
|
@@ -468,6 +501,9 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
468
501
|
lastCompletedBoundary: 'browser-keydown',
|
|
469
502
|
stages: Object.assign(Object.create(null), { 'browser-keydown': { at: startedAt } }),
|
|
470
503
|
workload: Object.create(null),
|
|
504
|
+
// WP-0 (S-9): set by note()'s 'inflight-acked' branch when this interaction's own refusal
|
|
505
|
+
// named the seq that ack retired (see buildSlowInteractionRow / pendingClosed).
|
|
506
|
+
heldBehind: null,
|
|
471
507
|
});
|
|
472
508
|
prune(startedAt);
|
|
473
509
|
return interactionId;
|
|
@@ -528,10 +564,46 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
528
564
|
row.stages[stage] = Array.isArray(event.mainSpans)
|
|
529
565
|
? { at, mainSpans: sanitizeMainSpans(event.mainSpans) }
|
|
530
566
|
: { at };
|
|
567
|
+
} else if (stage === 'inflight-acked') {
|
|
568
|
+
// WP-0 (S-9): the acked frame's seq plus both measured legs (host = the emitter's own
|
|
569
|
+
// send->ack span; main = the server ledger's sentAt delta; windowFrames = the gate's window
|
|
570
|
+
// size when the ack landed). Report-only -- see OPTIONAL_STAGES above.
|
|
571
|
+
row.stages[stage] = {
|
|
572
|
+
at,
|
|
573
|
+
inFlightSeq: Math.max(0, Math.floor(finite(event.inFlightSeq))),
|
|
574
|
+
hostRttMs: rttMs(event.hostRttMs, 0),
|
|
575
|
+
mainRttMs: rttMs(event.mainRttMs, -1),
|
|
576
|
+
windowFrames: Math.max(0, Math.floor(finite(event.windowFrames))),
|
|
577
|
+
};
|
|
531
578
|
} else {
|
|
532
579
|
row.stages[stage] = { at };
|
|
533
580
|
}
|
|
534
581
|
}
|
|
582
|
+
// WP-0 (S-9, §5 D-5): if THIS interaction was refused behind the very seq this ack retired,
|
|
583
|
+
// remember the held frame's two round-trip legs on the interaction itself. FIRST match wins --
|
|
584
|
+
// a later ack, or one for another seq, never overwrites the evidence for the frame that
|
|
585
|
+
// actually held this keystroke, and a never-refused interaction keeps `heldBehind: null`.
|
|
586
|
+
if (stage === 'inflight-acked') {
|
|
587
|
+
const windowFrames = Math.max(0, Math.floor(finite(event.windowFrames)));
|
|
588
|
+
if (windowFrames > 0) {
|
|
589
|
+
setBoundedByKey(windowFramesByGroup, rollupGroupKey(row.sessionId, row.agentType), windowFrames);
|
|
590
|
+
}
|
|
591
|
+
if (!row.heldBehind) {
|
|
592
|
+
const refused = row.stages['emit-refused'];
|
|
593
|
+
const retiredSeq = Math.max(0, Math.floor(finite(event.inFlightSeq)));
|
|
594
|
+
if (refused && retiredSeq > 0 && Math.max(0, Math.floor(finite(refused.inFlightSeq))) === retiredSeq) {
|
|
595
|
+
const hostRttMs = rttMs(event.hostRttMs, 0);
|
|
596
|
+
const mainRttMs = rttMs(event.mainRttMs, -1);
|
|
597
|
+
row.heldBehind = {
|
|
598
|
+
seq: retiredSeq,
|
|
599
|
+
hostRttMs,
|
|
600
|
+
mainRttMs,
|
|
601
|
+
// The relay leg is the part of the host leg main's own measurement cannot see.
|
|
602
|
+
relayMs: mainRttMs >= 0 ? Math.max(0, hostRttMs - mainRttMs) : -1,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
535
607
|
// R-8, order-independent: the worker posts `frame-posted` as its own 'typing-stage' message
|
|
536
608
|
// AFTER the frame shipped (headless-term-service.js emitSettled -> noteFramePostedForEchoed),
|
|
537
609
|
// so main usually stamps `frame-arrived` BEFORE it knows `frame-posted`. Compute the spans when
|
|
@@ -724,6 +796,20 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
724
796
|
return values.length ? percentile(values, 0.95) : 0;
|
|
725
797
|
}
|
|
726
798
|
|
|
799
|
+
// WP-0 (S-9, §6 API specs): nearest-rank p95 over the CLOSED interactions of the minute that
|
|
800
|
+
// carried held-frame evidence, for one leg (`hostRttMs` | `mainRttMs` | `relayMs`). The -1
|
|
801
|
+
// "no evidence" sentinel is not a sample: an all-unknown minute reports 0, not -1.
|
|
802
|
+
function heldPercentileMs(closedList, field) {
|
|
803
|
+
const values = [];
|
|
804
|
+
for (const entry of closedList) {
|
|
805
|
+
const held = entry.heldBehind;
|
|
806
|
+
if (!held) continue;
|
|
807
|
+
const value = Number(held[field]);
|
|
808
|
+
if (Number.isFinite(value) && value >= 0) values.push(value);
|
|
809
|
+
}
|
|
810
|
+
return values.length ? percentile(values, 0.95) : 0;
|
|
811
|
+
}
|
|
812
|
+
|
|
727
813
|
// D-1: groups every interaction that CLOSED (reached `painted`) or EXPIRED (pruned by TTL
|
|
728
814
|
// without `painted`) since the previous flush, by (sessionId, agentType||'unknown'), and
|
|
729
815
|
// emits one flat rollup object per group via `onRollup`. Returns the number emitted.
|
|
@@ -793,6 +879,14 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
793
879
|
worstUnpainted: worstUnpaintedByGroup.get(key) || null,
|
|
794
880
|
slowEmitted: slowEmittedBySession.get(sessionId) || 0,
|
|
795
881
|
slowThrottled: slowThrottledBySession.get(sessionId) || 0,
|
|
882
|
+
// WP-0 (S-9, §6 API specs): the frame WINDOW size in force this minute (1 today -- the gate
|
|
883
|
+
// is still one frame in flight; WP-1 widens it) and the round trip of every keystroke this
|
|
884
|
+
// minute held behind an in-flight frame, split into its two measured legs plus the relay
|
|
885
|
+
// remainder (host - main). 0 = nothing held / no evidence in this minute.
|
|
886
|
+
windowFrames: windowFramesByGroup.get(key) || 1,
|
|
887
|
+
heldHostRttP95Ms: heldPercentileMs(closedList, 'hostRttMs'),
|
|
888
|
+
heldMainRttP95Ms: heldPercentileMs(closedList, 'mainRttMs'),
|
|
889
|
+
heldRelayP95Ms: heldPercentileMs(closedList, 'relayMs'),
|
|
796
890
|
workerLoopMaxMs: Math.max(0, finite(extras.workerLoopMaxMs, 0)),
|
|
797
891
|
host: {
|
|
798
892
|
loadPerCore: Math.max(0, finite(extras.host?.loadPerCore, 0)),
|
|
@@ -810,6 +904,9 @@ function createTypingInteractionTraceStore(options = {}) {
|
|
|
810
904
|
// minute starts from 0 rather than re-reporting the previous minute's worst).
|
|
811
905
|
worstByGroup.clear();
|
|
812
906
|
worstUnpaintedByGroup.clear();
|
|
907
|
+
// WP-0 (S-9): the minute's observed window size is per-flush-window state, cleared with the
|
|
908
|
+
// buckets it describes -- a later minute starts from "no evidence" (reported as 1) again.
|
|
909
|
+
windowFramesByGroup.clear();
|
|
813
910
|
slowEmittedBySession.clear();
|
|
814
911
|
slowThrottledBySession.clear();
|
|
815
912
|
lastFlushAt = at;
|
|
@@ -880,6 +977,12 @@ function noteWorkerStageMessage(store, msg = {}) {
|
|
|
880
977
|
inFlightAgeMs: msg.inFlightAgeMs,
|
|
881
978
|
rejectedSurfaceEpoch: msg.rejectedSurfaceEpoch,
|
|
882
979
|
sweepSkipReason: msg.sweepSkipReason,
|
|
980
|
+
// WP-0 (S-11): the matched ack's two measured round-trip legs and the gate's window size ride
|
|
981
|
+
// the same 'typing-stage' message as the `inflight-acked` stage stamp (the store bounds and
|
|
982
|
+
// validates each one itself -- see note()'s branch).
|
|
983
|
+
hostRttMs: msg.hostRttMs,
|
|
984
|
+
mainRttMs: msg.mainRttMs,
|
|
985
|
+
windowFrames: msg.windowFrames,
|
|
883
986
|
});
|
|
884
987
|
}
|
|
885
988
|
return true;
|
|
@@ -22,9 +22,11 @@ const path = require('node:path');
|
|
|
22
22
|
|
|
23
23
|
const { statTranscriptSync } = require('../transcript-source');
|
|
24
24
|
const { claudeFileIdentity } = require('./claude-parse');
|
|
25
|
+
const { DSH_USAGE_DIR_NAME } = require('./dsh-parse');
|
|
25
26
|
|
|
26
27
|
const CODEX_ROLLOUT_RE = /^rollout-.*\.jsonl$/;
|
|
27
28
|
const CLAUDE_TRANSCRIPT_RE = /\.jsonl(\.bak)?$/i;
|
|
29
|
+
const DSH_USAGE_FILE_RE = /\.jsonl$/i;
|
|
28
30
|
// Directories that hold no usage facts (memory notes, tool results).
|
|
29
31
|
const SKIP_DIR_NAMES = new Set(['memory', 'tool-results']);
|
|
30
32
|
|
|
@@ -74,16 +76,39 @@ function codexCorpusFiles(root, { listDir, realpath, onError = (_path, error) =>
|
|
|
74
76
|
return out;
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
// Every `*.jsonl` directly under the dsh usage directory (WP-9). FLAT on purpose: the directory
|
|
80
|
+
// holds one file per CTM session, named by the session id, and nothing else -- no project nesting, no
|
|
81
|
+
// `subagents/` tree, no `workflows/`. A missing directory is normal (no dsh session has been routed
|
|
82
|
+
// through the proxy yet).
|
|
83
|
+
function dshCorpusFiles(root, { listDir, onError = (_path, error) => { throw error; } }) {
|
|
84
|
+
const out = [];
|
|
85
|
+
if (!root) return out;
|
|
86
|
+
let entries;
|
|
87
|
+
try { entries = listDir(root); } catch (err) { onError(root, err); return out; }
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
if (!entry || !entry.isFile) continue;
|
|
90
|
+
if (!DSH_USAGE_FILE_RE.test(entry.name)) continue;
|
|
91
|
+
out.push(path.join(root, entry.name));
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
77
96
|
/**
|
|
78
97
|
* The whole local corpus, newest first.
|
|
79
98
|
*
|
|
80
|
-
* @param {{claudeProjectsDir?: string, codexSessionsDir?: string}} roots
|
|
99
|
+
* @param {{claudeProjectsDir?: string, codexSessionsDir?: string, dshUsageDir?: string}} roots
|
|
100
|
+
* `dshUsageDir` is `<dataDir>/dsh-usage`; `createBackfill` derives it from the ledger's own
|
|
101
|
+
* database file when the caller does not name it.
|
|
81
102
|
* @param {{listDir: (dir: string) => Array<{name: string, isFile: boolean, isDirectory: boolean}>,
|
|
82
103
|
* realpath: (p: string) => string|null}} fsOps
|
|
83
104
|
* @returns {Array<{path: string, size: number, mtimeMs: number}>}
|
|
84
105
|
*/
|
|
85
|
-
function listCorpusFiles({ claudeProjectsDir, codexSessionsDir } = {}, fsOps) {
|
|
86
|
-
const paths = [
|
|
106
|
+
function listCorpusFiles({ claudeProjectsDir, codexSessionsDir, dshUsageDir } = {}, fsOps) {
|
|
107
|
+
const paths = [
|
|
108
|
+
...claudeCorpusFiles(claudeProjectsDir, fsOps),
|
|
109
|
+
...codexCorpusFiles(codexSessionsDir, fsOps),
|
|
110
|
+
...dshCorpusFiles(dshUsageDir, fsOps),
|
|
111
|
+
];
|
|
87
112
|
const out = [];
|
|
88
113
|
for (const filePath of paths) {
|
|
89
114
|
try {
|
|
@@ -105,6 +130,7 @@ function createBackfill({
|
|
|
105
130
|
store,
|
|
106
131
|
ingestor,
|
|
107
132
|
roots,
|
|
133
|
+
dshUsageDir = null,
|
|
108
134
|
parserVersion,
|
|
109
135
|
isShedding = () => false,
|
|
110
136
|
isLiveClaimed = () => false,
|
|
@@ -117,6 +143,15 @@ function createBackfill({
|
|
|
117
143
|
} = {}) {
|
|
118
144
|
const STEP = Math.max(1, Math.floor(Number(stepBytes) || DEFAULT_STEP_BYTES));
|
|
119
145
|
const CHECKPOINT_EVERY = Math.max(1, Math.floor(Number(checkpointEveryCalls) || DEFAULT_CHECKPOINT_EVERY_CALLS));
|
|
146
|
+
// The dsh corpus root (WP-9). The Claude/Codex roots are HOME-derived and handed in by the worker;
|
|
147
|
+
// dsh's is NOT (it lives under the CTM data dir), and the ledger's own database file is the one
|
|
148
|
+
// thing in this process that already names that directory -- `<dataDir>/usage.db`. Deriving it here
|
|
149
|
+
// keeps the worker entrypoint free of a second path source, and a caller that knows better (a test)
|
|
150
|
+
// can still pass `dshUsageDir` explicitly.
|
|
151
|
+
const DSH_USAGE_DIR = dshUsageDir
|
|
152
|
+
|| (store && store.db && typeof store.db.name === 'string' && store.db.name !== ''
|
|
153
|
+
? path.join(path.dirname(store.db.name), DSH_USAGE_DIR_NAME)
|
|
154
|
+
: null);
|
|
120
155
|
let callsSinceCheckpoint = 0;
|
|
121
156
|
let lastError = null;
|
|
122
157
|
// Calls upserted so far for a file that takes several steps, so the queue row is
|
|
@@ -138,7 +173,7 @@ function createBackfill({
|
|
|
138
173
|
lastError = { path: sourcePath, message, at: now() };
|
|
139
174
|
if (scanErrors.length < 20) scanErrors.push(message);
|
|
140
175
|
};
|
|
141
|
-
const files = listCorpusFiles(roots, { listDir, realpath, onError, statTranscript }).map((f) => ({ path: f.path, size: f.size }));
|
|
176
|
+
const files = listCorpusFiles({ ...(roots || {}), dshUsageDir: DSH_USAGE_DIR }, { listDir, realpath, onError, statTranscript }).map((f) => ({ path: f.path, size: f.size }));
|
|
142
177
|
const runId = store.createRun({ parserVersion, reason, files });
|
|
143
178
|
if (scanErrors.length) store.setRunStatus(runId, 'queued', { error: `scan incomplete: ${scanErrors.join('; ')}`.slice(0, 500) });
|
|
144
179
|
return runId;
|
|
@@ -244,4 +279,4 @@ function createBackfill({
|
|
|
244
279
|
return { ensureRun, step, status, lastFailure };
|
|
245
280
|
}
|
|
246
281
|
|
|
247
|
-
module.exports = { listCorpusFiles, createBackfill };
|
|
282
|
+
module.exports = { listCorpusFiles, dshCorpusFiles, createBackfill };
|
|
@@ -221,7 +221,10 @@ function startUsageLedger({
|
|
|
221
221
|
|
|
222
222
|
function requestSources(sources) {
|
|
223
223
|
if (stopping || !Array.isArray(sources) || sources.length > PRIORITY_REQUEST_LIMIT) return { accepted: false, backlog: priority.size };
|
|
224
|
-
|
|
224
|
+
// The main thread is the FIRST gate on a source batch; the live lane re-checks the same set
|
|
225
|
+
// (lib/usage-ledger/live.js `LIVE_PROVIDERS`). dsh was added by WP-9: its roots are the
|
|
226
|
+
// `<dataDir>/dsh-usage/<ctmSessionId>.jsonl` files the model proxy writes.
|
|
227
|
+
const valid = sources.filter((s) => s && typeof s.path === 'string' && path.isAbsolute(s.path) && ['claude', 'codex', 'dsh'].includes(s.provider));
|
|
225
228
|
if (valid.length !== sources.length || priority.size + valid.filter((s) => !priority.has(s.path)).length > PRIORITY_QUEUE_CAP) return { accepted: false, backlog: priority.size };
|
|
226
229
|
for (const source of valid) priority.set(source.path, { provider: source.provider, path: source.path });
|
|
227
230
|
deliverSources();
|