@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
package/dist/core/feed/inbox.js
CHANGED
|
@@ -1,23 +1,5 @@
|
|
|
1
|
-
// Per-node inbox.jsonl primitive for the pi-native canvas runtime.
|
|
2
|
-
//
|
|
3
|
-
// An inbox entry is a lightweight pointer for a push (~30 tokens, body lives
|
|
4
|
-
// in nodes/<id>/reports/) or carries a direct message inline. A direct
|
|
5
|
-
// message short enough to inline stays entirely in the jsonl line; one that
|
|
6
|
-
// would clip spills its full body to nodes/<id>/messages/ and the entry
|
|
7
|
-
// carries `ref` to it alongside a bounded inline preview.
|
|
8
|
-
//
|
|
9
|
-
// Layout:
|
|
10
|
-
// nodes/<id>/inbox.jsonl — one JSON line per entry, append-only
|
|
11
|
-
// nodes/<id>/inbox.jsonl.cursor — exact identity of the last successfully
|
|
12
|
-
// settled/covered entry (sidecar), distinct from the in-memory read position
|
|
13
|
-
import { appendFileSync, existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, } from 'node:fs';
|
|
14
|
-
import { dirname, join } from 'node:path';
|
|
15
|
-
import { randomBytes, randomUUID } from 'node:crypto';
|
|
16
|
-
import { deliverAndSettleMessageWait, getRow, inboxPath, messagesDir, settleDeadMessageWait } from '../canvas/index.js';
|
|
17
1
|
import { resolveRef } from '../canvas/history.js';
|
|
18
|
-
import {
|
|
19
|
-
import { errorClassFromError } from '../events/errors.js';
|
|
20
|
-
import { generateOperationId, operationIdContext, validateOperationId } from '../events/operation-id.js';
|
|
2
|
+
import { validateOperationId } from '../events/operation-id.js';
|
|
21
3
|
import { formatInboxCard, formatInboxRefInstruction } from '../../shared/generated-context.js';
|
|
22
4
|
import { renderBirthAnnouncementBody } from '../../shared/birth-announcement.js';
|
|
23
5
|
const INBOX_ENTRY_ID = /^(?!0{32}$)[0-9a-f]{32}$/;
|
|
@@ -26,321 +8,27 @@ function validateInboxEntryId(value) {
|
|
|
26
8
|
throw new TypeError('entry_id must be 32 lowercase non-zero hexadecimal characters');
|
|
27
9
|
return value;
|
|
28
10
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
value = randomBytes(16).toString('hex');
|
|
33
|
-
while (value === '00000000000000000000000000000000');
|
|
34
|
-
return validateInboxEntryId(value);
|
|
35
|
-
}
|
|
36
|
-
/** Complete an entry exactly once before any spill or append work. */
|
|
37
|
-
export function finalizeInboxEntry(input) {
|
|
38
|
-
const operationId = input.operation_id === undefined
|
|
39
|
-
? operationIdContext.current() ?? generateOperationId()
|
|
40
|
-
: validateOperationId(input.operation_id);
|
|
11
|
+
/** Project the immutable message body and destination-specific urgency into the canonical inbox rendering shape. */
|
|
12
|
+
export function nodeMailEntry(delivery) {
|
|
13
|
+
const message = delivery.message;
|
|
41
14
|
return {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
15
|
+
entry_id: validateInboxEntryId(message.messageId),
|
|
16
|
+
operation_id: validateOperationId(message.operationId),
|
|
17
|
+
ts: message.createdAt,
|
|
18
|
+
from: message.senderNodeId,
|
|
19
|
+
...(message.senderName === null ? {} : { from_name: message.senderName }),
|
|
20
|
+
tier: delivery.urgency,
|
|
21
|
+
kind: message.kind,
|
|
22
|
+
...(message.bodyRef === null ? {} : { ref: message.bodyRef }),
|
|
23
|
+
label: message.label,
|
|
24
|
+
...(message.bodyJson === null ? {} : { data: message.bodyJson }),
|
|
25
|
+
...(message.disposition === null ? {} : { disposition: message.disposition }),
|
|
46
26
|
};
|
|
47
27
|
}
|
|
48
|
-
// Cursor sidecar path
|
|
49
|
-
function cursorPath(nodeId) {
|
|
50
|
-
return `${inboxPath(nodeId)}.cursor`;
|
|
51
|
-
}
|
|
52
|
-
// Append
|
|
53
|
-
/** Spill an oversized inline body to a durable file — the SAME atomic
|
|
54
|
-
* tmp+rename pattern a push report uses — and return its absolute path.
|
|
55
|
-
* Called only when the body would clip in the digest; short bodies never
|
|
56
|
-
* touch disk beyond the jsonl line itself. */
|
|
57
|
-
function writeMessageBody(nodeId, ts, body) {
|
|
58
|
-
const dir = messagesDir(nodeId);
|
|
59
|
-
if (!existsSync(dir))
|
|
60
|
-
mkdirSync(dir, { recursive: true });
|
|
61
|
-
const stamp = ts.replace(/[^0-9]/g, '');
|
|
62
|
-
const finalPath = join(dir, `${stamp}-${randomUUID().slice(0, 6)}.md`);
|
|
63
|
-
const tmpPath = `${finalPath}.tmp`;
|
|
64
|
-
writeFileSync(tmpPath, body, 'utf8');
|
|
65
|
-
renameSync(tmpPath, finalPath);
|
|
66
|
-
return finalPath;
|
|
67
|
-
}
|
|
68
|
-
/** The tier a live watcher injects into the turn a node is ALREADY running
|
|
69
|
-
* (`visibleRoute`, canvas-inbox-watcher). `normal` and `deferred` both wait
|
|
70
|
-
* for a later cycle instead. */
|
|
71
|
-
const STEERING_TIER = 'urgent';
|
|
72
|
-
/** The tier an entry is actually appended at. A terminal node owes one final
|
|
73
|
-
* result and reaps on it, so the later cycle `normal` and `deferred` wait for
|
|
74
|
-
* is one it may never take — mail handed to such a node is raised to the
|
|
75
|
-
* steering tier so the turn it is running now carries it, and so a dormant one
|
|
76
|
-
* is woken for it rather than holding it forever. */
|
|
77
|
-
function effectiveTier(nodeId, tier) {
|
|
78
|
-
if (tier !== 'normal' && tier !== 'deferred')
|
|
79
|
-
return tier;
|
|
80
|
-
return getRow(nodeId)?.lifecycle === 'terminal' ? STEERING_TIER : tier;
|
|
81
|
-
}
|
|
82
|
-
/** Atomically append one finalized inbox entry to `nodes/<nodeId>/inbox.jsonl`,
|
|
83
|
-
* at the tier `effectiveTier` resolves for this target. */
|
|
84
|
-
export function appendInbox(nodeId, entry) {
|
|
85
|
-
const full = finalizeInboxEntry({ ...entry, tier: effectiveTier(nodeId, entry.tier) });
|
|
86
|
-
try {
|
|
87
|
-
// A push pointer already carries its canonical history `ref` — its body
|
|
88
|
-
// lives in the report file, never inline. A direct message / system notice has no ref yet: when
|
|
89
|
-
// its inline body would clip in the digest, spill the FULL text to a durable
|
|
90
|
-
// file (same atomic tmp+rename as a report) and point `ref` at it, exactly
|
|
91
|
-
// like a push, then keep only the bounded preview inline. A short body is
|
|
92
|
-
// left fully inline, untouched — uniform with how a push's body always
|
|
93
|
-
// lives in a file, never inline, dereferenced by reading `ref`.
|
|
94
|
-
if (full.ref === undefined) {
|
|
95
|
-
const body = inlineBody(full);
|
|
96
|
-
const { text, clipped } = clipBody(body);
|
|
97
|
-
if (clipped) {
|
|
98
|
-
full.ref = writeMessageBody(nodeId, full.ts, body);
|
|
99
|
-
full.data = { ...full.data, body: text };
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const line = JSON.stringify(full) + '\n';
|
|
103
|
-
// Ensure the parent directory exists (inbox.jsonl lives directly under the
|
|
104
|
-
// node dir, which ensureNodeDirs creates — but guard anyway for callers that
|
|
105
|
-
// haven't yet scaffolded the node).
|
|
106
|
-
const dir = dirname(inboxPath(nodeId));
|
|
107
|
-
if (!existsSync(dir))
|
|
108
|
-
mkdirSync(dir, { recursive: true });
|
|
109
|
-
// The append and matching wait settlement share SQLite's write boundary.
|
|
110
|
-
// A re-arm therefore cannot land between this delivery and its clear.
|
|
111
|
-
return deliverAndSettleMessageWait(nodeId, entry.from, () => {
|
|
112
|
-
// appendFileSync is atomic within a single process (a single write(2) call for
|
|
113
|
-
// a short line is atomic on POSIX). For multi-process safety we rely on the
|
|
114
|
-
// OS-level append guarantee (O_APPEND) which Node honours via 'a' flag.
|
|
115
|
-
appendFileSync(inboxPath(nodeId), line, { encoding: 'utf8', flag: 'a' });
|
|
116
|
-
return full;
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
catch (error) {
|
|
120
|
-
emitActiveAppendFailure(nodeId, full, error);
|
|
121
|
-
throw error;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
function emitActiveAppendFailure(nodeId, entry, error) {
|
|
125
|
-
try {
|
|
126
|
-
emitEvent({
|
|
127
|
-
level: 'error',
|
|
128
|
-
event: 'inbox.delivery.failed',
|
|
129
|
-
operation_id: entry.operation_id,
|
|
130
|
-
outcome: 'failed',
|
|
131
|
-
error,
|
|
132
|
-
error_class: errorClassFromError(error),
|
|
133
|
-
fields: { stage: 'append', channel: 'active', target_node_id: nodeId },
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
catch {
|
|
137
|
-
// Event emission is observational; the original append failure remains authoritative.
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
/** Deliver the one system notice for a controller that can no longer satisfy a
|
|
141
|
-
* wait. Returns null when another durable operation already settled or re-armed
|
|
142
|
-
* that wait. */
|
|
143
|
-
export function appendControllerDeathNotice(nodeId, controller) {
|
|
144
|
-
const full = finalizeInboxEntry({
|
|
145
|
-
from: null,
|
|
146
|
-
tier: 'urgent',
|
|
147
|
-
kind: 'urgent',
|
|
148
|
-
label: 'declared controller is no longer live',
|
|
149
|
-
data: { body: `Controller ${controller} is no longer live; the declared message wait was cleared.` },
|
|
150
|
-
});
|
|
151
|
-
try {
|
|
152
|
-
const line = JSON.stringify(full) + '\n';
|
|
153
|
-
const dir = dirname(inboxPath(nodeId));
|
|
154
|
-
if (!existsSync(dir))
|
|
155
|
-
mkdirSync(dir, { recursive: true });
|
|
156
|
-
return settleDeadMessageWait(nodeId, controller, () => {
|
|
157
|
-
appendFileSync(inboxPath(nodeId), line, { encoding: 'utf8', flag: 'a' });
|
|
158
|
-
return full;
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
emitActiveAppendFailure(nodeId, full, error);
|
|
163
|
-
throw error;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
// Read
|
|
167
|
-
function readPhysicalInbox(nodeId) {
|
|
168
|
-
const p = inboxPath(nodeId);
|
|
169
|
-
if (!existsSync(p))
|
|
170
|
-
return [];
|
|
171
|
-
const raw = readFileSync(p, 'utf8');
|
|
172
|
-
if (raw === '')
|
|
173
|
-
return [];
|
|
174
|
-
const lines = raw.split('\n');
|
|
175
|
-
if (lines.at(-1) === '')
|
|
176
|
-
lines.pop();
|
|
177
|
-
if (lines.some((line) => line.trim() === ''))
|
|
178
|
-
throw new Error('inbox contains a blank physical line');
|
|
179
|
-
const entries = lines.map((line) => {
|
|
180
|
-
const entry = JSON.parse(line);
|
|
181
|
-
entry.entry_id = validateInboxEntryId(entry.entry_id);
|
|
182
|
-
entry.operation_id = validateOperationId(entry.operation_id);
|
|
183
|
-
return entry;
|
|
184
|
-
});
|
|
185
|
-
const seen = new Set();
|
|
186
|
-
for (const entry of entries) {
|
|
187
|
-
if (seen.has(entry.entry_id))
|
|
188
|
-
throw new Error(`duplicate inbox entry_id: ${entry.entry_id}`);
|
|
189
|
-
seen.add(entry.entry_id);
|
|
190
|
-
}
|
|
191
|
-
return entries;
|
|
192
|
-
}
|
|
193
|
-
function cursorIndex(entries, rawCursor) {
|
|
194
|
-
const cursor = validateInboxEntryId(rawCursor);
|
|
195
|
-
return entries.findIndex((entry) => entry.entry_id === cursor);
|
|
196
|
-
}
|
|
197
|
-
/** Return the physical suffix strictly after the exact cursor identity. */
|
|
198
|
-
export function readInboxSince(nodeId, cursorEntryId) {
|
|
199
|
-
const entries = readPhysicalInbox(nodeId);
|
|
200
|
-
if (cursorEntryId === undefined)
|
|
201
|
-
return entries;
|
|
202
|
-
const index = cursorIndex(entries, cursorEntryId);
|
|
203
|
-
if (index < 0) {
|
|
204
|
-
throw new Error(`inbox cursor entry_id not found: ${validateInboxEntryId(cursorEntryId)}`);
|
|
205
|
-
}
|
|
206
|
-
return entries.slice(index + 1);
|
|
207
|
-
}
|
|
208
|
-
/** Read one exact contiguous physical range after an exclusive boundary through an inclusive boundary. */
|
|
209
|
-
export function readInboxRange(nodeId, afterEntryId, throughEntryId) {
|
|
210
|
-
const after = afterEntryId === undefined ? undefined : validateInboxEntryId(afterEntryId);
|
|
211
|
-
const through = validateInboxEntryId(throughEntryId);
|
|
212
|
-
const entries = readPhysicalInbox(nodeId);
|
|
213
|
-
const throughIndex = entries.findIndex((entry) => entry.entry_id === through);
|
|
214
|
-
if (throughIndex < 0)
|
|
215
|
-
throw new Error(`inbox range through entry_id not found: ${through}`);
|
|
216
|
-
if (after === undefined)
|
|
217
|
-
return entries.slice(0, throughIndex + 1);
|
|
218
|
-
const afterIndex = entries.findIndex((entry) => entry.entry_id === after);
|
|
219
|
-
if (afterIndex < 0)
|
|
220
|
-
throw new Error(`inbox range after entry_id not found: ${after}`);
|
|
221
|
-
if (afterIndex >= throughIndex)
|
|
222
|
-
throw new Error(`inbox range is reversed: ${after} through ${through}`);
|
|
223
|
-
return entries.slice(afterIndex + 1, throughIndex + 1);
|
|
224
|
-
}
|
|
225
|
-
// Cancel set (interrupt-canceled entries)
|
|
226
|
-
function canceledPath(nodeId) {
|
|
227
|
-
return `${inboxPath(nodeId)}.canceled`;
|
|
228
|
-
}
|
|
229
|
-
/** Entry ids a human interrupt canceled before delivery. Append-only sidecar
|
|
230
|
-
* (the inbox itself is append-only — never mutated in place): one entry_id
|
|
231
|
-
* per line. The watcher skips canceled entries at plan time; a missing file
|
|
232
|
-
* is an empty set. */
|
|
233
|
-
export function readCanceledEntryIds(nodeId) {
|
|
234
|
-
const p = canceledPath(nodeId);
|
|
235
|
-
if (!existsSync(p))
|
|
236
|
-
return new Set();
|
|
237
|
-
const out = new Set();
|
|
238
|
-
for (const line of readFileSync(p, 'utf8').split('\n')) {
|
|
239
|
-
const trimmed = line.trim();
|
|
240
|
-
if (trimmed === '')
|
|
241
|
-
continue;
|
|
242
|
-
out.add(validateInboxEntryId(trimmed));
|
|
243
|
-
}
|
|
244
|
-
return out;
|
|
245
|
-
}
|
|
246
|
-
/** Mark every not-yet-settled HUMAN message entry canceled — the boot-window
|
|
247
|
-
* half of a first-class interrupt (`POST /v1/nodes/{id}/interrupt`): a send
|
|
248
|
-
* that rode the durable inbox (dormant target, or the mid-revive fallback)
|
|
249
|
-
* must not be injected after the human pressed Esc. Scope: `from === 'human'`
|
|
250
|
-
* `kind: 'message'` entries ONLY — a human Esc never cancels spine/agent
|
|
251
|
-
* messages or system notices. Entries past the durable cursor that a live
|
|
252
|
-
* watcher already handed to the engine may be over-canceled; that is safe —
|
|
253
|
-
* the interrupt's abort lands right behind, and covered handoffs are never
|
|
254
|
-
* re-delivered anyway. Returns the newly canceled entry ids. */
|
|
255
|
-
export function cancelPendingHumanMessages(nodeId) {
|
|
256
|
-
return cancelPendingEntries(nodeId, (e) => e.from === 'human' && e.kind === 'message');
|
|
257
|
-
}
|
|
258
|
-
/** Cancel every not-yet-settled entry the predicate selects. Retraction, not
|
|
259
|
-
* deletion: the append-only inbox is untouched and the sidecar grows. Safe to
|
|
260
|
-
* call late — an entry already past the cursor is not pending, and the watcher
|
|
261
|
-
* re-reads the set at plan time so a cancel racing a buffered entry still
|
|
262
|
-
* lands. */
|
|
263
|
-
export function cancelPendingEntries(nodeId, select) {
|
|
264
|
-
const cursor = readCursor(nodeId);
|
|
265
|
-
const pending = readInboxSince(nodeId, cursor);
|
|
266
|
-
const already = readCanceledEntryIds(nodeId);
|
|
267
|
-
const targets = pending
|
|
268
|
-
.filter((e) => !already.has(e.entry_id) && select(e))
|
|
269
|
-
.map((e) => e.entry_id);
|
|
270
|
-
if (targets.length === 0)
|
|
271
|
-
return [];
|
|
272
|
-
const dir = dirname(inboxPath(nodeId));
|
|
273
|
-
if (!existsSync(dir))
|
|
274
|
-
mkdirSync(dir, { recursive: true });
|
|
275
|
-
appendFileSync(canceledPath(nodeId), targets.join('\n') + '\n', { encoding: 'utf8', flag: 'a' });
|
|
276
|
-
return targets;
|
|
277
|
-
}
|
|
278
|
-
// Cursor persistence
|
|
279
|
-
/** Read and validate the persisted exact cursor identity. */
|
|
280
|
-
export function readCursor(nodeId) {
|
|
281
|
-
const p = cursorPath(nodeId);
|
|
282
|
-
if (!existsSync(p))
|
|
283
|
-
return undefined;
|
|
284
|
-
const raw = readFileSync(p, 'utf8').trim();
|
|
285
|
-
if (raw === '')
|
|
286
|
-
return undefined;
|
|
287
|
-
return validateInboxEntryId(raw);
|
|
288
|
-
}
|
|
289
|
-
/** Persist one validated exact cursor identity (atomic tmp+rename). */
|
|
290
|
-
export function writeCursor(nodeId, entryId) {
|
|
291
|
-
const value = validateInboxEntryId(entryId);
|
|
292
|
-
const p = cursorPath(nodeId);
|
|
293
|
-
const tmp = `${p}.tmp`;
|
|
294
|
-
const dir = dirname(p);
|
|
295
|
-
if (!existsSync(dir))
|
|
296
|
-
mkdirSync(dir, { recursive: true });
|
|
297
|
-
writeFileSync(tmp, value, 'utf8');
|
|
298
|
-
renameSync(tmp, p);
|
|
299
|
-
}
|
|
300
|
-
/** Is there mail this node has not seen that would drive a turn? The one
|
|
301
|
-
* authority for "wake-worthy inbox state", read by the park clock, the
|
|
302
|
-
* settlement policy, the review-companion guard, and reviveNode's parked
|
|
303
|
-
* re-entry rule. Deferred entries are excluded everywhere for the same
|
|
304
|
-
* reason: a deferred entry rides the next natural cycle and never starts one.
|
|
305
|
-
* A cursor that no longer resolves against the physical inbox is a fault, not
|
|
306
|
-
* an answer — every caller's conservative reading of this predicate is `true`
|
|
307
|
-
* (do not park, do not shut down, do not resume quietly), so report it and
|
|
308
|
-
* return that. */
|
|
309
|
-
export function hasUnseenWakeMail(nodeId) {
|
|
310
|
-
try {
|
|
311
|
-
return readInboxSince(nodeId, readCursor(nodeId)).some((entry) => entry.tier !== 'deferred');
|
|
312
|
-
}
|
|
313
|
-
catch (error) {
|
|
314
|
-
emitEvent({ level: 'warn', event: 'inbox.wake_scan.failed', node_id: nodeId, error });
|
|
315
|
-
return true;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
/** Whether wake-capable mail arrived at or after a parking turn began. Unlike
|
|
319
|
-
* `hasUnseenWakeMail`, this deliberately includes mail the main engine already
|
|
320
|
-
* consumed: a shadow completion must not undo activity that occurred while it
|
|
321
|
-
* ran. A failed scan conservatively keeps the node live. */
|
|
322
|
-
export function hasWakeMailSince(nodeId, sinceMs) {
|
|
323
|
-
try {
|
|
324
|
-
return readPhysicalInbox(nodeId).some((entry) => entry.tier !== 'deferred' && Date.parse(entry.ts) >= sinceMs);
|
|
325
|
-
}
|
|
326
|
-
catch (error) {
|
|
327
|
-
emitEvent({ level: 'warn', event: 'inbox.wake_scan.failed', node_id: nodeId, error });
|
|
328
|
-
return true;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
// Coalesce
|
|
332
|
-
/** Bounds for inlining a message body's preview in the digest. */
|
|
333
28
|
const BODY_MAX_LINES = 12;
|
|
334
29
|
const BODY_MAX_CHARS = 1000;
|
|
335
30
|
const INLINE_REPORT_MAX_CHARS = 1000;
|
|
336
|
-
/**
|
|
337
|
-
* Empty for a push pointer (whose body lives at `ref`) or a one-line entry
|
|
338
|
-
* whose `label` already IS the whole message. */
|
|
339
|
-
function inlineBody(e) {
|
|
340
|
-
const body = typeof e.data?.['body'] === 'string' ? e.data['body'].trim() : '';
|
|
341
|
-
return body === '' || body === e.label ? '' : body;
|
|
342
|
-
}
|
|
343
|
-
/** Clip a body to a bounded preview, reporting whether anything was dropped. */
|
|
31
|
+
/** Clip a body to the bounded preview stored beside a spilled message body. */
|
|
344
32
|
export function clipBody(body) {
|
|
345
33
|
let text = body;
|
|
346
34
|
let clipped = false;
|
|
@@ -355,83 +43,65 @@ export function clipBody(body) {
|
|
|
355
43
|
}
|
|
356
44
|
return { text: text.trimEnd(), clipped };
|
|
357
45
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
46
|
+
function inlineBody(entry) {
|
|
47
|
+
const body = typeof entry.data?.['body'] === 'string' ? entry.data['body'].trim() : '';
|
|
48
|
+
return body === '' || body === entry.label ? '' : body;
|
|
49
|
+
}
|
|
50
|
+
function inlineReport(entry) {
|
|
51
|
+
if (entry.ref === undefined || entry.ref.startsWith('/'))
|
|
362
52
|
return null;
|
|
363
53
|
try {
|
|
364
|
-
const report = resolveRef(
|
|
54
|
+
const report = resolveRef(entry.ref);
|
|
365
55
|
if (report?.source !== 'report' || report.path === null || report.body.length >= INLINE_REPORT_MAX_CHARS)
|
|
366
56
|
return null;
|
|
367
57
|
return report.body;
|
|
368
58
|
}
|
|
369
59
|
catch {
|
|
370
|
-
// A malformed or unavailable history ref remains a pointer in the digest.
|
|
371
60
|
return null;
|
|
372
61
|
}
|
|
373
62
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
*
|
|
377
|
-
* A short pushed report is inlined as its own body; the label is NOT repeated
|
|
378
|
-
* above it, because a report's label is just its first line (feed.ts
|
|
379
|
-
* `firstLine`), so carrying both reads as a truncated preview stacked on the
|
|
380
|
-
* full text it previews. A larger report has only its label, with `ref`
|
|
381
|
-
* carrying the pointer. Direct messages keep their bounded inline-body/spill
|
|
382
|
-
* behavior.
|
|
383
|
-
*/
|
|
384
|
-
function entryBody(e) {
|
|
385
|
-
const birth = renderBirthAnnouncementBody(e.data, e.ts);
|
|
63
|
+
function entryBody(entry) {
|
|
64
|
+
const birth = renderBirthAnnouncementBody(entry.data, entry.ts);
|
|
386
65
|
if (birth !== null)
|
|
387
66
|
return birth;
|
|
388
|
-
const report = inlineReport(
|
|
67
|
+
const report = inlineReport(entry);
|
|
389
68
|
if (report !== null)
|
|
390
|
-
return `${report.trimEnd()}\n\n${formatInboxRefInstruction(
|
|
391
|
-
const body = inlineBody(
|
|
69
|
+
return `${report.trimEnd()}\n\n${formatInboxRefInstruction(entry.ref)}`;
|
|
70
|
+
const body = inlineBody(entry);
|
|
392
71
|
if (body === '')
|
|
393
|
-
return
|
|
72
|
+
return entry.ref === undefined ? entry.label : `${entry.label}\n\n${formatInboxRefInstruction(entry.ref)}`;
|
|
394
73
|
const { text, clipped } = clipBody(body);
|
|
395
|
-
if (
|
|
396
|
-
return `${text}\n\n${formatInboxRefInstruction(
|
|
74
|
+
if (entry.ref !== undefined)
|
|
75
|
+
return `${text}\n\n${formatInboxRefInstruction(entry.ref)}`;
|
|
397
76
|
return clipped ? `${text}\n… (body clipped)` : text;
|
|
398
77
|
}
|
|
399
|
-
function cardEntry(
|
|
78
|
+
function cardEntry(entry) {
|
|
400
79
|
return {
|
|
401
|
-
kind:
|
|
402
|
-
body: entryBody(
|
|
403
|
-
...(
|
|
404
|
-
...(
|
|
80
|
+
kind: entry.kind,
|
|
81
|
+
body: entryBody(entry),
|
|
82
|
+
...(entry.ref === undefined ? {} : { ref: entry.ref }),
|
|
83
|
+
...(entry.disposition === undefined ? {} : { disposition: entry.disposition }),
|
|
405
84
|
};
|
|
406
85
|
}
|
|
407
|
-
/** Split
|
|
408
|
-
* verbatim, and every other sender in one `<runtime kind="inbox">` card. */
|
|
86
|
+
/** Split delivered entries into verbatim human messages and sender-grouped inbox cards. */
|
|
409
87
|
export function coalesce(entries) {
|
|
410
88
|
if (entries.length === 0)
|
|
411
89
|
return [];
|
|
412
|
-
// Group by `from` (null → 'system').
|
|
413
90
|
const groups = new Map();
|
|
414
|
-
for (const
|
|
415
|
-
const
|
|
416
|
-
if (!groups.has(
|
|
417
|
-
groups.set(
|
|
418
|
-
groups.get(
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const sender = entry.from ?? 'system';
|
|
93
|
+
if (!groups.has(sender))
|
|
94
|
+
groups.set(sender, []);
|
|
95
|
+
groups.get(sender).push(entry);
|
|
419
96
|
}
|
|
420
|
-
// Human words stay outside the card, so a batch mixing both keeps the card
|
|
421
|
-
// where the first node sender fell rather than reordering the digest.
|
|
422
97
|
const deliveries = [];
|
|
423
98
|
const sections = [];
|
|
424
99
|
let cardSlot = -1;
|
|
425
100
|
for (const [sender, items] of groups) {
|
|
426
|
-
// A human typing directly into a node's box is a CONVERSATION TURN, not a
|
|
427
|
-
// notification the node is being woken to triage. Deliver those words
|
|
428
|
-
// verbatim as the woken turn's user message — no card, no `<from>` section.
|
|
429
|
-
// This makes the dormant path identical to the live path (type "hi" → the
|
|
430
|
-
// node just reads "hi"). Every other sender is digest content.
|
|
431
101
|
if (sender === 'human') {
|
|
432
|
-
for (const
|
|
433
|
-
const body = inlineBody(
|
|
434
|
-
deliveries.push({ kind: 'human', text: body === '' ?
|
|
102
|
+
for (const entry of items) {
|
|
103
|
+
const body = inlineBody(entry);
|
|
104
|
+
deliveries.push({ kind: 'human', text: body === '' ? entry.label : body, entries: [entry] });
|
|
435
105
|
}
|
|
436
106
|
continue;
|
|
437
107
|
}
|
|
@@ -442,12 +112,10 @@ export function coalesce(entries) {
|
|
|
442
112
|
sections.push({ id: sender, entries: items.map(cardEntry) });
|
|
443
113
|
}
|
|
444
114
|
if (cardSlot >= 0) {
|
|
445
|
-
// Card sections group by sender, so its entry list comes from the input
|
|
446
|
-
// array instead, keeping physical inbox order.
|
|
447
115
|
deliveries[cardSlot] = {
|
|
448
116
|
kind: 'card',
|
|
449
117
|
text: formatInboxCard(sections),
|
|
450
|
-
entries: entries.filter((
|
|
118
|
+
entries: entries.filter((entry) => (entry.from ?? 'system') !== 'human'),
|
|
451
119
|
};
|
|
452
120
|
}
|
|
453
121
|
return deliveries;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type InboxDisposition, type InboxKind, type InboxTier } from './inbox.js';
|
|
2
|
+
export type { InboxDisposition, InboxKind, InboxTier } from './inbox.js';
|
|
3
|
+
export interface NodeMailInput {
|
|
4
|
+
kind: InboxKind;
|
|
5
|
+
label: string;
|
|
6
|
+
senderNodeId?: string | null;
|
|
7
|
+
senderName?: string | null;
|
|
8
|
+
bodyRef?: string | null;
|
|
9
|
+
bodyJson?: unknown;
|
|
10
|
+
disposition?: InboxDisposition | null;
|
|
11
|
+
urgency: InboxTier;
|
|
12
|
+
wake: 0 | 1;
|
|
13
|
+
operationId?: string;
|
|
14
|
+
/** Optional caller-owned obligation identity, used by cron settlement replay. */
|
|
15
|
+
idempotencyKey?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ExternalActionAdapter {
|
|
18
|
+
adapter: 'subprocess' | 'cron_spawn' | 'cron_human';
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface ExternalActionInput {
|
|
22
|
+
destinationId: string;
|
|
23
|
+
adapter: ExternalActionAdapter;
|
|
24
|
+
bodyJson: unknown;
|
|
25
|
+
idempotencyKey: string;
|
|
26
|
+
label?: string;
|
|
27
|
+
kind?: InboxKind;
|
|
28
|
+
}
|
|
29
|
+
export interface EnqueuedNodeMail {
|
|
30
|
+
messageId: string;
|
|
31
|
+
deliveryId: string;
|
|
32
|
+
urgency: InboxTier;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
}
|
|
35
|
+
export interface EnqueuedExternalAction {
|
|
36
|
+
messageId: string;
|
|
37
|
+
deliveryId: string;
|
|
38
|
+
}
|
|
39
|
+
type Subscriber = {
|
|
40
|
+
node_id: string;
|
|
41
|
+
active: boolean;
|
|
42
|
+
};
|
|
43
|
+
/** Insert one immutable message and one node-inbox obligation into the caller's write transaction. */
|
|
44
|
+
export declare function enqueueNodeMail(destinationNodeId: string, input: NodeMailInput): EnqueuedNodeMail;
|
|
45
|
+
/** Fan out one immutable report message to the supplied subscriber snapshot. */
|
|
46
|
+
export declare function enqueueSubscriberMail(subscribers: readonly Subscriber[], input: Omit<NodeMailInput, 'wake'>): Array<EnqueuedNodeMail & {
|
|
47
|
+
destinationNodeId: string;
|
|
48
|
+
}>;
|
|
49
|
+
/** Insert one frozen external-action obligation. A duplicate idempotency key returns its original identity. */
|
|
50
|
+
export declare function enqueueExternalAction(input: ExternalActionInput): EnqueuedExternalAction;
|
|
51
|
+
/** Retract an obligation without fabricating a terminal receipt. */
|
|
52
|
+
export declare function cancelDelivery(deliveryId: string, now?: number): boolean;
|
|
53
|
+
export declare function cancelPendingNodeMail(nodeId: string, select?: {
|
|
54
|
+
senderNodeId?: string | null;
|
|
55
|
+
kind?: InboxKind;
|
|
56
|
+
}): string[];
|
|
57
|
+
/** Enqueue the one notice only if the same live controller wait is still dead. */
|
|
58
|
+
export declare function enqueueControllerDeathNotice(nodeId: string, controllerId: string): EnqueuedNodeMail | null;
|