create-walle 0.10.1 → 0.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/lib/owner-write-safety.js +135 -0
- package/lib/public-runtime.js +13 -5
- package/lib/release-schema.json +3 -2
- package/lib/runtime-closure-policy.json +6 -4
- package/package.json +1 -1
- package/template/bin/deps-doctor.js +1 -1
- package/template/bin/node-bin.sh +11 -0
- package/template/coding-task-manager/api-prompts.js +10 -22
- package/template/coding-task-manager/bin/claude-hook.js +7 -3
- package/template/coding-task-manager/bin/claude-table-parity.js +307 -0
- package/template/coding-task-manager/bin/conversation-storage-auto-migration-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-generation-evidence.js +9 -2
- package/template/coding-task-manager/bin/conversation-storage-service-entry-lib.js +16 -1
- package/template/coding-task-manager/bin/conversation-storage-walle-owner.js +247 -0
- package/template/coding-task-manager/bin/ctm-machine-pair.js +160 -0
- package/template/coding-task-manager/bin/lead-wait-census.js +1348 -0
- package/template/coding-task-manager/bin/repair-foreign-clone.js +564 -0
- package/template/coding-task-manager/bin/repair-resume-echo-titles.js +248 -0
- package/template/coding-task-manager/bin/write-lock-bench.js +111 -0
- package/template/coding-task-manager/db.js +705 -286
- package/template/coding-task-manager/git-utils.js +44 -0
- package/template/coding-task-manager/lib/adopted-host-redial.js +4 -0
- package/template/coding-task-manager/lib/agent-presets.js +15 -0
- package/template/coding-task-manager/lib/agent-title-apply.js +88 -0
- package/template/coding-task-manager/lib/agent-title-backfill-read.js +92 -0
- package/template/coding-task-manager/lib/api/host-stats.js +98 -0
- package/template/coding-task-manager/lib/api/ingress.js +35 -12
- package/template/coding-task-manager/lib/api/machine-pairing.js +285 -0
- package/template/coding-task-manager/lib/api/machine-pool.js +307 -0
- package/template/coding-task-manager/lib/api/machines.js +461 -0
- package/template/coding-task-manager/lib/api/misc-ops.js +20 -5
- package/template/coding-task-manager/lib/api/providers.js +53 -6
- package/template/coding-task-manager/lib/api/resume-from-store.js +25 -0
- package/template/coding-task-manager/lib/api/sessions.js +160 -8
- package/template/coding-task-manager/lib/api/transcript-history.js +17 -4
- package/template/coding-task-manager/lib/api/worktrees.js +38 -37
- package/template/coding-task-manager/lib/approval-drift.js +16 -1
- package/template/coding-task-manager/lib/approval-logical-frame.js +5 -1
- package/template/coding-task-manager/lib/approval-scope.js +68 -4
- package/template/coding-task-manager/lib/auth-context.js +32 -2
- package/template/coding-task-manager/lib/auth-rate-limit.js +41 -1
- package/template/coding-task-manager/lib/auth-rules.js +186 -45
- package/template/coding-task-manager/lib/broadcast-serialize.js +2 -1
- package/template/coding-task-manager/lib/browser-session-broker.js +9 -1
- package/template/coding-task-manager/lib/browser-use-adapter.js +33 -2
- package/template/coding-task-manager/lib/claude-markdown-ansi.js +27 -85
- package/template/coding-task-manager/lib/claude-session-title.js +6 -30
- package/template/coding-task-manager/lib/claude-table-layout.js +322 -0
- package/template/coding-task-manager/lib/client-diag-handler.js +5 -0
- package/template/coding-task-manager/lib/codex-config-guard.js +33 -3
- package/template/coding-task-manager/lib/codex-harness-qualification.js +12 -0
- package/template/coding-task-manager/lib/codex-launch-health.js +29 -2
- package/template/coding-task-manager/lib/codex-link-preparation.js +9 -8
- package/template/coding-task-manager/lib/codex-paths.js +2 -1
- package/template/coding-task-manager/lib/coding-agent-models.js +21 -30
- package/template/coding-task-manager/lib/coding-session-model-adapters.js +27 -2
- package/template/coding-task-manager/lib/coding-session-model-projection.js +5 -0
- package/template/coding-task-manager/lib/coding-session-model-runtime.js +1 -2
- package/template/coding-task-manager/lib/coding-session-model-state.js +10 -0
- package/template/coding-task-manager/lib/coding-session-model-sync-state.js +0 -1
- package/template/coding-task-manager/lib/conversation-import/cursor-guard-owner.js +10 -0
- package/template/coding-task-manager/lib/create/resolve-launch-params.js +8 -1
- package/template/coding-task-manager/lib/ctm-boot-lifecycle.js +17 -1
- package/template/coding-task-manager/lib/db-domain-tables.js +7 -0
- package/template/coding-task-manager/lib/db-domains.js +21 -2
- package/template/coding-task-manager/lib/db-owner-op-registry.js +7 -0
- package/template/coding-task-manager/lib/db-schema-source-files.js +1 -0
- package/template/coding-task-manager/lib/feature-manifest.js +1 -1
- package/template/coding-task-manager/lib/fs-watcher.js +3 -2
- package/template/coding-task-manager/lib/harness-history-transition.js +3 -3
- package/template/coding-task-manager/lib/headless-inflight-ops.js +203 -0
- package/template/coding-task-manager/lib/headless-missing-reply.js +42 -0
- package/template/coding-task-manager/lib/headless-term-service.js +55 -17
- package/template/coding-task-manager/lib/host-control-dial.js +167 -0
- package/template/coding-task-manager/lib/host-handoff-orchestrator.js +16 -2
- package/template/coding-task-manager/lib/host-handoff.js +51 -13
- package/template/coding-task-manager/lib/host-health-ledger.js +164 -12
- package/template/coding-task-manager/lib/host-self-truth-watchdog.js +4 -0
- package/template/coding-task-manager/lib/host-stats.js +328 -0
- package/template/coding-task-manager/lib/host-threadpool-evacuation.js +160 -0
- package/template/coding-task-manager/lib/host-threadpool-monitor.js +14 -1
- package/template/coding-task-manager/lib/hosted-input-dispatch.js +203 -0
- package/template/coding-task-manager/lib/hosted-sync-worker.js +113 -5
- package/template/coding-task-manager/lib/instance-id-ownership-manifest.js +4 -0
- package/template/coding-task-manager/lib/instance-manifest-runtime.js +3 -0
- package/template/coding-task-manager/lib/instance-manifest.js +13 -1
- package/template/coding-task-manager/lib/instance-sync-status.js +15 -0
- package/template/coding-task-manager/lib/launch-model-override.js +160 -1
- package/template/coding-task-manager/lib/launch-plan-worker.js +59 -2
- package/template/coding-task-manager/lib/lead-model-switch-runtime.js +57 -4
- package/template/coding-task-manager/lib/lead-model-switch.js +3 -2
- package/template/coding-task-manager/lib/lead-model-transition-store.js +61 -3
- package/template/coding-task-manager/lib/legacy-draft-cancellation-recovery.js +111 -0
- package/template/coding-task-manager/lib/login-tripwire.js +1 -0
- package/template/coding-task-manager/lib/machine-pairing.js +238 -0
- package/template/coding-task-manager/lib/machine-pool.js +409 -0
- package/template/coding-task-manager/lib/machine-registry.js +749 -0
- package/template/coding-task-manager/lib/machine-self.js +66 -0
- package/template/coding-task-manager/lib/main-thread-lint-exemptions.json +52 -4
- package/template/coding-task-manager/lib/media-journal-control-reader.js +473 -0
- package/template/coding-task-manager/lib/media-journal.js +84 -27
- package/template/coding-task-manager/lib/media-store-options.js +43 -15
- package/template/coding-task-manager/lib/migrations/v56-host-samples-and-machine-pool.js +76 -0
- package/template/coding-task-manager/lib/mirror-feed-sanitize.js +12 -3
- package/template/coding-task-manager/lib/model-proxy/anthropic-face.js +4 -0
- package/template/coding-task-manager/lib/model-proxy/chat-response-translators.js +3 -0
- package/template/coding-task-manager/lib/model-proxy/handoff.js +494 -0
- package/template/coding-task-manager/lib/model-proxy/lead-worker-picks.js +25 -0
- package/template/coding-task-manager/lib/model-proxy/native-lead-listener.js +61 -7
- package/template/coding-task-manager/lib/model-proxy/proxy-cli.js +200 -0
- package/template/coding-task-manager/lib/model-proxy/proxy-instance-record.js +257 -0
- package/template/coding-task-manager/lib/model-proxy/stream-accounting.js +205 -0
- package/template/coding-task-manager/lib/model-proxy/tokens.js +78 -0
- package/template/coding-task-manager/lib/model-proxy/upstream-outcome.js +9 -0
- package/template/coding-task-manager/lib/native-history-control.js +2 -2
- package/template/coding-task-manager/lib/native-lead-settings-client.js +2 -1
- package/template/coding-task-manager/lib/native-lead-tls.js +18 -4
- package/template/coding-task-manager/lib/oauth-proxy-supervisor.js +628 -64
- package/template/coding-task-manager/lib/owner-action-manifest-data.json +14 -0
- package/template/coding-task-manager/lib/painted-row-recorder.js +9 -1
- package/template/coding-task-manager/lib/prompt-submission-contract.js +21 -1
- package/template/coding-task-manager/lib/provider-login-broker.js +192 -9
- package/template/coding-task-manager/lib/provider-login-capture.js +153 -0
- package/template/coding-task-manager/lib/queue-draft-status-overlay.js +36 -0
- package/template/coding-task-manager/lib/raw-codex-history-window.js +5 -3
- package/template/coding-task-manager/lib/read-pool-client.js +5 -2
- package/template/coding-task-manager/lib/read-pool-op-registry.js +10 -1
- package/template/coding-task-manager/lib/recent-catalog-query.js +26 -0
- package/template/coding-task-manager/lib/recent-session-catalog-response.js +9 -0
- package/template/coding-task-manager/lib/remote-command-context.js +12 -0
- package/template/coding-task-manager/lib/remote-command-runtime.js +13 -1
- package/template/coding-task-manager/lib/remote-machine-catalog.js +1062 -0
- package/template/coding-task-manager/lib/remote-machine-create.js +693 -0
- package/template/coding-task-manager/lib/remote-machine-link.js +939 -0
- package/template/coding-task-manager/lib/remote-machine-proxy.js +520 -0
- package/template/coding-task-manager/lib/remote-session-forward.js +306 -0
- package/template/coding-task-manager/lib/remote-submission-status.js +6 -0
- package/template/coding-task-manager/lib/restart-outcome-truth.js +20 -3
- package/template/coding-task-manager/lib/restart-preflight.js +9 -2
- package/template/coding-task-manager/lib/restore-backoff-gate.js +10 -2
- package/template/coding-task-manager/lib/restore-prepare-retry.js +12 -5
- package/template/coding-task-manager/lib/restore-resume-batch.js +22 -1
- package/template/coding-task-manager/lib/resume-blocked-wire.js +62 -1
- package/template/coding-task-manager/lib/resume-cwd.js +13 -0
- package/template/coding-task-manager/lib/resume-from-store.js +12 -1
- package/template/coding-task-manager/lib/resume-origin-facts.js +38 -1
- package/template/coding-task-manager/lib/resume-preflight.js +21 -16
- package/template/coding-task-manager/lib/review-repo-admission.js +39 -6
- package/template/coding-task-manager/lib/review-repo-registry.js +17 -0
- package/template/coding-task-manager/lib/root-delivery-runtime.js +72 -15
- package/template/coding-task-manager/lib/root-delivery-selection.js +37 -1
- package/template/coding-task-manager/lib/root-prompt-admission.js +33 -2
- package/template/coding-task-manager/lib/root-prompt-flow.js +167 -33
- package/template/coding-task-manager/lib/scrollback-archive-store.js +7 -4
- package/template/coding-task-manager/lib/session-analysis-memory.js +2 -0
- package/template/coding-task-manager/lib/session-create/codex-native-provider-gate.js +218 -0
- package/template/coding-task-manager/lib/session-create/codex-resume-exit-classify.js +52 -0
- package/template/coding-task-manager/lib/session-create/delegate-worker.js +95 -6
- package/template/coding-task-manager/lib/session-create/identity.js +20 -1
- package/template/coding-task-manager/lib/session-create/prepared.js +69 -1
- package/template/coding-task-manager/lib/session-create/provider-launch-context.js +77 -0
- package/template/coding-task-manager/lib/session-create/provider-process.js +34 -37
- package/template/coding-task-manager/lib/session-create/response.js +30 -12
- package/template/coding-task-manager/lib/session-create/transcript.js +13 -4
- package/template/coding-task-manager/lib/session-create/worker-continuation.js +43 -1
- package/template/coding-task-manager/lib/session-create/worker-notices.js +94 -5
- package/template/coding-task-manager/lib/session-create/worker-observability.js +99 -7
- package/template/coding-task-manager/lib/session-create/worker-stop.js +11 -3
- package/template/coding-task-manager/lib/session-create/worker-wait-watcher.js +315 -0
- package/template/coding-task-manager/lib/session-geometry-authority-handler.js +10 -1
- package/template/coding-task-manager/lib/session-host-manager.js +152 -206
- package/template/coding-task-manager/lib/session-jobs.js +17 -9
- package/template/coding-task-manager/lib/session-lifecycle.js +18 -0
- package/template/coding-task-manager/lib/session-model-action-preconditions.js +9 -0
- package/template/coding-task-manager/lib/session-resource-sampler.js +19 -9
- package/template/coding-task-manager/lib/session-standup.js +67 -4
- package/template/coding-task-manager/lib/session-status-ledger.js +42 -3
- package/template/coding-task-manager/lib/session-status-runtime.js +45 -1
- package/template/coding-task-manager/lib/session-title-mirror.js +25 -57
- package/template/coding-task-manager/lib/session-transcript-trash.js +8 -1
- package/template/coding-task-manager/lib/startup-pointer-write.js +57 -0
- package/template/coding-task-manager/lib/state-sync/painted-frame-field.js +11 -0
- package/template/coding-task-manager/lib/storage/coding-session-model-store.js +21 -22
- package/template/coding-task-manager/lib/surviving-owner-bootstrap.js +7 -2
- package/template/coding-task-manager/lib/surviving-owner-recovery.js +2 -1
- package/template/coding-task-manager/lib/terminal-draft-http-status.js +25 -0
- package/template/coding-task-manager/lib/transcript-archiver.js +229 -229
- package/template/coding-task-manager/lib/transcript-frame-cache.js +12 -2
- package/template/coding-task-manager/lib/transcript-guard-job.js +55 -4
- package/template/coding-task-manager/lib/transcript-link.js +77 -0
- package/template/coding-task-manager/lib/transcript-manifest-store.js +8 -4
- package/template/coding-task-manager/lib/transcript-source.js +8 -3
- package/template/coding-task-manager/lib/transcript-store.js +40 -0
- package/template/coding-task-manager/lib/tunnel-lane-governor.js +6 -3
- package/template/coding-task-manager/lib/typing-interaction-trace.js +92 -0
- package/template/coding-task-manager/lib/typing-worker-stages.js +60 -0
- package/template/coding-task-manager/lib/visible-revision-watchdog.js +8 -12
- package/template/coding-task-manager/lib/wake-skip-reasons.js +46 -0
- package/template/coding-task-manager/lib/walle-supervisor.js +98 -14
- package/template/coding-task-manager/lib/worker-failure-classify.js +13 -1
- package/template/coding-task-manager/lib/ws/state-sync.js +19 -2
- package/template/coding-task-manager/lib/ws/terminal-attach.js +32 -1
- package/template/coding-task-manager/lib/ws-router.js +68 -1
- package/template/coding-task-manager/lib/ws-send-admission.js +22 -4
- package/template/coding-task-manager/oauth-proxy.js +99 -55
- package/template/coding-task-manager/package-lock.json +24 -0
- package/template/coding-task-manager/package.json +3 -0
- package/template/coding-task-manager/providers/codex-mcp-extract.js +121 -19
- package/template/coding-task-manager/providers/codex-mcp.js +14 -5
- package/template/coding-task-manager/public/css/app.css +279 -1
- package/template/coding-task-manager/public/css/reviews.css +4 -0
- package/template/coding-task-manager/public/index.html +294 -223
- package/template/coding-task-manager/public/js/app/machines-page.js +1252 -0
- package/template/coding-task-manager/public/js/app/models-tab.js +546 -36
- package/template/coding-task-manager/public/js/app/worktrees-panel.js +7 -5
- package/template/coding-task-manager/public/js/background-work.js +13 -7
- package/template/coding-task-manager/public/js/coding-session-model-presentation.js +44 -4
- package/template/coding-task-manager/public/js/core/session-commands.js +676 -0
- package/template/coding-task-manager/public/js/core/session-selectors.js +5 -1
- package/template/coding-task-manager/public/js/history-app-seam.js +26 -2
- package/template/coding-task-manager/public/js/history-painted-rows.js +17 -2
- package/template/coding-task-manager/public/js/history-reader-park.js +13 -1
- package/template/coding-task-manager/public/js/history-scroller.js +187 -9
- package/template/coding-task-manager/public/js/history-transcript-pages.js +5 -5
- package/template/coding-task-manager/public/js/machine-pool-shared.js +436 -0
- package/template/coding-task-manager/public/js/private-state-scope.js +31 -3
- package/template/coding-task-manager/public/js/prompt-submission-client.js +173 -8
- package/template/coding-task-manager/public/js/prompt-submission-tray.js +281 -0
- package/template/coding-task-manager/public/js/queue-panel-submission-reconcile.js +174 -1
- package/template/coding-task-manager/public/js/reviews.js +7 -3
- package/template/coding-task-manager/public/js/root-draft-lifetime.js +139 -2
- package/template/coding-task-manager/public/js/root-queue-builder-lifetime.js +16 -0
- package/template/coding-task-manager/public/js/row-join.js +4 -2
- package/template/coding-task-manager/public/js/session-model-picker.js +1 -1
- package/template/coding-task-manager/public/js/session-search-utils.js +46 -19
- package/template/coding-task-manager/public/js/state-sync-client.js +4 -0
- package/template/coding-task-manager/public/js/terminal/runtime-02.js +16 -7
- package/template/coding-task-manager/public/js/terminal/runtime-03.js +41 -0
- package/template/coding-task-manager/public/js/terminal/runtime-04.js +41 -4
- package/template/coding-task-manager/public/js/terminal/runtime-12.js +52 -2
- package/template/coding-task-manager/public/js/terminal/runtime-16.js +12 -12
- package/template/coding-task-manager/public/js/terminal/runtime-18.js +14 -0
- package/template/coding-task-manager/public/js/terminal/runtime-19.js +8 -4
- package/template/coding-task-manager/public/js/terminal/runtime-20.js +210 -73
- package/template/coding-task-manager/public/js/terminal/runtime-21.js +19 -6
- package/template/coding-task-manager/public/js/terminal/runtime-22.js +86 -0
- package/template/coding-task-manager/public/js/terminal-history-viewport.js +1 -1
- package/template/coding-task-manager/public/js/terminal-wheel.js +39 -2
- package/template/coding-task-manager/public/js/walle/chat-conversation.js +11 -3
- package/template/coding-task-manager/public/js/walle-session.js +30 -7
- package/template/coding-task-manager/public/m/app.css +226 -8
- package/template/coding-task-manager/public/m/app.js +502 -9
- package/template/coding-task-manager/public/m/index.html +38 -1
- package/template/coding-task-manager/public/m/machines.js +1313 -0
- package/template/coding-task-manager/public/m/pool-failover.js +391 -0
- package/template/coding-task-manager/public/m/private-queue-actions.js +26 -7
- package/template/coding-task-manager/public/m/sw.js +5 -0
- package/template/coding-task-manager/queue-engine.js +13 -0
- package/template/coding-task-manager/server/approvals.js +5 -6
- package/template/coding-task-manager/server/boot.js +136 -17
- package/template/coding-task-manager/server.js +902 -239
- package/template/coding-task-manager/session-integrity.js +7 -9
- package/template/coding-task-manager/workers/db-owner-worker.js +53 -7
- package/template/coding-task-manager/workers/read-pool-worker.js +17 -6
- package/template/coding-task-manager/workers/session-host-pool-process.js +18 -4
- package/template/coding-task-manager/workers/session-host-process.js +14 -3
- package/template/coding-task-manager/workers/transcript-archive-worker.js +1 -1
- package/template/coding-task-manager/workers/worktree-worker.js +34 -0
- package/template/package-lock.json +2 -2
- package/template/package.json +1 -1
- package/template/scripts/conversation-storage-v2-migration.js +78 -11
- package/template/shared/conversation-storage-v2-contract.js +42 -6
- package/template/shared/fixtures/worker-status-payloads.json +392 -0
- package/template/shared/git-remote-key.js +83 -0
- package/template/shared/host-identity.js +98 -2
- package/template/shared/owner-write-safety.js +135 -0
- package/template/shared/public-runtime.js +13 -5
- package/template/shared/release-schema.json +3 -2
- package/template/shared/report-citations.js +14 -0
- package/template/shared/sqlite-write-lock.js +361 -223
- package/template/shared/storage/contract.js +35 -3
- package/template/wall-e/agent.js +21 -0
- package/template/wall-e/api-walle.js +5 -0
- package/template/wall-e/bin/brain-purge-legacy-ctm.js +3 -2
- package/template/wall-e/bin/walle-mcp-stdio.js +12 -6
- package/template/wall-e/brain/helper-rules-schema.js +129 -0
- package/template/wall-e/brain/migrations.js +51 -22
- package/template/wall-e/brain/model-deployment-facts.js +31 -1
- package/template/wall-e/brain/owner-call-whitelist.js +16 -0
- package/template/wall-e/brain/schema-ensures.js +22 -0
- package/template/wall-e/brain.js +1 -1
- package/template/wall-e/coding/journal-dispatcher.js +51 -0
- package/template/wall-e/coding/session-journal.js +28 -40
- package/template/wall-e/coding-orchestrator.js +23 -26
- package/template/wall-e/http/auth.js +18 -1
- package/template/wall-e/http/blog-views-api.js +318 -0
- package/template/wall-e/http/helper-rules-api.js +321 -0
- package/template/wall-e/http/model-proxy-providers.js +3 -1
- package/template/wall-e/http/telemetry-api.js +12 -0
- package/template/wall-e/lib/blog-view-policy.js +88 -0
- package/template/wall-e/lib/blog-view-store.js +169 -0
- package/template/wall-e/lib/client-config-lock.js +2 -1
- package/template/wall-e/lib/coding-journal-writer-child-client.js +67 -18
- package/template/wall-e/lib/error-kinds.js +10 -1
- package/template/wall-e/lib/feature-manifest.js +1 -1
- package/template/wall-e/lib/helper-rules/cell-state.js +123 -0
- package/template/wall-e/lib/helper-rules/evaluate.js +357 -0
- package/template/wall-e/lib/helper-rules/explore-rubric.md +12 -0
- package/template/wall-e/lib/helper-rules/grade.js +277 -0
- package/template/wall-e/lib/helper-rules/label.js +247 -0
- package/template/wall-e/lib/helper-rules/lead-call-hook.js +522 -0
- package/template/wall-e/lib/helper-rules/store.js +667 -0
- package/template/wall-e/lib/mcp-integration.js +5 -6
- package/template/wall-e/lib/runtime-worker-pool.js +1 -0
- package/template/wall-e/lib/scheduler-worker-jobs.js +6 -0
- package/template/wall-e/lib/telemetry-db-schema.js +37 -0
- package/template/wall-e/lib/telemetry-process-client.js +76 -1
- package/template/wall-e/llm/default-fallback.js +4 -0
- package/template/wall-e/llm/model-catalog.js +13 -4
- package/template/wall-e/llm/model-roles.js +6 -0
- package/template/wall-e/llm/portkey-http.js +150 -0
- package/template/wall-e/llm/portkey-sync.js +15 -145
- package/template/wall-e/llm/worker-mcp-routing.js +61 -0
- package/template/wall-e/llm/worker-route.js +43 -1
- package/template/wall-e/loops/brain-custom-writes.js +45 -0
- package/template/wall-e/mcp-protocol-contract.js +41 -1
- package/template/wall-e/mcp-server.js +13 -2
- package/template/wall-e/mcp-worker-schemas.js +20 -2
- package/template/wall-e/memory/ctm-context-client.js +25 -5
- package/template/wall-e/shared/release-schema.json +3 -2
- package/template/wall-e/shared/sqlite-write-lock.js +361 -223
- package/template/wall-e/shared/storage/contract.js +35 -3
- package/template/wall-e/skills/_templates/delegate-worker/VERSION +1 -1
- package/template/wall-e/skills/_templates/delegate-worker/released-sha256.json +6 -0
- package/template/wall-e/skills/_templates/delegate-worker/templates/claude/SKILL.md +7 -2
- package/template/wall-e/skills/_templates/delegate-worker/templates/codex/SKILL.md +7 -2
- package/template/wall-e/tools/local-tools.js +6 -4
- package/template/wall-e/workers/brain-owner-worker.js +9 -0
- package/template/wall-e/workers/coding-journal-writer-child.js +8 -1
- package/template/wall-e/workers/telemetry-worker.js +8 -0
|
@@ -5,7 +5,6 @@ const { dispatchOwnedInputAck } = require('./host-input-ack');
|
|
|
5
5
|
const { EventEmitter } = require('node:events');
|
|
6
6
|
const { fork } = require('node:child_process');
|
|
7
7
|
const fs = require('node:fs');
|
|
8
|
-
const net = require('node:net');
|
|
9
8
|
const path = require('node:path');
|
|
10
9
|
const crypto = require('node:crypto');
|
|
11
10
|
const { resolveRealNode } = require('./real-node'); const { hostDiagnosticFrame } = require('./host-diagnostic-frame');
|
|
@@ -18,13 +17,14 @@ const {
|
|
|
18
17
|
isProcessAlive,
|
|
19
18
|
probeHostAliveDetailed,
|
|
20
19
|
} = require('./host-registry');
|
|
21
|
-
const {
|
|
20
|
+
const { HOST_HANDOFF_EXIT_CODE } = require('./host-control-protocol');
|
|
21
|
+
const { dialControlSocketWithRetry: _dialControlSocketWithRetry } = require('./host-control-dial');
|
|
22
|
+
const { postSocketFrameObserved, postIpcFrameObserved, postSelectedSocket, notePostRefusal, withAdapterPostObservation, forwardPostObservation, observeAdapterWrite } = require('./hosted-input-dispatch');
|
|
22
23
|
const { isHostedAdapterLive, isHostedHeadlessLive, isHostedSessionStateAdoptable } = require('./hosted-adapter-liveness');
|
|
23
|
-
const { hostRuntimeCompatibilityDecision } = require('./host-runtime-compatibility');
|
|
24
24
|
const { hashClosureFiles } = require('./host-closure-hash');
|
|
25
25
|
const { headlessMissingReplies } = require('./headless-missing-reply');
|
|
26
|
-
const { resolveDialRetryDeadline, DIAL_MAX_STALL_EXTENSION_RATIO } = require('./host-dial-stall-clock');
|
|
27
26
|
const { redialAdoptedHost } = require('./adopted-host-redial');
|
|
27
|
+
const { sanitizeSessionOps, createOverdueEdgeTrigger } = require('./headless-inflight-ops'); // WP-0 (D-6/S-12): frame sessionOps + one-shot overdue edge
|
|
28
28
|
const { dialHostState, shutdownHostSession } = require('./host-adopt-dial');
|
|
29
29
|
const handoffOrchestrator = require('./host-handoff-orchestrator');
|
|
30
30
|
const { applyModelHostReceipt, applyStartedModelHostReceipt } = require('./model-host-receipt');
|
|
@@ -49,162 +49,10 @@ function _openHostLogFd(dataDir, hostId) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// A1: the wire leaf (guard, encode, write, swallowed-failure boundary) moved to
|
|
53
|
+
// lib/hosted-input-dispatch.js, where it observes its own outcome; this stays VOID for callers.
|
|
52
54
|
function _writeFrame(conn, obj) {
|
|
53
|
-
|
|
54
|
-
try { conn.write(encodeFrame(obj)); } catch { /* expected: connection may already be gone */ }
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Dial a host control socket within a stall-aware deadline. The first state frame
|
|
58
|
-
// is judged by hostRuntimeCompatibilityDecision (a differing closure hash is adoptable); later frames
|
|
59
|
-
// route to onFrame, while onState exposes adoptable session metadata.
|
|
60
|
-
function _dialControlSocketWithRetry(socketPath, {
|
|
61
|
-
serverBootId, onFrame, onState, timeoutMs = 5000, retryDelayMs = 200,
|
|
62
|
-
protocolVersion = PROTOCOL_VERSION,
|
|
63
|
-
} = {}) {
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
const budgetMs = Math.max(0, Number(timeoutMs) || 5000);
|
|
66
|
-
// Stall-aware, not fixed wall clock: see lib/host-dial-stall-clock.js for the incident where
|
|
67
|
-
// this deadline drained during the server's OWN boot freeze and a healthy pooled host was
|
|
68
|
-
// SIGTERM'd (taking its live sessions with it). `deadline` is reassigned as stall is credited
|
|
69
|
-
// back; `_stallExtendedMs` is the running total and is capped, so a permanently stalled
|
|
70
|
-
// server still times out rather than waiting forever.
|
|
71
|
-
let deadline = Date.now() + budgetMs;
|
|
72
|
-
let _stallExtendedMs = 0;
|
|
73
|
-
const maxStallExtensionMs = budgetMs * DIAL_MAX_STALL_EXTENSION_RATIO;
|
|
74
|
-
let settled = false;
|
|
75
|
-
let retryTimer = null, deadlineTimer = null, activeConn = null;
|
|
76
|
-
function finishOk(conn) {
|
|
77
|
-
if (settled) return;
|
|
78
|
-
settled = true;
|
|
79
|
-
clearTimeout(deadlineTimer);
|
|
80
|
-
resolve(conn);
|
|
81
|
-
}
|
|
82
|
-
function finishFail(err) {
|
|
83
|
-
if (settled) return;
|
|
84
|
-
settled = true;
|
|
85
|
-
clearTimeout(retryTimer); clearTimeout(deadlineTimer);
|
|
86
|
-
try { activeConn?.destroy(); } catch { /* expected: connection may already be gone */ }
|
|
87
|
-
reject(err || new Error('control socket dial failed'));
|
|
88
|
-
}
|
|
89
|
-
function armDeadlineWatchdog(scheduledAt = Date.now()) {
|
|
90
|
-
const delayMs = Math.max(1, deadline - scheduledAt);
|
|
91
|
-
deadlineTimer = setTimeout(() => {
|
|
92
|
-
const firedAt = Date.now();
|
|
93
|
-
const credited = resolveDialRetryDeadline({ deadline, scheduledAt, firedAt, retryDelayMs: delayMs,
|
|
94
|
-
extendedMs: _stallExtendedMs, maxExtensionMs: maxStallExtensionMs });
|
|
95
|
-
deadline = credited.deadline; _stallExtendedMs = credited.extendedMs;
|
|
96
|
-
if (firedAt < deadline) armDeadlineWatchdog(firedAt); else finishFail(new Error(`control socket handshake timed out after ${timeoutMs}ms`));
|
|
97
|
-
}, delayMs);
|
|
98
|
-
deadlineTimer.unref?.();
|
|
99
|
-
}
|
|
100
|
-
function scheduleRetry() {
|
|
101
|
-
if (settled) return;
|
|
102
|
-
if (Date.now() >= deadline) {
|
|
103
|
-
finishFail(new Error(
|
|
104
|
-
`control socket dial timed out after ${timeoutMs}ms`
|
|
105
|
-
+ (_stallExtendedMs > 0 ? ` (+${_stallExtendedMs}ms credited for main-loop stall)` : ''),
|
|
106
|
-
));
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
const scheduledAt = Date.now();
|
|
110
|
-
retryTimer = setTimeout(() => {
|
|
111
|
-
// A retry that fires far later than it was armed for means OUR event loop was starved --
|
|
112
|
-
// that time is not evidence about the child, so give it back before re-testing the
|
|
113
|
-
// deadline above. Bounded by maxStallExtensionMs.
|
|
114
|
-
const credited = resolveDialRetryDeadline({
|
|
115
|
-
deadline,
|
|
116
|
-
scheduledAt,
|
|
117
|
-
firedAt: Date.now(),
|
|
118
|
-
retryDelayMs,
|
|
119
|
-
extendedMs: _stallExtendedMs,
|
|
120
|
-
maxExtensionMs: maxStallExtensionMs,
|
|
121
|
-
});
|
|
122
|
-
deadline = credited.deadline;
|
|
123
|
-
_stallExtendedMs = credited.extendedMs;
|
|
124
|
-
attempt();
|
|
125
|
-
}, retryDelayMs);
|
|
126
|
-
retryTimer.unref?.();
|
|
127
|
-
}
|
|
128
|
-
function attempt() {
|
|
129
|
-
if (settled) return;
|
|
130
|
-
// Do NOT dial before the host has created its socket. A connect to a missing unix socket
|
|
131
|
-
// makes node build an ExceptionWithHostPort and capture its stack, and this loop runs every
|
|
132
|
-
// retryDelayMs across every concurrent dial (pool + per-session + registry probes). Measured
|
|
133
|
-
// 2026-08-23 with the server's own auto-CPU-profiler, during a boot where a pooled host was
|
|
134
|
-
// being started:
|
|
135
|
-
// top self-time frames: ExceptionWithHostPort (errors:765) 3290ms
|
|
136
|
-
// | defaultPrepareStackTrace (errors:95) 3256ms
|
|
137
|
-
// | (garbage collector) 752ms | checkError (destroy:33) 512ms
|
|
138
|
-
// | scheduleRetry (session-host-manager.js:89) 192ms
|
|
139
|
-
// i.e. ~6.5s of main-loop CPU spent building the retry loop's OWN connection errors. That
|
|
140
|
-
// block (`[perf-lag] Event loop blocked 6102ms`) is what then starved the very handshake it
|
|
141
|
-
// was polling for, until the dial "timed out" and the manager SIGTERM'd a healthy pooled
|
|
142
|
-
// host, killing its live sessions. A self-inflicted starvation loop.
|
|
143
|
-
//
|
|
144
|
-
// fs.access (async -- never sync I/O on the main loop) is a cheap stat that produces no
|
|
145
|
-
// exception object. This is a fast-path skip only: once the socket exists the dial below is
|
|
146
|
-
// byte-identical to before, and a socket that appears between this check and the connect
|
|
147
|
-
// still takes the ordinary error path.
|
|
148
|
-
fs.access(socketPath, fs.constants.F_OK, (missing) => {
|
|
149
|
-
if (settled) return;
|
|
150
|
-
if (missing) { scheduleRetry(); return; }
|
|
151
|
-
_connect();
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
function _connect() {
|
|
155
|
-
if (settled) return;
|
|
156
|
-
let conn;
|
|
157
|
-
let helloAcked = false;
|
|
158
|
-
try {
|
|
159
|
-
conn = net.createConnection(socketPath);
|
|
160
|
-
activeConn = conn;
|
|
161
|
-
} catch {
|
|
162
|
-
scheduleRetry();
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
const decoder = createFrameDecoder({
|
|
166
|
-
onFrame: (msg) => {
|
|
167
|
-
if (!helloAcked) {
|
|
168
|
-
if (msg && msg.type === 'state') {
|
|
169
|
-
const diskClosureHash = hashClosureFiles(Array.isArray(msg.closureFiles) ? msg.closureFiles : []), hostClosureHash = String(msg.closureHash || '');
|
|
170
|
-
const compatibility = { ...hostRuntimeCompatibilityDecision({
|
|
171
|
-
expectedProtocol: protocolVersion, actualProtocol: msg.protocolVersion,
|
|
172
|
-
expectedFloor: FLOOR_VERSION, actualFloor: msg.floorVersion, diskClosureHash, hostClosureHash,
|
|
173
|
-
}), hostClosureHash, diskClosureHash };
|
|
174
|
-
if (!compatibility.compatible) {
|
|
175
|
-
helloAcked = true;
|
|
176
|
-
try { conn.destroy(); } catch { /* expected: already gone */ }
|
|
177
|
-
finishFail(Object.assign(
|
|
178
|
-
new Error(`control socket host compatibility mismatch (${compatibility.reason})`),
|
|
179
|
-
{ code: 'HOST_INCOMPATIBLE', compatibilityReason: compatibility.reason },
|
|
180
|
-
));
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
helloAcked = true;
|
|
184
|
-
try { onState?.(msg, compatibility); } catch { /* expected: caller's onState must not wedge the dial */ }
|
|
185
|
-
finishOk(conn);
|
|
186
|
-
}
|
|
187
|
-
return;
|
|
188
|
-
}
|
|
189
|
-
if (typeof onFrame === 'function') onFrame(msg);
|
|
190
|
-
},
|
|
191
|
-
onError: () => { try { conn.destroy(); } catch { /* expected: already gone */ } },
|
|
192
|
-
});
|
|
193
|
-
conn.on('data', (chunk) => decoder.push(chunk));
|
|
194
|
-
conn.on('connect', () => {
|
|
195
|
-
try {
|
|
196
|
-
conn.write(encodeFrame({ type: 'hello', serverBootId, connectionRole: CONTROL_CONNECTION_ROLE.CONTROLLER, lastSeq: 0, protocolVersion, floorVersion: FLOOR_VERSION }));
|
|
197
|
-
} catch {
|
|
198
|
-
try { conn.destroy(); } catch { /* expected: already gone */ }
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
conn.on('error', () => { /* expected: close follows error and owns the sole retry */ });
|
|
202
|
-
conn.on('close', () => { if (!helloAcked) scheduleRetry(); });
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
attempt();
|
|
206
|
-
armDeadlineWatchdog();
|
|
207
|
-
});
|
|
55
|
+
postSocketFrameObserved(conn, obj);
|
|
208
56
|
}
|
|
209
57
|
|
|
210
58
|
const DEFAULT_START_TIMEOUT_MS = 5000;
|
|
@@ -248,6 +96,26 @@ function _sleep(ms) {
|
|
|
248
96
|
|
|
249
97
|
const TERMINATE_ACK_TIMEOUT_MS = 1500;
|
|
250
98
|
|
|
99
|
+
// WP-4 (clock-free-tests-followups-r4-2026-10-24.html §5 R-7, §6.5): stamp the FIRST
|
|
100
|
+
// main-thread touch of a headless message with the receiving thread's own clock, so server.js
|
|
101
|
+
// can price the receiver-loop leg (`frame-posted` -> `frame-arrived`) separately from the work
|
|
102
|
+
// it does after (`mirror-revision`). Read-only instrumentation: the property is NON-enumerable, so
|
|
103
|
+
// the message's shape is unchanged for every consumer that compares, spreads or serializes it (a
|
|
104
|
+
// pool host's `serialized` missing reply is deep-equal to the shared headlessMissingReplies table),
|
|
105
|
+
// and no decision anywhere reads it; server.js reads it off the same object. One helper for all three
|
|
106
|
+
// transports (the dedicated host's IPC channel and control socket both funnel through
|
|
107
|
+
// HostedPtyAdapter._handleChildMessage; the pool's fallback and the legacy worker path call it
|
|
108
|
+
// themselves), so the value means the same thing whichever carried the frame. Returns the
|
|
109
|
+
// message so a call site can chain it into its own emit.
|
|
110
|
+
function _stampMainArrival(message) {
|
|
111
|
+
if (message && typeof message === 'object') {
|
|
112
|
+
Object.defineProperty(message, '_mainArrivedAt', {
|
|
113
|
+
value: Date.now(), enumerable: false, writable: true, configurable: true,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return message;
|
|
117
|
+
}
|
|
118
|
+
|
|
251
119
|
// WP-3: bound for adoptHost's dial. Plain const, not a flag -- a boot reconcile
|
|
252
120
|
// pass adopting a handful of hosts is not a hot path.
|
|
253
121
|
//
|
|
@@ -405,6 +273,15 @@ class HostedPtyAdapter {
|
|
|
405
273
|
this.closed = true;
|
|
406
274
|
this._manager?._unregister(this.sessionId, this);
|
|
407
275
|
if (this._hostId) this._manager?._removeHostRecordAsync(this._hostId);
|
|
276
|
+
// WP-3 (session-stops-followups-2026-10-24.html, D-5): a dedicated host's
|
|
277
|
+
// death announces itself exactly like the pool's and an adopted host's, so
|
|
278
|
+
// the constructor's single 'host-exit' listener drops this hostId's frame
|
|
279
|
+
// clock and server.js's listener drops its readiness-ledger entry. Without it
|
|
280
|
+
// both outlived the host -- and since a dedicated hostId IS the sessionId (set
|
|
281
|
+
// in _startDedicated above), the next host for that session inherited the dead
|
|
282
|
+
// one's ledger misses (final-review fix I6, pool-only until now). Sits AFTER
|
|
283
|
+
// the `if (this.closed) return;` guard, so it fires once per host.
|
|
284
|
+
if (this._hostId) this._manager?.emit?.('host-exit', { hostId: this._hostId, kind: 'dedicated' });
|
|
408
285
|
this._emitExitOnce({
|
|
409
286
|
exitCode: Number.isFinite(code) ? code : 1,
|
|
410
287
|
signal: signal || null,
|
|
@@ -465,32 +342,30 @@ class HostedPtyAdapter {
|
|
|
465
342
|
|
|
466
343
|
_post(message) {
|
|
467
344
|
if (this._pooled) {
|
|
468
|
-
|
|
345
|
+
// A1: only a truly ABSENT manager refuses here; a present manager keeps its COPY + forwarded scope.
|
|
346
|
+
if (this._manager === undefined || this._manager === null) { notePostRefusal(message); return false; }
|
|
347
|
+
const forwarded = { ...message, sessionId: message.sessionId || this.sessionId };
|
|
348
|
+
return forwardPostObservation(message, forwarded, () => this._manager?._postToPool(forwarded)) || false;
|
|
469
349
|
}
|
|
470
|
-
if (this.closed) return false;
|
|
350
|
+
if (this.closed) { notePostRefusal(message); return false; }
|
|
471
351
|
// WP-1 (deliverable 2): once the control flip has succeeded, ALL control +
|
|
472
352
|
// data goes over the socket -- IPC is no longer used to send.
|
|
473
353
|
if (this._transport === 'socket' && this._socketConn && !this._socketConn.destroyed) {
|
|
474
|
-
|
|
475
|
-
_writeFrame(this._socketConn, message);
|
|
476
|
-
return true;
|
|
477
|
-
} catch (err) {
|
|
478
|
-
this._events.emit('host-error', err);
|
|
479
|
-
return false;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
if (!this._child || !this._child.connected) return false;
|
|
483
|
-
try {
|
|
484
|
-
this._child.send(message);
|
|
485
|
-
return true;
|
|
486
|
-
} catch (err) {
|
|
487
|
-
this._events.emit('host-error', err);
|
|
488
|
-
return false;
|
|
354
|
+
return postSelectedSocket(() => this._socketConn, message, (err) => this._events.emit('host-error', err));
|
|
489
355
|
}
|
|
356
|
+
// The helper owns the ONE missing/disconnected refusal AND the legacy try/send/host-error boundary.
|
|
357
|
+
return postIpcFrameObserved(this._child, message, (err) => this._events.emit('host-error', err)).posted;
|
|
490
358
|
}
|
|
491
359
|
|
|
492
360
|
_handleChildMessage(msg) {
|
|
493
361
|
if (!msg || typeof msg !== 'object') return;
|
|
362
|
+
// WP-3 (session-stops-mid-job-2026-10-24.html, D-10): every frame a host
|
|
363
|
+
// sends -- PTY data, exit, threadpool report, serialize reply, control
|
|
364
|
+
// replies -- proves it alive. Recorded under the SAME hostId the readiness
|
|
365
|
+
// ledger keys on (lib/ws/state-sync.js derives it via
|
|
366
|
+
// SessionHostManager.hostIdForSession), so a pooled session records under
|
|
367
|
+
// its pool's `pool-<pid>`, not under its own sessionId. Cheap: one Map.set.
|
|
368
|
+
this._manager?._noteHostFrame?.(this._manager?.hostIdForSession?.(this.sessionId) || this._hostId);
|
|
494
369
|
switch (msg.type) {
|
|
495
370
|
case 'ready':
|
|
496
371
|
if (this._hostId) {
|
|
@@ -536,7 +411,10 @@ class HostedPtyAdapter {
|
|
|
536
411
|
});
|
|
537
412
|
return;
|
|
538
413
|
case 'headless-message':
|
|
539
|
-
|
|
414
|
+
// WP-4 (R-7): the first main-thread touch of this frame on BOTH dedicated-host
|
|
415
|
+
// transports -- the IPC channel's child.on('message') and the control socket's
|
|
416
|
+
// onFrame --- converge on this switch.
|
|
417
|
+
this._manager?._emitHeadlessMessage(_stampMainArrival(msg.message || {}));
|
|
540
418
|
return;
|
|
541
419
|
case 'snapshot':
|
|
542
420
|
this._headlessReady = true;
|
|
@@ -616,7 +494,19 @@ class HostedPtyAdapter {
|
|
|
616
494
|
// exists once the host's 'input-ack' frame comes back (see _handleChildMessage's
|
|
617
495
|
// 'input-ack' case and the manager's onInputAck hook). `inputSeq` correlates the two.
|
|
618
496
|
write(data, { inputSeq } = {}) {
|
|
619
|
-
|
|
497
|
+
// A1: the frame is built here exactly as before, then handed to the ACTUAL selected `_post`
|
|
498
|
+
// through the observation scope, so an observed write can report what THIS route did while the
|
|
499
|
+
// legacy `=== true` Boolean keeps its exact meaning.
|
|
500
|
+
const message = { type: 'input', sessionId: this.sessionId, data: String(data || ''), inputSeq: Number(inputSeq) || 0 };
|
|
501
|
+
return withAdapterPostObservation(this, message, () => this._post(message)) === true;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// A1: observe ONE dispatch through the ACTUAL selected writer (never a prototype bypass). The
|
|
505
|
+
// result is diagnostic data -- `posted` mirrors the selected writer's own legacy result and the
|
|
506
|
+
// disposition says only how much this module actually saw. It is not byte-write, ack or
|
|
507
|
+
// no-post proof, and it grants no caller any withdrawal authority.
|
|
508
|
+
writeObserved(data, { inputSeq } = {}) {
|
|
509
|
+
return observeAdapterWrite(this, () => this.write(data, { inputSeq }));
|
|
620
510
|
}
|
|
621
511
|
|
|
622
512
|
resize(cols, rows) {
|
|
@@ -793,10 +683,28 @@ class SessionHostManager extends EventEmitter {
|
|
|
793
683
|
// only, same seam shape as _onDiagnostic -- never a path that kills/respawns/migrates
|
|
794
684
|
// anything on 'stalled' (see _handleThreadpoolFrame below and its AC-0c test).
|
|
795
685
|
this._threadpoolStates = new Map();
|
|
686
|
+
// WP-3 (session-stops-mid-job-2026-10-24.html, D-10): hostId -> the last
|
|
687
|
+
// instant ANY frame arrived from that host. This is the readiness ledger's
|
|
688
|
+
// ONE liveness input (server.js injects `lastFrameAt` into it): a hard
|
|
689
|
+
// serialize miss on a host whose lastFrameAt is newer than the request was
|
|
690
|
+
// issued is 'degraded' (readiness), never a kill. Written by
|
|
691
|
+
// HostedPtyAdapter._handleChildMessage and _handleThreadpoolFrame below on
|
|
692
|
+
// every received frame; dropped when the manager announces 'host-exit'.
|
|
693
|
+
this._hostFrameAt = new Map();
|
|
694
|
+
// WP-3 (session-stops-followups-2026-10-24.html, D-6): the ONE place a host's
|
|
695
|
+
// frame clock is dropped. Every death path announces itself as
|
|
696
|
+
// 'host-exit {hostId, kind}' -- pool, adopted (lib/adopted-host-redial.js) and
|
|
697
|
+
// dedicated (HostedPtyAdapter's child 'exit' handler below) -- so a future death
|
|
698
|
+
// path is covered by emitting that event alone, and no call site can forget the
|
|
699
|
+
// clock (the pre-D-6 inline delete at the pool exit left the adopted and
|
|
700
|
+
// dedicated paths leaking it).
|
|
701
|
+
this.on('host-exit', ({ hostId } = {}) => { if (hostId) this._hostFrameAt.delete(String(hostId)); });
|
|
796
702
|
this._onThreadpoolReport = typeof options.onThreadpoolReport === 'function' ? options.onThreadpoolReport : null;
|
|
797
703
|
// D-2 (pty-host-threadpool-stranded-waiters-2026-09-25.html): report-only seam for
|
|
798
704
|
// input-ack frames -- server.js's _onHostInputAck. Same shape as onThreadpoolReport.
|
|
799
705
|
this._onInputAck = typeof options.onInputAck === 'function' ? options.onInputAck : null; this._onSessionDiagnostic = typeof options.onSessionDiagnostic === 'function' ? options.onSessionDiagnostic : null; // probe: host-diagnostic rows
|
|
706
|
+
// WP-0 (D-6): at most one report-only headless-op-overdue diagnostic per (hostId, sid8, seq).
|
|
707
|
+
this._headlessOpOverdue = createOverdueEdgeTrigger();
|
|
800
708
|
}
|
|
801
709
|
|
|
802
710
|
createPty(options = {}) {
|
|
@@ -1152,12 +1060,18 @@ class SessionHostManager extends EventEmitter {
|
|
|
1152
1060
|
// (never a per-tick echo -- the monitor itself already only frames on transition or once
|
|
1153
1061
|
// per its own report interval, but this dedupes defensively against redelivery), and
|
|
1154
1062
|
// forwards every frame to the optional onThreadpoolReport hook (server.js's __host__
|
|
1155
|
-
// diagnostic-row writer + golden-signals feed) -- report-only, exactly like _onDiagnostic;
|
|
1156
|
-
//
|
|
1063
|
+
// diagnostic-row writer + golden-signals feed) -- report-only, exactly like _onDiagnostic; nothing
|
|
1064
|
+
// here kills/respawns/migrates a host (09-25 AC-0c). WP-3 supersedes that for the SUPERVISOR only: server.js's onThreadpoolReport -> hostHealth.recordThreadpool -> evacuateStalledHost evacuates a stalled host (docs/stale-pty-host-evacuation-2026-10-24.html §5 D-3, §9 S-6).
|
|
1157
1065
|
_handleThreadpoolFrame(hostId, msg) {
|
|
1158
1066
|
if (!msg || typeof msg !== 'object') return;
|
|
1067
|
+
// WP-3 (D-10): a threadpool report is a frame like any other -- the host's
|
|
1068
|
+
// main thread is alive and talking even when its threadpool is wedged (the
|
|
1069
|
+
// exact 2026-10-24 shape: stalled for 68 min while PTY I/O kept flowing).
|
|
1070
|
+
this._noteHostFrame(hostId);
|
|
1159
1071
|
const state = msg.state === 'stalled' ? 'stalled' : 'ok';
|
|
1160
1072
|
const prev = this._threadpoolStates.get(hostId);
|
|
1073
|
+
// WP-0 (D-6): the frame's per-session view, sanitized to strings/numbers and capped at 5.
|
|
1074
|
+
const sessionOps = sanitizeSessionOps(msg.sessionOps, 5);
|
|
1161
1075
|
const snapshot = {
|
|
1162
1076
|
hostId,
|
|
1163
1077
|
pid: Number.isFinite(msg.pid) ? msg.pid : (prev?.pid ?? null),
|
|
@@ -1167,12 +1081,22 @@ class SessionHostManager extends EventEmitter {
|
|
|
1167
1081
|
requestsPerMin: Number(msg.requestsPerMin) || 0,
|
|
1168
1082
|
byType: msg.byType && typeof msg.byType === 'object' ? { ...msg.byType } : {},
|
|
1169
1083
|
probeMs: Number.isFinite(msg.probeMs) ? msg.probeMs : null,
|
|
1084
|
+
sessionOps,
|
|
1170
1085
|
receivedAt: Date.now(),
|
|
1171
1086
|
};
|
|
1172
1087
|
this._threadpoolStates.set(hostId, snapshot);
|
|
1173
1088
|
if (!prev || prev.state !== state) {
|
|
1174
1089
|
this.logger.warn?.(`[session-host-pool] threadpool-${state} hostId=${hostId} pid=${snapshot.pid} pendingRequests=${snapshot.pendingRequests} oldestPendingMs=${snapshot.oldestPendingMs}`);
|
|
1175
1090
|
}
|
|
1091
|
+
// WP-0 (D-6/AC-0c): one report-only diagnostic per (hostId, sid8, seq) at >= 30 s. Never
|
|
1092
|
+
// rejects/times out/reorders an op, and never touches host or session state.
|
|
1093
|
+
for (const hit of this._headlessOpOverdue.next(sessionOps, hostId, (sid8) => {
|
|
1094
|
+
for (const sid of this.hosts.keys()) if (sid.startsWith(sid8)) return sid;
|
|
1095
|
+
return sid8;
|
|
1096
|
+
})) {
|
|
1097
|
+
try { this._onSessionDiagnostic?.(hit.sessionId, 'headless-op-overdue', hit.details); }
|
|
1098
|
+
catch (err) { this.logger.warn?.(`[session-host-pool] onSessionDiagnostic hook threw: ${err?.message || err}`); }
|
|
1099
|
+
}
|
|
1176
1100
|
if (this._onThreadpoolReport) {
|
|
1177
1101
|
try { this._onThreadpoolReport(snapshot); }
|
|
1178
1102
|
catch (err) { this.logger.warn?.(`[session-host-pool] onThreadpoolReport hook threw: ${err?.message || err}`); }
|
|
@@ -1236,6 +1160,23 @@ class SessionHostManager extends EventEmitter {
|
|
|
1236
1160
|
return null;
|
|
1237
1161
|
}
|
|
1238
1162
|
|
|
1163
|
+
// WP-3 (session-stops-mid-job-2026-10-24.html, D-10): the per-host frame clock.
|
|
1164
|
+
// `_noteHostFrame` is called for every frame a host sends (see
|
|
1165
|
+
// HostedPtyAdapter._handleChildMessage and _handleThreadpoolFrame); `lastFrameAt`
|
|
1166
|
+
// is the public read server.js injects into lib/host-health-ledger.js. One
|
|
1167
|
+
// Map.set per frame -- no allocation beyond that, no event emitted per frame.
|
|
1168
|
+
_noteHostFrame(hostId) {
|
|
1169
|
+
const id = String(hostId || '');
|
|
1170
|
+
if (!id) return;
|
|
1171
|
+
this._hostFrameAt.set(id, Date.now());
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
lastFrameAt(hostId) {
|
|
1175
|
+
const id = String(hostId || '');
|
|
1176
|
+
if (!id) return 0;
|
|
1177
|
+
return this._hostFrameAt.get(id) || 0;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1239
1180
|
// WP-1: reconstructs the same shape of record `_shutdownOrphanHost` (server.js)
|
|
1240
1181
|
// expects -- {hostId, kind, pid, socketPath, sessionIds} -- from this manager's
|
|
1241
1182
|
// own live routing state, so the revive path never has to block on an async
|
|
@@ -1384,11 +1325,17 @@ class SessionHostManager extends EventEmitter {
|
|
|
1384
1325
|
// prototype's IPC fallback can never fire) -- redial on write failure
|
|
1385
1326
|
// (lib/adopted-host-redial.js) instead of failing forever.
|
|
1386
1327
|
adapter._post = (message) => {
|
|
1387
|
-
if (adapter.closed) return false;
|
|
1328
|
+
if (adapter.closed) { notePostRefusal(message); return false; }
|
|
1329
|
+
// A1: this per-instance override stays the selected route for an adopted host. The helper
|
|
1330
|
+
// owns the WHOLE second-lookup/write/error boundary, so a caught failure falls through to
|
|
1331
|
+
// this adapter's ORIGINAL redial (never lost, never doubled) and only a genuinely missing
|
|
1332
|
+
// socket refuses here.
|
|
1388
1333
|
if (adapter._socketConn && !adapter._socketConn.destroyed) {
|
|
1389
|
-
|
|
1390
|
-
|
|
1334
|
+
if (postSelectedSocket(() => adapter._socketConn, message, (err) => adapter._events.emit('host-error', err))) return true;
|
|
1335
|
+
this._redialAdoptedHost(hostId, socketPath);
|
|
1336
|
+
return false;
|
|
1391
1337
|
}
|
|
1338
|
+
notePostRefusal(message);
|
|
1392
1339
|
this._redialAdoptedHost(hostId, socketPath);
|
|
1393
1340
|
return false;
|
|
1394
1341
|
};
|
|
@@ -1495,12 +1442,12 @@ class SessionHostManager extends EventEmitter {
|
|
|
1495
1442
|
|
|
1496
1443
|
// WP-3 (fix round 1, P1-2): dispatch for frames arriving on an ADOPTED host's
|
|
1497
1444
|
// connection -- pooled OR dedicated, both now route here rather than through
|
|
1498
|
-
// _handlePoolMessage's manager-global pool special cases. Scoped by hostId so a
|
|
1499
|
-
//
|
|
1500
|
-
// frames only to its own adapter(s).
|
|
1445
|
+
// _handlePoolMessage's manager-global pool special cases. Scoped by hostId so a manager that has adopted more
|
|
1446
|
+
// than one host at once routes each connection's frames only to its own adapter(s).
|
|
1501
1447
|
_routeAdoptedFrame(hostId, msg, originConnection) {
|
|
1502
1448
|
if (!msg || typeof msg !== 'object') return;
|
|
1503
1449
|
const sessionId = String(msg.sessionId || '');
|
|
1450
|
+
if (msg.type === 'host-threadpool') { this._handleThreadpoolFrame(hostId, msg); return; } // stale-pty-host-evacuation S-7: host-wide (no sessionId) -- an adopted stalled host must reach the ledger
|
|
1504
1451
|
if (msg.type === 'shutdown-session-ack') { this._shutdownSessionWaiters.get(sessionId)?.(true); return; }
|
|
1505
1452
|
if (String(msg.type).startsWith('handoff-')) { handoffOrchestrator.routeFrame(this, hostId, msg); return; }
|
|
1506
1453
|
const adapter = sessionId ? this.hosts.get(sessionId) : null;
|
|
@@ -1778,7 +1725,13 @@ class SessionHostManager extends EventEmitter {
|
|
|
1778
1725
|
// drops this hostId. Without it the per-hostId misses outlived the host, and
|
|
1779
1726
|
// since a hostId is `pool-<pid>`, a LATER host reusing that pid inherited the
|
|
1780
1727
|
// dead one's miss count and could be killed on its first deadline miss.
|
|
1781
|
-
if (exitingPoolHostId)
|
|
1728
|
+
if (exitingPoolHostId) {
|
|
1729
|
+
// WP-3 (session-stops-followups-2026-10-24.html, D-5/D-6): announce only --
|
|
1730
|
+
// the constructor's single 'host-exit' listener owns dropping this hostId's
|
|
1731
|
+
// frame clock (with its ledger entry), so a later host reusing the same
|
|
1732
|
+
// `pool-<pid>` id can never inherit it. No inline delete here.
|
|
1733
|
+
this.emit('host-exit', { hostId: exitingPoolHostId, kind: 'pool' });
|
|
1734
|
+
}
|
|
1782
1735
|
for (const host of Array.from(this.hosts.values())) {
|
|
1783
1736
|
if (!host._pooled || host._adopted || host.closed || host._hostId !== exitingPoolHostId && host._hostId) continue; // WP-4: a re-pointed adapter no longer belongs to this exiting pool
|
|
1784
1737
|
host.closed = true;
|
|
@@ -1797,26 +1750,14 @@ class SessionHostManager extends EventEmitter {
|
|
|
1797
1750
|
|
|
1798
1751
|
_postToPool(message) {
|
|
1799
1752
|
const child = this._ensurePool();
|
|
1800
|
-
|
|
1753
|
+
// A1: an absent/closed pool posts nothing -- recorded as a refusal, joined CONSERVATIVELY below.
|
|
1754
|
+
if (!child || this._poolClosed) { notePostRefusal(message); return false; }
|
|
1801
1755
|
// WP-1 (deliverable 2): once the pool's control flip has succeeded, ALL
|
|
1802
1756
|
// control + data goes over the socket -- IPC is no longer used to send.
|
|
1803
1757
|
if (this._poolTransport === 'socket' && this._poolSocketConn && !this._poolSocketConn.destroyed) {
|
|
1804
|
-
|
|
1805
|
-
_writeFrame(this._poolSocketConn, message);
|
|
1806
|
-
return true;
|
|
1807
|
-
} catch (err) {
|
|
1808
|
-
this._emitHostError(message?.sessionId || '', err);
|
|
1809
|
-
return false;
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
if (!child.connected) return false;
|
|
1813
|
-
try {
|
|
1814
|
-
child.send(message);
|
|
1815
|
-
return true;
|
|
1816
|
-
} catch (err) {
|
|
1817
|
-
this._emitHostError(message?.sessionId || '', err);
|
|
1818
|
-
return false;
|
|
1758
|
+
return postSelectedSocket(() => this._poolSocketConn, message, (err) => this._emitHostError(message?.sessionId || '', err));
|
|
1819
1759
|
}
|
|
1760
|
+
return postIpcFrameObserved(child, message, (err) => this._emitHostError(message?.sessionId || '', err)).posted;
|
|
1820
1761
|
}
|
|
1821
1762
|
_handlePoolMessage(msg, sourceChild = null) {
|
|
1822
1763
|
if (sourceChild && sourceChild !== this._poolChild) return;
|
|
@@ -1893,7 +1834,9 @@ class SessionHostManager extends EventEmitter {
|
|
|
1893
1834
|
return;
|
|
1894
1835
|
}
|
|
1895
1836
|
}
|
|
1896
|
-
|
|
1837
|
+
// WP-4 (R-7): the pool's own arrival stamp for a frame with no routed adapter above --
|
|
1838
|
+
// same helper, so a pooled frame and a dedicated one answer the same question.
|
|
1839
|
+
this._emitHeadlessMessage(_stampMainArrival(inner));
|
|
1897
1840
|
} else if (msg.type === 'host-diagnostic') { hostDiagnosticFrame(this, sessionId, msg); // no adapter routed yet (successor restore)
|
|
1898
1841
|
} else if (msg.type === 'host-error') {
|
|
1899
1842
|
const err = new Error(msg.message || 'session host pool error');
|
|
@@ -1934,7 +1877,10 @@ class HeadlessTerminalRouter extends EventEmitter {
|
|
|
1934
1877
|
return;
|
|
1935
1878
|
}
|
|
1936
1879
|
if (msg?.type === 'worker-error') this._scheduleStatusRefresh();
|
|
1937
|
-
|
|
1880
|
+
// WP-4 (R-7): the legacy worker transport is a third arrival path into the same 'message'
|
|
1881
|
+
// event the two hosted ones feed -- stamp it here so a frame's `_mainArrivedAt` means the
|
|
1882
|
+
// same thing regardless of which transport delivered it.
|
|
1883
|
+
this.emit('message', _stampMainArrival(msg));
|
|
1938
1884
|
});
|
|
1939
1885
|
this.legacyWorker.on('error', (err) => this.emit('error', err));
|
|
1940
1886
|
this.sessionHostManager.on('headless-message', (msg) => this.emit('message', msg));
|
|
@@ -2042,5 +1988,5 @@ module.exports = {
|
|
|
2042
1988
|
HeadlessTerminalRouter,
|
|
2043
1989
|
createSessionHostManager,
|
|
2044
1990
|
createHeadlessTerminalRouter,
|
|
2045
|
-
_internals: { ADOPT_DIAL_TIMEOUT_MS },
|
|
1991
|
+
_internals: { ADOPT_DIAL_TIMEOUT_MS, _stampMainArrival },
|
|
2046
1992
|
};
|
|
@@ -175,35 +175,38 @@ function registerSessionJobs(scheduler, deps) {
|
|
|
175
175
|
}
|
|
176
176
|
return false;
|
|
177
177
|
}
|
|
178
|
+
// WP-6: the window reports WHY it is quiet -- a short reason string, '' when maintenance may run. Its only
|
|
179
|
+
// caller uses the value for truthiness, so this is a naming change, not a behaviour change; the transcript
|
|
180
|
+
// archive job passes the reason through to its own `deferred` log line.
|
|
178
181
|
function _isInStartupMaintenanceQuietWindow() {
|
|
179
|
-
if (typeof isRestoreInProgress === 'function' && isRestoreInProgress()) return
|
|
182
|
+
if (typeof isRestoreInProgress === 'function' && isRestoreInProgress()) return 'restore_in_progress';
|
|
180
183
|
// Defer while the single serial db-owner worker is degraded under load: piling more
|
|
181
184
|
// maintenance onto a struggling worker deepens the contention cascade that wedges the
|
|
182
185
|
// cold-boot storm. The scheduler re-runs the job once the worker recovers.
|
|
183
|
-
if (typeof isDbWorkerDegraded === 'function' && isDbWorkerDegraded()) return
|
|
186
|
+
if (typeof isDbWorkerDegraded === 'function' && isDbWorkerDegraded()) return 'db_worker_degraded';
|
|
184
187
|
// Just woke from a process suspension (laptop sleep): the wake backlog (imports/restore/harvest)
|
|
185
188
|
// fires at once and saturates the serial db-owner worker → main-loop freezes. Hold heavy
|
|
186
189
|
// maintenance for a short grace window so the burst drains before we pile more on (mirrors the
|
|
187
190
|
// degraded-worker defer above, but catches the INITIAL wake wave before degradation sets in).
|
|
188
|
-
if (typeof recentlyResumedFromSleep === 'function' && recentlyResumedFromSleep()) return
|
|
191
|
+
if (typeof recentlyResumedFromSleep === 'function' && recentlyResumedFromSleep()) return 'resumed_from_sleep';
|
|
189
192
|
// isDbWarming() is currently a retired compatibility gate; keep honoring it
|
|
190
193
|
// here so any future SQLite-owned warmup can defer maintenance safely. The
|
|
191
194
|
// fixed startup grace below remains the active maintenance quiet window.
|
|
192
|
-
if (typeof isDbWarming === 'function' && isDbWarming()) return
|
|
193
|
-
if (typeof canAdmitTierB === 'function' && !canAdmitTierB()) return
|
|
195
|
+
if (typeof isDbWarming === 'function' && isDbWarming()) return 'db_warming';
|
|
196
|
+
if (typeof canAdmitTierB === 'function' && !canAdmitTierB()) return 'tier_b_refused';
|
|
194
197
|
if (typeof getServerStartedAt === 'function') {
|
|
195
198
|
const startedAt = Number(getServerStartedAt());
|
|
196
199
|
if (Number.isFinite(startedAt) && startedAt > 0 && (Date.now() - startedAt) < STARTUP_MAINTENANCE_GRACE_MS) {
|
|
197
|
-
return
|
|
200
|
+
return 'startup_grace';
|
|
198
201
|
}
|
|
199
202
|
}
|
|
200
203
|
if (typeof getRestoreCompletedAt === 'function') {
|
|
201
204
|
const completedAt = Number(getRestoreCompletedAt());
|
|
202
205
|
if (Number.isFinite(completedAt) && completedAt > 0 && (Date.now() - completedAt) < STARTUP_MAINTENANCE_GRACE_MS) {
|
|
203
|
-
return
|
|
206
|
+
return 'restore_grace';
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
|
-
return
|
|
209
|
+
return '';
|
|
207
210
|
}
|
|
208
211
|
// Interactive guard: heavy maintenance jobs (the io-pool scans) must not START
|
|
209
212
|
// their synchronous DB/fs work within INTERACTIVE_DEFER_MS of a user keystroke.
|
|
@@ -231,6 +234,11 @@ function registerSessionJobs(scheduler, deps) {
|
|
|
231
234
|
_interactiveDeferSince = 0;
|
|
232
235
|
return true;
|
|
233
236
|
}
|
|
237
|
+
// WP-6: why `_canRunStartupMaintenance` is holding a heavy job back, in the same words the transcript
|
|
238
|
+
// archive job logs. '' means nothing is holding it back.
|
|
239
|
+
function _maintenanceDeferReason() {
|
|
240
|
+
return _isInStartupMaintenanceQuietWindow() || (_userInteractingNow() ? 'user_typing' : '');
|
|
241
|
+
}
|
|
234
242
|
|
|
235
243
|
let sessionMetadataSyncCursor = 0;
|
|
236
244
|
let sessionMetadataSyncTick = 0;
|
|
@@ -1104,7 +1112,7 @@ function registerSessionJobs(scheduler, deps) {
|
|
|
1104
1112
|
});
|
|
1105
1113
|
}
|
|
1106
1114
|
|
|
1107
|
-
if (deps.runConversationSummaryBackfill) require('./conversation-summary-backfill').registerJob(scheduler, deps.runConversationSummaryBackfill, _canRunStartupMaintenance); if (deps.transcriptGuard && deps.transcriptArchiveEnv) require('./transcript-guard-job').registerArchiveJob(scheduler, deps.transcriptGuard, deps.transcriptArchiveEnv, _canRunStartupMaintenance); // D-19 transcript archive
|
|
1115
|
+
if (deps.runConversationSummaryBackfill) require('./conversation-summary-backfill').registerJob(scheduler, deps.runConversationSummaryBackfill, _canRunStartupMaintenance); if (deps.transcriptGuard && deps.transcriptArchiveEnv) require('./transcript-guard-job').registerArchiveJob(scheduler, deps.transcriptGuard, deps.transcriptArchiveEnv, _canRunStartupMaintenance, _maintenanceDeferReason); // D-19 transcript archive
|
|
1108
1116
|
// --- message-backfill: maintain legacy session_messages FTS from canonical rows ---
|
|
1109
1117
|
if (deps.backfillSessionMessages) {
|
|
1110
1118
|
scheduler.register({
|
|
@@ -728,6 +728,10 @@ function percentile(values, ratio) {
|
|
|
728
728
|
return sorted[Math.min(sorted.length - 1, Math.max(0, Math.ceil(sorted.length * ratio) - 1))];
|
|
729
729
|
}
|
|
730
730
|
|
|
731
|
+
// WP-3 (§5 D-8): the skip-reason vocabulary lives in its own module (so server.js can name tokens
|
|
732
|
+
// without growing); re-exported here for the existing importers.
|
|
733
|
+
const { WAKE_SKIP_REASONS } = require('./wake-skip-reasons');
|
|
734
|
+
|
|
731
735
|
class LifecycleDiagnostics {
|
|
732
736
|
constructor({ maxEvents = 200 } = {}) {
|
|
733
737
|
this.maxEvents = Math.max(1, maxEvents);
|
|
@@ -740,6 +744,10 @@ class LifecycleDiagnostics {
|
|
|
740
744
|
this.events = [];
|
|
741
745
|
this.wake = new Map();
|
|
742
746
|
this.wakeOutcomes = {};
|
|
747
|
+
// WP-3 (§5 D-6): skip-reason counter for the pre-gate deferred-restore bails -- the ones that
|
|
748
|
+
// precede _wakeStartedAt and so can never be counted by wakeOutcomes ("65 deferred, zero
|
|
749
|
+
// wakes" was invisible for exactly this reason).
|
|
750
|
+
this.wakeSkips = {};
|
|
743
751
|
}
|
|
744
752
|
|
|
745
753
|
_count(target, key) { target[key] = (target[key] || 0) + 1; }
|
|
@@ -818,6 +826,14 @@ class LifecycleDiagnostics {
|
|
|
818
826
|
this._event({ type: 'wake-outcome', id, provider, outcome, phases: { ...phases } });
|
|
819
827
|
}
|
|
820
828
|
|
|
829
|
+
// WP-3 (§5 D-6/D-8): the sibling of recordWakeOutcome for the pre-gate bails. `reason` is a
|
|
830
|
+
// WAKE_SKIP_REASONS token (CamelCase, machine-readable — the K8s-condition convention); a
|
|
831
|
+
// caller that still passes a legacy human string is recorded verbatim rather than dropped.
|
|
832
|
+
recordWakeSkip({ id = '', provider = 'unknown', reason = 'Unclassified' } = {}) {
|
|
833
|
+
this._count(this.wakeSkips, reason);
|
|
834
|
+
this._event({ type: 'wake-skip', id, provider, reason });
|
|
835
|
+
}
|
|
836
|
+
|
|
821
837
|
snapshot(extra = {}) {
|
|
822
838
|
const wakeLatency = {};
|
|
823
839
|
for (const [provider, entry] of this.wake) {
|
|
@@ -834,6 +850,7 @@ class LifecycleDiagnostics {
|
|
|
834
850
|
shadow: { ...this.shadow },
|
|
835
851
|
pressureTransitions: this.pressureTransitions,
|
|
836
852
|
wakeOutcomes: { ...this.wakeOutcomes },
|
|
853
|
+
wakeSkips: { ...this.wakeSkips },
|
|
837
854
|
wakeLatency,
|
|
838
855
|
events: [...this.events],
|
|
839
856
|
...extra,
|
|
@@ -844,6 +861,7 @@ class LifecycleDiagnostics {
|
|
|
844
861
|
module.exports = {
|
|
845
862
|
ActivationGate,
|
|
846
863
|
LifecycleDiagnostics,
|
|
864
|
+
WAKE_SKIP_REASONS,
|
|
847
865
|
MemoryBudgetController,
|
|
848
866
|
PressureController,
|
|
849
867
|
automaticParkSweepPolicy,
|