@north-light/crouter 0.3.312 → 0.3.313
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/dist/api/client.d.ts +27 -30
- package/dist/api/client.js +80 -67
- package/dist/api/dto/broker-ops.d.ts +10 -20
- package/dist/api/dto/canvas.d.ts +1 -10
- package/dist/api/dto/health.d.ts +113 -0
- package/dist/api/dto/human-requests.d.ts +14 -3
- package/dist/api/dto/human.d.ts +2 -48
- package/dist/api/dto/human.js +3 -2
- package/dist/api/dto/inbox.d.ts +14 -0
- package/dist/api/dto/mail.d.ts +43 -0
- package/dist/api/dto/nodes.d.ts +11 -8
- package/dist/api/dto/recovery.d.ts +96 -0
- package/dist/api/dto/reviews.d.ts +2 -2
- package/dist/api/routes.d.ts +9 -6
- package/dist/api/routes.js +11 -11
- package/dist/build-root.d.ts +4 -0
- package/dist/build-root.js +11 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
- package/dist/cli.js +10 -1
- package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
- package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
- package/dist/clients/attach/chrome/inbox-strip.js +17 -9
- package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
- package/dist/clients/attach/chrome/ticket-panel.js +77 -46
- package/dist/clients/attach/overlays/graph.js +6 -9
- package/dist/clients/attach/render/chat-view.d.ts +5 -4
- package/dist/clients/attach/render/chat-view.js +22 -13
- package/dist/clients/attach/render/page-block.d.ts +11 -7
- package/dist/clients/attach/render/page-block.js +64 -55
- package/dist/clients/attach/viewer.js +746 -735
- package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
- package/dist/clients/inbox/controller.d.ts +42 -14
- package/dist/clients/inbox/controller.js +240 -124
- package/dist/clients/inbox/dto-adapt.d.ts +28 -0
- package/dist/clients/inbox/dto-adapt.js +93 -0
- package/dist/clients/inbox/page-adapter.d.ts +5 -4
- package/dist/clients/inbox/page-adapter.js +12 -12
- package/dist/clients/inbox/resolve.d.ts +10 -5
- package/dist/clients/inbox/resolve.js +13 -12
- package/dist/clients/inbox/review/review-client.d.ts +0 -1
- package/dist/clients/inbox/review/review-client.js +0 -4
- package/dist/clients/inbox/review-adapter.d.ts +2 -1
- package/dist/clients/inbox/review-adapter.js +3 -5
- package/dist/clients/inbox/surface.d.ts +2 -2
- package/dist/clients/inbox/surface.js +19 -8
- package/dist/clients/inbox/tui.d.ts +3 -3
- package/dist/commands/__tests__/human.test.js +31 -15
- package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
- package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
- package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
- package/dist/commands/api-client.d.ts +5 -4
- package/dist/commands/api-client.js +13 -7
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-roster.js +1 -1
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/human/feedback.js +20 -17
- package/dist/commands/human/prompts.js +45 -36
- package/dist/commands/human/queue.js +73 -123
- package/dist/commands/human/review.js +6 -16
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
- package/dist/commands/node-inspect-artifacts.js +1 -1
- package/dist/commands/node-lifecycle-revive.d.ts +2 -2
- package/dist/commands/node-lifecycle-revive.js +9 -19
- package/dist/commands/pkg/plugin-manage.js +0 -1
- package/dist/commands/profile/show.js +4 -12
- package/dist/commands/surface-tmux-spread.js +1 -5
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
- package/dist/commands/sys/branch.d.ts +2 -0
- package/dist/commands/sys/branch.js +19 -0
- package/dist/commands/sys/config.js +106 -33
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/sys/daemon.js +130 -7
- package/dist/commands/sys/doctor.js +5 -15
- package/dist/commands/sys/migrate.js +21 -92
- package/dist/commands/sys/setup-settings-runner.js +4 -2
- package/dist/commands/sys.js +2 -15
- package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
- package/dist/core/__tests__/boot.test.js +32 -25
- package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
- package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
- package/dist/core/__tests__/canvas.test.js +18 -47
- package/dist/core/__tests__/child-death-wake.test.js +29 -7
- package/dist/core/__tests__/cli-help-contract.test.js +2 -0
- package/dist/core/__tests__/close.test.js +29 -10
- package/dist/core/__tests__/collectible.test.js +2 -1
- package/dist/core/__tests__/config-change-delta.test.js +2 -0
- package/dist/core/__tests__/context-intro.test.js +13 -1
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
- package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +3 -2
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +8 -2
- package/dist/core/runtime/reset.js +22 -6
- package/dist/core/runtime/revive.js +226 -218
- package/dist/core/runtime/spawn.js +14 -3
- package/dist/core/scoped-state/db.d.ts +7 -0
- package/dist/core/scoped-state/db.js +92 -0
- package/dist/core/scoped-state/migrate.d.ts +11 -0
- package/dist/core/scoped-state/migrate.js +198 -0
- package/dist/core/scoped-state/paths.d.ts +9 -0
- package/dist/core/scoped-state/paths.js +27 -0
- package/dist/core/scoped-state/profiles.d.ts +12 -0
- package/dist/core/scoped-state/profiles.js +62 -0
- package/dist/core/scoped-state/providers.d.ts +16 -0
- package/dist/core/scoped-state/providers.js +8 -0
- package/dist/core/scoped-state/schema.d.ts +3 -0
- package/dist/core/scoped-state/schema.js +26 -0
- package/dist/core/scoped-state/settings.d.ts +28 -0
- package/dist/core/scoped-state/settings.js +82 -0
- package/dist/core/subscription-state.d.ts +29 -48
- package/dist/core/subscription-state.js +176 -712
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +2 -2
- package/dist/core/worktree-sweep.js +11 -16
- package/dist/core/worktree.js +6 -12
- package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
- package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
- package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
- package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
- package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -151
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.js +7 -13
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
- package/dist/core/__tests__/human-deliver.test.js +0 -256
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
- package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
- package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
- package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-store.test.js +0 -144
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
- package/dist/core/canvas/human-deliveries.d.ts +0 -39
- package/dist/core/canvas/human-deliveries.js +0 -75
- package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
- package/dist/core/canvas/node-outcome-deliveries.js +0 -159
- package/dist/core/feed/passive.d.ts +0 -3
- package/dist/core/feed/passive.js +0 -53
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
- package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
- package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
- package/dist/core/human/__tests__/page-tickets.test.js +0 -161
- package/dist/core/review/ticket-filter.d.ts +0 -17
- package/dist/core/review/ticket-filter.js +0 -21
- package/dist/core/runtime/broker/passive.d.ts +0 -17
- package/dist/core/runtime/broker/passive.js +0 -44
- package/dist/core/runtime/busy.d.ts +0 -46
- package/dist/core/runtime/busy.js +0 -150
- package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
- package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
- package/dist/daemon/human/deliver-action.d.ts +0 -3
- package/dist/daemon/human/deliver-action.js +0 -9
- package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
- package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
- package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
- package/dist/daemon/startup-block-marker.d.ts +0 -25
- package/dist/daemon/startup-block-marker.js +0 -99
- /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
- /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
- /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
|
@@ -1,70 +1,66 @@
|
|
|
1
|
-
import { existsSync, readdirSync,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export async function reconcileUndeliveredTickets() {
|
|
19
|
-
let scanned = 0;
|
|
20
|
-
let delivered = 0;
|
|
1
|
+
import { existsSync, readdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { reviewsRoot } from '../../core/canvas/paths.js';
|
|
3
|
+
import { listBindingRequests, listRequests, listUnprojectedReviews, markProjectionError, } from '../../core/human/requests.js';
|
|
4
|
+
import { projectAndRetire } from './settle.js';
|
|
5
|
+
function errorText(error) { return error instanceof Error ? error.message : String(error); }
|
|
6
|
+
/**
|
|
7
|
+
* The one startup repair pass for SQL-authoritative pages and reviews. It does
|
|
8
|
+
* not infer a missing notification or action delivery: settlement created both
|
|
9
|
+
* atomically. The two remaining filesystem effects retain their durable marks.
|
|
10
|
+
*/
|
|
11
|
+
/** Direct outbox rows are created in the settlement transaction; there is no separate ticket-delivery repair pass. */
|
|
12
|
+
export async function reconcileUndeliveredTickets() { }
|
|
13
|
+
export async function sweepHumanRequests(effects) {
|
|
14
|
+
let realized = 0;
|
|
15
|
+
let collected = 0;
|
|
16
|
+
let reprojected = 0;
|
|
17
|
+
let retired = 0;
|
|
21
18
|
let failed = 0;
|
|
22
|
-
const
|
|
23
|
-
for (const entry of readdirSync(root)) {
|
|
19
|
+
for (const request of listBindingRequests()) {
|
|
24
20
|
try {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
await effects.realizeReview(request.request_id);
|
|
22
|
+
realized += 1;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// A missing branch is a valid binding-recovery outcome. Its terminal row
|
|
26
|
+
// is written by realization; other failures remain visible for next boot.
|
|
27
|
+
failed += 1;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const live = new Set(listRequests({ kind: 'review' }).map((request) => request.request_id));
|
|
32
|
+
if (existsSync(reviewsRoot())) {
|
|
33
|
+
for (const entry of readdirSync(reviewsRoot(), { withFileTypes: true })) {
|
|
34
|
+
if (entry.isDirectory() && !live.has(entry.name)) {
|
|
35
|
+
rmSync(`${reviewsRoot()}/${entry.name}`, { recursive: true, force: true });
|
|
36
|
+
collected += 1;
|
|
35
37
|
}
|
|
36
|
-
continue;
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
await
|
|
46
|
-
|
|
47
|
-
// owes that delivery; the insert is idempotent on the request id.
|
|
48
|
-
releaseActionDelivery(entry);
|
|
49
|
-
// The ROW is what carries status; `getNode` would answer from a pruned
|
|
50
|
-
// bridge's surviving meta.json with no status at all.
|
|
51
|
-
const bridge = getRow(entry);
|
|
52
|
-
if (bridge === null || isTerminalBridge(bridge.status))
|
|
53
|
-
continue;
|
|
54
|
-
if (await deliverTerminalResult(entry))
|
|
55
|
-
delivered += 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
failed += 1;
|
|
43
|
+
}
|
|
44
|
+
for (const request of listUnprojectedReviews()) {
|
|
45
|
+
try {
|
|
46
|
+
await projectAndRetire(request, { project: effects.projectReview, retire: effects.retireCompanion });
|
|
47
|
+
reprojected += 1;
|
|
56
48
|
}
|
|
57
49
|
catch (error) {
|
|
50
|
+
markProjectionError(request.request_id, errorText(error));
|
|
51
|
+
failed += 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
for (const request of listRequests({ state: 'settled' })) {
|
|
55
|
+
if (request.companion_node_id === null || request.companion_retired_at !== null)
|
|
56
|
+
continue;
|
|
57
|
+
try {
|
|
58
|
+
await projectAndRetire(request, { retire: effects.retireCompanion });
|
|
59
|
+
retired += 1;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
58
62
|
failed += 1;
|
|
59
|
-
emitEvent({
|
|
60
|
-
level: 'error',
|
|
61
|
-
event: 'human.delivery.reconcile_failed',
|
|
62
|
-
node_id: entry,
|
|
63
|
-
error,
|
|
64
|
-
});
|
|
65
63
|
}
|
|
66
64
|
}
|
|
67
|
-
|
|
68
|
-
emitEvent({ level: 'info', event: 'human.delivery.reconciled', fields: result });
|
|
69
|
-
return result;
|
|
65
|
+
return { realized, collected, reprojected, retired, failed };
|
|
70
66
|
}
|
package/dist/daemon/manage.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type HealthDTO, type StartupPhaseDTO } from '../api/index.js';
|
|
1
2
|
/** Env keys that must NEVER reach the daemon process. Restarting crtrd is
|
|
2
3
|
* overwhelmingly done from inside an agent node's own bash tool (`crtr sys
|
|
3
4
|
* daemon stop && start`), which inherits that node's FULL env — its identity
|
|
@@ -39,6 +40,10 @@ export declare function sweepStrayDaemons(keepPid: number | null): number[];
|
|
|
39
40
|
/** Replace PID 1 with the selected daemon generation. Docker keeps a container
|
|
40
41
|
* alive only while PID 1 lives, so a handover there must preserve its pid. */
|
|
41
42
|
export declare function execDaemon(): Promise<never>;
|
|
43
|
+
export interface SpawnDaemonOptions {
|
|
44
|
+
/** The phase that proves a daemon launched by this call is available. */
|
|
45
|
+
targetPhase?: 'ready' | 'prepared';
|
|
46
|
+
}
|
|
42
47
|
export interface SpawnDaemonResult {
|
|
43
48
|
/** True when a new daemon process was spawned. */
|
|
44
49
|
started: boolean;
|
|
@@ -52,9 +57,12 @@ export interface SpawnDaemonResult {
|
|
|
52
57
|
serving?: false;
|
|
53
58
|
/** The final `/healthz` probe failure when a live owner misses readiness. */
|
|
54
59
|
probe_error?: string;
|
|
60
|
+
/** The observed phase when the daemon was available. */
|
|
61
|
+
startup_phase?: StartupPhaseDTO;
|
|
55
62
|
}
|
|
56
|
-
/** Make one `/healthz` observation without client-side recovery. The caller
|
|
57
|
-
|
|
63
|
+
/** Make one `/healthz` observation without client-side recovery. The caller owns the availability window, so this probe cannot extend it. */
|
|
64
|
+
export declare function probeDaemonHealth(timeoutMs?: number): Promise<HealthDTO>;
|
|
65
|
+
/** True only when one mandatory Unix API socket probe answers the existing ready health contract. */
|
|
58
66
|
export declare function probeDaemonServing(timeoutMs?: number): Promise<void>;
|
|
59
67
|
/** True only when one mandatory Unix API socket probe answers `/healthz`.
|
|
60
68
|
* A pidfile identifies an owner; it is never readiness. */
|
|
@@ -72,13 +80,16 @@ export interface DaemonStartupDeps extends DaemonWaitDeps {
|
|
|
72
80
|
} | null;
|
|
73
81
|
isDaemonServing?: () => Promise<boolean>;
|
|
74
82
|
probeDaemonServing?: (timeoutMs: number) => Promise<void>;
|
|
83
|
+
probeDaemonHealth?: (timeoutMs: number) => Promise<HealthDTO>;
|
|
75
84
|
}
|
|
76
|
-
/**
|
|
77
|
-
*
|
|
78
|
-
* would hit identically. Callers must stop retrying and surface the repair;
|
|
79
|
-
* the daemon has already written the detail to `crtrd.err`. */
|
|
85
|
+
/** A live daemon has bound its repair socket but cannot serve normal work
|
|
86
|
+
* until its corpus migration succeeds. */
|
|
80
87
|
export declare class DaemonStartupBlockedError extends Error {
|
|
81
|
-
constructor(pid: number);
|
|
88
|
+
constructor(pid: number, message: string);
|
|
89
|
+
}
|
|
90
|
+
/** A preparation request cannot succeed unless the live daemon explicitly reports prepared. */
|
|
91
|
+
export declare class DaemonNotPreparedError extends Error {
|
|
92
|
+
constructor(pid: number, startupPhase: StartupPhaseDTO | undefined);
|
|
82
93
|
}
|
|
83
94
|
/** Tiny bounded post-spawn guard: wait for the daemon pidfile and live pid to
|
|
84
95
|
* appear before reporting success. This catches the "started:true but not yet
|
|
@@ -93,7 +104,7 @@ export declare class DaemonStartupBlockedError extends Error {
|
|
|
93
104
|
*
|
|
94
105
|
* Returns null when the spawned pid owns the pidfile; returns a different live
|
|
95
106
|
* daemon pid when startup lost the race to an already-running daemon. */
|
|
96
|
-
export declare function verifyDaemonStartup(pid: number, timeoutMs?: number, deps?: DaemonStartupDeps): Promise<number | null>;
|
|
107
|
+
export declare function verifyDaemonStartup(pid: number, timeoutMs?: number, deps?: DaemonStartupDeps, targetPhase?: 'ready' | 'prepared'): Promise<number | null>;
|
|
97
108
|
/** Wait until a signaled daemon has exited and relinquished its pidfile. This
|
|
98
109
|
* makes a following start safe to claim the singleton rather than racing its
|
|
99
110
|
* previous owner. */
|
|
@@ -119,7 +130,7 @@ export declare function stopDaemonProcess(pid: number, timeoutMs?: number, deps?
|
|
|
119
130
|
*
|
|
120
131
|
* If the daemon is already running, returns {started:false, existing_pid}.
|
|
121
132
|
* If spawning fails (e.g. missing dist — run `npm run build` first), throws. */
|
|
122
|
-
export declare function spawnDaemon(): Promise<SpawnDaemonResult>;
|
|
133
|
+
export declare function spawnDaemon(opts?: SpawnDaemonOptions): Promise<SpawnDaemonResult>;
|
|
123
134
|
/** Whether autostart is suppressed for this invocation. `--no-autostart` or
|
|
124
135
|
* `CRTR_NO_DAEMON_AUTOSTART=1` forces fail-loud on a cold socket (spec §7.1) —
|
|
125
136
|
* for environments that manage crtrd externally and want the diagnostic, and
|
|
@@ -134,13 +145,7 @@ export declare function spawnDaemon(): Promise<SpawnDaemonResult>;
|
|
|
134
145
|
* explicit `crtr sys daemon start` calls `spawnDaemon` directly and is
|
|
135
146
|
* deliberately unaffected. */
|
|
136
147
|
export declare function autostartDisabled(): boolean;
|
|
137
|
-
/**
|
|
138
|
-
* run. Set only by a `DaemonStartupBlockedError`, which no retry can clear —
|
|
139
|
-
* an explicit `crtr sys daemon start` still calls `spawnDaemon` directly and
|
|
140
|
-
* reports the failure in full. */
|
|
141
|
-
export declare function daemonAutostartSuppression(): string | null;
|
|
142
|
-
/** Clear the suppression and the backoff — for a caller that has repaired the
|
|
143
|
-
* standing condition and wants autostart live again without a new process. */
|
|
148
|
+
/** Reset in-process spawn backoff after a daemon is observed alive. */
|
|
144
149
|
export declare function resetDaemonAutostart(): void;
|
|
145
150
|
export interface EnsureDaemonDeps {
|
|
146
151
|
isDaemonRunning?: () => boolean;
|
package/dist/daemon/manage.js
CHANGED
|
@@ -14,8 +14,7 @@ import { hostExecPath } from '../core/runtime/branded-host.js';
|
|
|
14
14
|
// Pulled from the lean db-free pidfile module (NOT crtrd.js, whose module graph
|
|
15
15
|
// reaches openDb) so the CLI daemon front door stays canvas.db-free (plan B-0).
|
|
16
16
|
import { isDaemonRunning, readPidfile, isPidAlive } from './pidfile.js';
|
|
17
|
-
import {
|
|
18
|
-
import { clearDaemonStartupBlocked, daemonStartupBlocked } from './startup-block-marker.js';
|
|
17
|
+
import { DAEMON_STARTUP_WINDOW_MS } from './startup-policy.js';
|
|
19
18
|
import { exclusiveLockOwnerPid } from '../core/exclusive-lock.js';
|
|
20
19
|
import { onDiskMigrationLockPath } from '../core/canvas/paths.js';
|
|
21
20
|
import { envNoDaemonAutostart } from '../shared/env.js';
|
|
@@ -208,11 +207,18 @@ const DAEMON_VERIFY_POLL_MS = 10;
|
|
|
208
207
|
/** A status/start readiness probe must not hang behind a daemon that accepts a
|
|
209
208
|
* Unix connection but never answers it. */
|
|
210
209
|
const DAEMON_HEALTH_PROBE_TIMEOUT_MS = 1_000;
|
|
211
|
-
/** Make one `/healthz` observation without client-side recovery. The caller
|
|
212
|
-
|
|
213
|
-
export async function probeDaemonServing(timeoutMs = DAEMON_HEALTH_PROBE_TIMEOUT_MS) {
|
|
210
|
+
/** Make one `/healthz` observation without client-side recovery. The caller owns the availability window, so this probe cannot extend it. */
|
|
211
|
+
export async function probeDaemonHealth(timeoutMs = DAEMON_HEALTH_PROBE_TIMEOUT_MS) {
|
|
214
212
|
const probeTimeoutMs = Math.min(timeoutMs, DAEMON_HEALTH_PROBE_TIMEOUT_MS);
|
|
215
|
-
|
|
213
|
+
return CrtrClient.forLocalSocket({ autostart: false, timeoutMs: probeTimeoutMs }).probeHealthz(probeTimeoutMs);
|
|
214
|
+
}
|
|
215
|
+
/** True only when one mandatory Unix API socket probe answers the existing ready health contract. */
|
|
216
|
+
export async function probeDaemonServing(timeoutMs = DAEMON_HEALTH_PROBE_TIMEOUT_MS) {
|
|
217
|
+
const health = await probeDaemonHealth(timeoutMs);
|
|
218
|
+
if (health.startup_blocked !== undefined) {
|
|
219
|
+
const pid = readPidfile() ?? process.pid;
|
|
220
|
+
throw new DaemonStartupBlockedError(pid, health.startup_blocked);
|
|
221
|
+
}
|
|
216
222
|
if (!health.ok)
|
|
217
223
|
throw new Error('crtrd health check reported not ready');
|
|
218
224
|
}
|
|
@@ -232,16 +238,23 @@ function sleepMs(ms) {
|
|
|
232
238
|
setTimeout(resolve, ms);
|
|
233
239
|
});
|
|
234
240
|
}
|
|
235
|
-
/**
|
|
236
|
-
*
|
|
237
|
-
* would hit identically. Callers must stop retrying and surface the repair;
|
|
238
|
-
* the daemon has already written the detail to `crtrd.err`. */
|
|
241
|
+
/** A live daemon has bound its repair socket but cannot serve normal work
|
|
242
|
+
* until its corpus migration succeeds. */
|
|
239
243
|
export class DaemonStartupBlockedError extends Error {
|
|
240
|
-
constructor(pid) {
|
|
241
|
-
super(`daemon ${pid}
|
|
244
|
+
constructor(pid, message) {
|
|
245
|
+
super(`daemon ${pid} is running but normal startup is blocked: ${message}`);
|
|
242
246
|
this.name = 'DaemonStartupBlockedError';
|
|
243
247
|
}
|
|
244
248
|
}
|
|
249
|
+
/** A preparation request cannot succeed unless the live daemon explicitly reports prepared. */
|
|
250
|
+
export class DaemonNotPreparedError extends Error {
|
|
251
|
+
constructor(pid, startupPhase) {
|
|
252
|
+
super(startupPhase === undefined
|
|
253
|
+
? `daemon ${pid} is serving but did not report the prepared startup phase`
|
|
254
|
+
: `daemon ${pid} reported startup phase ${startupPhase}, not prepared`);
|
|
255
|
+
this.name = 'DaemonNotPreparedError';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
245
258
|
/** Tiny bounded post-spawn guard: wait for the daemon pidfile and live pid to
|
|
246
259
|
* appear before reporting success. This catches the "started:true but not yet
|
|
247
260
|
* plausibly alive" race without turning startup into a retry loop.
|
|
@@ -255,7 +268,7 @@ export class DaemonStartupBlockedError extends Error {
|
|
|
255
268
|
*
|
|
256
269
|
* Returns null when the spawned pid owns the pidfile; returns a different live
|
|
257
270
|
* daemon pid when startup lost the race to an already-running daemon. */
|
|
258
|
-
export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_STARTUP_WINDOW_MS, deps = {}) {
|
|
271
|
+
export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_STARTUP_WINDOW_MS, deps = {}, targetPhase = 'ready') {
|
|
259
272
|
const read = deps.readPidfile ?? readPidfile;
|
|
260
273
|
const alive = deps.isPidAlive ?? isPidAlive;
|
|
261
274
|
const exited = deps.childExited;
|
|
@@ -268,6 +281,7 @@ export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_STARTUP_WINDOW
|
|
|
268
281
|
}
|
|
269
282
|
await probeDaemonServing(remainingMs);
|
|
270
283
|
});
|
|
284
|
+
const probeHealth = deps.probeDaemonHealth ?? probeDaemonHealth;
|
|
271
285
|
const sleep = deps.sleepMs ?? sleepMs;
|
|
272
286
|
const now = deps.now ?? Date.now;
|
|
273
287
|
let owner = null;
|
|
@@ -285,18 +299,39 @@ export async function verifyDaemonStartup(pid, timeoutMs = DAEMON_STARTUP_WINDOW
|
|
|
285
299
|
if (exitState !== null && exitState !== undefined) {
|
|
286
300
|
if (exitState.signal !== null)
|
|
287
301
|
terminalError = new Error(`daemon ${pid} exited before becoming ready (by ${exitState.signal})`);
|
|
288
|
-
else if (exitState.code === DAEMON_EXIT_STARTUP_BLOCKED)
|
|
289
|
-
terminalError = new DaemonStartupBlockedError(pid);
|
|
290
302
|
else if (exitState.code !== 0)
|
|
291
303
|
terminalError = new Error(`daemon ${pid} exited before becoming ready (with exit code ${exitState.code ?? '?'})`);
|
|
292
|
-
// A clean exit can have lost the ownership claim, so keep observing.
|
|
293
304
|
if (terminalError !== null)
|
|
294
305
|
throw terminalError;
|
|
295
306
|
}
|
|
296
307
|
throw new Error(`daemon ${pid} has no live pidfile owner`);
|
|
297
308
|
}
|
|
298
|
-
|
|
299
|
-
|
|
309
|
+
if (targetPhase === 'ready') {
|
|
310
|
+
try {
|
|
311
|
+
await probeServing(remainingMs);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
if (error instanceof DaemonStartupBlockedError)
|
|
315
|
+
terminalError = error;
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
318
|
+
owner = candidate;
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const health = await probeHealth(remainingMs);
|
|
322
|
+
if (health.startup_phase === 'prepared') {
|
|
323
|
+
owner = candidate;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (health.startup_phase === 'blocked') {
|
|
327
|
+
terminalError = new DaemonStartupBlockedError(candidate, health.startup_blocked ?? 'on-disk migration is blocked');
|
|
328
|
+
throw terminalError;
|
|
329
|
+
}
|
|
330
|
+
if (health.startup_phase === 'ready') {
|
|
331
|
+
terminalError = new DaemonNotPreparedError(candidate, health.startup_phase);
|
|
332
|
+
throw terminalError;
|
|
333
|
+
}
|
|
334
|
+
throw new Error(`daemon ${candidate} is ${health.startup_phase ?? 'not reporting a startup phase'}; waiting for prepared`);
|
|
300
335
|
},
|
|
301
336
|
});
|
|
302
337
|
return owner === pid ? null : owner;
|
|
@@ -371,14 +406,37 @@ export async function stopDaemonProcess(pid, timeoutMs = DAEMON_SHUTDOWN_WINDOW_
|
|
|
371
406
|
*
|
|
372
407
|
* If the daemon is already running, returns {started:false, existing_pid}.
|
|
373
408
|
* If spawning fails (e.g. missing dist — run `npm run build` first), throws. */
|
|
374
|
-
export async function spawnDaemon() {
|
|
409
|
+
export async function spawnDaemon(opts = {}) {
|
|
410
|
+
const targetPhase = opts.targetPhase ?? 'ready';
|
|
375
411
|
const recordedPid = readPidfile();
|
|
376
412
|
if (recordedPid !== null && isPidAlive(recordedPid)) {
|
|
377
413
|
try {
|
|
378
|
-
await
|
|
379
|
-
|
|
414
|
+
const health = await probeDaemonHealth();
|
|
415
|
+
if (targetPhase === 'prepared') {
|
|
416
|
+
if (health.startup_phase === 'prepared') {
|
|
417
|
+
return { started: false, existing_pid: recordedPid, startup_phase: health.startup_phase };
|
|
418
|
+
}
|
|
419
|
+
throw new DaemonNotPreparedError(recordedPid, health.startup_phase);
|
|
420
|
+
}
|
|
421
|
+
if (health.ok) {
|
|
422
|
+
return {
|
|
423
|
+
started: false,
|
|
424
|
+
existing_pid: recordedPid,
|
|
425
|
+
...(health.startup_phase === undefined ? {} : { startup_phase: health.startup_phase }),
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
started: false,
|
|
430
|
+
existing_pid: recordedPid,
|
|
431
|
+
running: true,
|
|
432
|
+
serving: false,
|
|
433
|
+
probe_error: health.startup_blocked ?? 'crtrd health check reported not ready',
|
|
434
|
+
...(health.startup_phase === undefined ? {} : { startup_phase: health.startup_phase }),
|
|
435
|
+
};
|
|
380
436
|
}
|
|
381
437
|
catch (error) {
|
|
438
|
+
if (error instanceof DaemonNotPreparedError)
|
|
439
|
+
throw error;
|
|
382
440
|
return {
|
|
383
441
|
started: false,
|
|
384
442
|
existing_pid: recordedPid,
|
|
@@ -415,7 +473,7 @@ export async function spawnDaemon() {
|
|
|
415
473
|
// exactly instead of scanning the whole machine. crtrd-cli.ts's argv
|
|
416
474
|
// parsing only looks for `--tcp`, so this extra pair of tokens is inert
|
|
417
475
|
// there — it exists purely for `ps` visibility.
|
|
418
|
-
const child = spawn(hostExecPath(), [...launchArgs, '--canvas-home', crtrHome()], {
|
|
476
|
+
const child = spawn(hostExecPath(), [...launchArgs, '--canvas-home', crtrHome(), ...(targetPhase === 'prepared' ? ['--prepare'] : [])], {
|
|
419
477
|
detached: true,
|
|
420
478
|
stdio: ['ignore', errFd, errFd],
|
|
421
479
|
env: sanitizedDaemonEnv(),
|
|
@@ -444,7 +502,7 @@ export async function spawnDaemon() {
|
|
|
444
502
|
try {
|
|
445
503
|
existingPid = await verifyDaemonStartup(pid, DAEMON_STARTUP_WINDOW_MS, {
|
|
446
504
|
childExited: () => exitState,
|
|
447
|
-
});
|
|
505
|
+
}, targetPhase);
|
|
448
506
|
}
|
|
449
507
|
catch (error) {
|
|
450
508
|
// Reap ONLY a child that is not doing the work. A child holding the on-disk
|
|
@@ -455,7 +513,7 @@ export async function spawnDaemon() {
|
|
|
455
513
|
// corpus can legitimately outlast the window, and that daemon should be
|
|
456
514
|
// allowed to finish and serve.
|
|
457
515
|
const childOwnsMigrationLock = exclusiveLockOwnerPid(onDiskMigrationLockPath()) === pid;
|
|
458
|
-
if (exitState === null && !childOwnsMigrationLock) {
|
|
516
|
+
if (exitState === null && !childOwnsMigrationLock && !(error instanceof DaemonStartupBlockedError)) {
|
|
459
517
|
try {
|
|
460
518
|
await stopDaemonProcess(pid, DAEMON_REAP_WINDOW_MS);
|
|
461
519
|
}
|
|
@@ -464,9 +522,9 @@ export async function spawnDaemon() {
|
|
|
464
522
|
throw error;
|
|
465
523
|
}
|
|
466
524
|
if (existingPid !== null) {
|
|
467
|
-
return { started: false, existing_pid: existingPid };
|
|
525
|
+
return { started: false, existing_pid: existingPid, startup_phase: targetPhase };
|
|
468
526
|
}
|
|
469
|
-
return { started: true, pid };
|
|
527
|
+
return { started: true, pid, startup_phase: targetPhase };
|
|
470
528
|
}
|
|
471
529
|
// ensureDaemon — fire-and-forget front-door helper
|
|
472
530
|
/** Whether autostart is suppressed for this invocation. `--no-autostart` or
|
|
@@ -495,24 +553,13 @@ const AUTOSTART_BACKOFF_MAX_MS = 60_000;
|
|
|
495
553
|
let autostartInFlight = false;
|
|
496
554
|
let autostartFailures = 0;
|
|
497
555
|
let autostartNextAttemptAt = 0;
|
|
498
|
-
let autostartBlocked = null;
|
|
499
556
|
function autostartBackoffMs(failures) {
|
|
500
557
|
return Math.min(AUTOSTART_BACKOFF_BASE_MS * 2 ** (failures - 1), AUTOSTART_BACKOFF_MAX_MS);
|
|
501
558
|
}
|
|
502
|
-
/**
|
|
503
|
-
* run. Set only by a `DaemonStartupBlockedError`, which no retry can clear —
|
|
504
|
-
* an explicit `crtr sys daemon start` still calls `spawnDaemon` directly and
|
|
505
|
-
* reports the failure in full. */
|
|
506
|
-
export function daemonAutostartSuppression() {
|
|
507
|
-
return autostartBlocked;
|
|
508
|
-
}
|
|
509
|
-
/** Clear the suppression and the backoff — for a caller that has repaired the
|
|
510
|
-
* standing condition and wants autostart live again without a new process. */
|
|
559
|
+
/** Reset in-process spawn backoff after a daemon is observed alive. */
|
|
511
560
|
export function resetDaemonAutostart() {
|
|
512
561
|
autostartFailures = 0;
|
|
513
562
|
autostartNextAttemptAt = 0;
|
|
514
|
-
autostartBlocked = null;
|
|
515
|
-
clearDaemonStartupBlocked();
|
|
516
563
|
}
|
|
517
564
|
/** Start the daemon if it is not already running. No-op if already up, if
|
|
518
565
|
* autostart is suppressed for this invocation, while an attempt is in flight,
|
|
@@ -525,8 +572,6 @@ export function ensureDaemon(deps = {}) {
|
|
|
525
572
|
const now = deps.now ?? Date.now;
|
|
526
573
|
if (autostartDisabled())
|
|
527
574
|
return;
|
|
528
|
-
if (autostartBlocked !== null)
|
|
529
|
-
return;
|
|
530
575
|
if (autostartInFlight)
|
|
531
576
|
return;
|
|
532
577
|
if (now() < autostartNextAttemptAt)
|
|
@@ -535,15 +580,6 @@ export function ensureDaemon(deps = {}) {
|
|
|
535
580
|
resetDaemonAutostart();
|
|
536
581
|
return;
|
|
537
582
|
}
|
|
538
|
-
// The durable half of the gate. Everything above is module state, which caps
|
|
539
|
-
// exactly one process; the storm is made of many. A daemon that already
|
|
540
|
-
// proved startup is blocked left this marker in the canvas home, and it
|
|
541
|
-
// retires itself as soon as the corpus it named changes.
|
|
542
|
-
const blocked = daemonStartupBlocked();
|
|
543
|
-
if (blocked !== null) {
|
|
544
|
-
autostartBlocked = blocked;
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
583
|
autostartInFlight = true;
|
|
548
584
|
void spawn().then(() => {
|
|
549
585
|
autostartFailures = 0;
|
|
@@ -553,8 +589,6 @@ export function ensureDaemon(deps = {}) {
|
|
|
553
589
|
// pre-build) must not break the calling command.
|
|
554
590
|
autostartFailures += 1;
|
|
555
591
|
autostartNextAttemptAt = now() + autostartBackoffMs(autostartFailures);
|
|
556
|
-
if (error instanceof DaemonStartupBlockedError)
|
|
557
|
-
autostartBlocked = error.message;
|
|
558
592
|
}).finally(() => {
|
|
559
593
|
autostartInFlight = false;
|
|
560
594
|
});
|
|
@@ -14,7 +14,7 @@ export interface RuntimeMessageCard {
|
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Deliver one daemon-originated node message. Interactive messages use the live
|
|
17
|
-
* broker when available; every other successful path is
|
|
17
|
+
* broker when available; every other successful path is durable node mail.
|
|
18
18
|
*/
|
|
19
19
|
export declare function deliverNodeMessage(args: {
|
|
20
20
|
node_id: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getNode } from '../../core/canvas/canvas.js';
|
|
2
2
|
import { cancelCronsOnWake } from '../../core/canvas/crons.js';
|
|
3
3
|
import { withFreshTerminalGuard } from '../../core/canvas/canvas.js';
|
|
4
|
-
import {
|
|
4
|
+
import { enqueueNodeMail } from '../../core/feed/messages.js';
|
|
5
5
|
import { BrokerUnreachableError } from '../../core/runtime/broker-request.js';
|
|
6
6
|
import { deliverLive } from '../../core/runtime/interactive-deliver.js';
|
|
7
7
|
import { isBrokerLive } from '../../core/runtime/model-swap.js';
|
|
@@ -24,7 +24,7 @@ function guardRoutable(nodeId, body) {
|
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Deliver one daemon-originated node message. Interactive messages use the live
|
|
27
|
-
* broker when available; every other successful path is
|
|
27
|
+
* broker when available; every other successful path is durable node mail.
|
|
28
28
|
*/
|
|
29
29
|
export async function deliverNodeMessage(args) {
|
|
30
30
|
// A live interactive delivery has no durable append to guard, so establish
|
|
@@ -67,20 +67,17 @@ export async function deliverNodeMessage(args) {
|
|
|
67
67
|
throw error;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
const entry = guardRoutable(args.node_id, () =>
|
|
71
|
-
|
|
72
|
-
tier: args.mode === 'quiet' ? 'deferred' : 'normal',
|
|
70
|
+
const entry = guardRoutable(args.node_id, () => enqueueNodeMail(args.node_id, {
|
|
71
|
+
senderNodeId: args.from ?? null,
|
|
73
72
|
kind: 'message',
|
|
74
73
|
label: args.label,
|
|
75
|
-
|
|
74
|
+
bodyJson: { ...args.data, body: args.body },
|
|
75
|
+
urgency: args.mode === 'quiet' ? 'deferred' : 'normal',
|
|
76
|
+
wake: 1,
|
|
76
77
|
}));
|
|
77
|
-
if (entry.tier !== 'deferred' || target.frozen_at !== null)
|
|
78
|
-
cancelCronsOnWake(args.node_id);
|
|
79
|
-
// The APPENDED entry's tier decides the wake: a quiet send to a terminal
|
|
80
|
-
// target was raised out of `deferred` by the append, and must be delivered.
|
|
81
78
|
let revived = false;
|
|
82
79
|
let reason;
|
|
83
|
-
if (entry.
|
|
80
|
+
if (entry.urgency !== 'deferred') {
|
|
84
81
|
target = getNode(args.node_id);
|
|
85
82
|
if (target === null)
|
|
86
83
|
deliveryUnroutable(args.node_id, 'origin_missing');
|
|
@@ -98,5 +95,5 @@ export async function deliverNodeMessage(args) {
|
|
|
98
95
|
}
|
|
99
96
|
}
|
|
100
97
|
}
|
|
101
|
-
return { entry_id: entry.
|
|
98
|
+
return { entry_id: entry.messageId, via: 'inbox', revived, ...(reason === undefined ? {} : { reason }) };
|
|
102
99
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { statSync } from 'node:fs';
|
|
2
2
|
import { emitEvent } from '../core/events/emit.js';
|
|
3
|
-
import { hasWakeMailSince } from '../core/
|
|
4
|
-
import {
|
|
3
|
+
import { hasWakeMailSince } from '../core/canvas/deliveries.js';
|
|
4
|
+
import { readLiveTurn } from '../core/canvas/recovery.js';
|
|
5
5
|
import { parkEvent } from './reconcilers/live-obligation.js';
|
|
6
6
|
/** A main-session write after parking was armed is durable evidence of live
|
|
7
7
|
* input even when the turn has since settled and the viewer detached. */
|
|
@@ -23,7 +23,7 @@ export function mainSessionActivitySince(sessionFile, startedAt) {
|
|
|
23
23
|
* the verdict cannot race a viewer, live delivery, or durable wake. */
|
|
24
24
|
export function shouldParkAfterSummary(nodeId, node, pending) {
|
|
25
25
|
return !pending.activity
|
|
26
|
-
&&
|
|
26
|
+
&& readLiveTurn(nodeId)?.busy !== true
|
|
27
27
|
&& !mainSessionActivitySince(node.pi_session_file, pending.startedAt)
|
|
28
28
|
&& !hasWakeMailSince(nodeId, pending.startedAt)
|
|
29
29
|
&& parkEvent(nodeId, node.lifecycle) === 'park';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { bashJobPaths, expiredAutoBackgroundBashJobs, formatBashElapsed, stopBackgroundBashJob, } from '../../core/bash-jobs.js';
|
|
2
2
|
import { isSafeNodeId } from '../../core/canvas/paths.js';
|
|
3
3
|
import { contextDir } from '../../core/canvas/paths.js';
|
|
4
|
-
import {
|
|
5
|
-
import { appendInbox } from '../../core/feed/inbox.js';
|
|
4
|
+
import { enqueueNodeMail } from '../../core/feed/messages.js';
|
|
6
5
|
import { emitEvent } from '../../core/events/emit.js';
|
|
7
6
|
import { operationIdContext } from '../../core/events/operation-id.js';
|
|
8
7
|
import { isProfilePaused } from '../../core/profiles/manifest.js';
|
|
@@ -60,18 +59,18 @@ export class BashDeadlineReconciler {
|
|
|
60
59
|
operationIdContext.fresh(() => {
|
|
61
60
|
try {
|
|
62
61
|
emitEvent({ level: 'info', event: 'bash_deadline.canceled', ...(isSafeNodeId(nodeId) ? { node_id: nodeId } : {}), fields: { job_id: jobId } });
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
62
|
+
enqueueNodeMail(nodeId, {
|
|
63
|
+
senderNodeId: null,
|
|
64
|
+
urgency: 'urgent',
|
|
65
|
+
wake: 1,
|
|
66
66
|
kind: 'urgent',
|
|
67
67
|
label: 'background bash job canceled at its deadline',
|
|
68
|
-
|
|
68
|
+
bodyJson: {
|
|
69
69
|
body: `Background bash job ${jobId} was canceled after ${formatBashElapsed(elapsedMs)} because its background deadline passed and you did not claim it. ` +
|
|
70
70
|
`Next time, give a long command more room up front (a larger inline timeout), or claim the job with \`crtr node bash extend ${jobId} --for <duration>\` before the deadline. ` +
|
|
71
71
|
`Log: ${paths.jobLog} Command: ${paths.cmdSh}`,
|
|
72
72
|
},
|
|
73
73
|
});
|
|
74
|
-
cancelCronsOnWake(nodeId);
|
|
75
74
|
}
|
|
76
75
|
catch (err) {
|
|
77
76
|
emitEvent({ level: 'error', event: 'bash_deadline.notice_failed', ...(isSafeNodeId(nodeId) ? { node_id: nodeId } : {}), error: err, fields: { job_id: jobId } });
|
|
@@ -55,7 +55,7 @@ export declare class BrokerSupervisionReconciler {
|
|
|
55
55
|
private readonly unattendedSince;
|
|
56
56
|
private readonly sampleTree;
|
|
57
57
|
private readonly signal;
|
|
58
|
-
private
|
|
58
|
+
private knownCredentialRevision;
|
|
59
59
|
private lastOverCapWarnAt;
|
|
60
60
|
constructor(options?: BrokerSupervisionOptions);
|
|
61
61
|
/** The fleet-wide preamble, run BEFORE the tick's row-list guard: an auth
|