@north-light/crouter 0.3.233 → 0.3.235
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.js +16 -15
- package/dist/api/dto/nodes.d.ts +11 -0
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +14 -17
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/frontmatter-rules/index.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +10 -11
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +2 -2
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +7 -7
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +8 -8
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/statusline.ts +6 -6
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/sysprompt-window.ts +3 -3
- package/dist/builtin-pi-packages/pi-crtr-extensions/lib/subscription-state.ts +1 -1
- package/dist/clients/attach/chrome/ticket-panel.js +15 -2
- package/dist/clients/attach/overlays/graph.js +0 -3
- package/dist/clients/attach/overlays/mcp.js +1 -2
- package/dist/clients/attach/render/chat-view.js +0 -12
- package/dist/clients/attach/render/crtr-output.js +0 -2
- package/dist/clients/attach/render/tool-calls.js +0 -6
- package/dist/clients/attach/slash/dispatch.js +8 -11
- package/dist/clients/attach/viewer.js +535 -537
- package/dist/clients/conversation/projection.js +0 -2
- package/dist/clients/inbox/controller.js +22 -3
- package/dist/clients/inbox/review/companion-pane.js +0 -4
- package/dist/clients/inbox/review-adapter.js +0 -7
- package/dist/clients/inbox/tui/slots.d.ts +3 -3
- package/dist/clients/inbox/tui/types.d.ts +2 -2
- package/dist/commands/api-client.js +0 -8
- package/dist/commands/attention.js +1 -9
- package/dist/commands/canvas-browse.js +2 -1
- package/dist/commands/canvas-config.js +0 -10
- package/dist/commands/canvas-history.js +2 -1
- package/dist/commands/cron.js +10 -23
- package/dist/commands/dashboard.js +0 -2
- package/dist/commands/human/feedback.js +2 -1
- package/dist/commands/human/prompts.js +2 -5
- package/dist/commands/human/queue.js +2 -7
- package/dist/commands/human/request.js +0 -14
- package/dist/commands/human/review.js +2 -1
- package/dist/commands/human.js +1 -1
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +4 -4
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.d.ts +1 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +96 -0
- package/dist/commands/memory/delete.js +1 -1
- package/dist/commands/memory/edit.js +6 -3
- package/dist/commands/memory/find.js +2 -2
- package/dist/commands/memory/lint.js +2 -1
- package/dist/commands/memory/list.d.ts +4 -0
- package/dist/commands/memory/list.js +20 -14
- package/dist/commands/memory/move.js +1 -1
- package/dist/commands/memory/read.d.ts +2 -7
- package/dist/commands/memory/read.js +5 -16
- package/dist/commands/memory/shared.d.ts +1 -0
- package/dist/commands/memory/shared.js +17 -8
- package/dist/commands/memory/write.js +8 -4
- package/dist/commands/node/bash.js +2 -1
- package/dist/commands/node/create.js +2 -1
- package/dist/commands/node/inspect.js +11 -10
- package/dist/commands/node/lifecycle.js +5 -13
- package/dist/commands/node/message.js +11 -6
- package/dist/commands/node/subscription.js +7 -2
- package/dist/commands/node/wait.js +9 -4
- package/dist/commands/node-context.js +2 -1
- package/dist/commands/node-lifecycle-revive.js +0 -2
- package/dist/commands/node-worktree.js +2 -1
- package/dist/commands/pkg/browse/actions.d.ts +1 -1
- package/dist/commands/pkg/browse/actions.js +4 -4
- package/dist/commands/pkg/browse/catalog.d.ts +1 -1
- package/dist/commands/pkg/browse/catalog.js +15 -15
- package/dist/commands/pkg/browse/command-view.d.ts +1 -1
- package/dist/commands/pkg/browse/command-view.js +3 -3
- package/dist/commands/pkg/browse/detail-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/detail-panel.js +8 -8
- package/dist/commands/pkg/browse/doc-view.d.ts +1 -1
- package/dist/commands/pkg/browse/doc-view.js +3 -3
- package/dist/commands/pkg/browse/list-panel.d.ts +1 -1
- package/dist/commands/pkg/browse/list-panel.js +3 -3
- package/dist/commands/pkg/browse/model.d.ts +3 -3
- package/dist/commands/pkg/browse/shell.d.ts +2 -2
- package/dist/commands/pkg/browse/shell.js +13 -13
- package/dist/commands/pkg/plugin-manage.js +3 -2
- package/dist/commands/pkg/shared.js +0 -2
- package/dist/commands/pkg.js +1 -0
- package/dist/commands/profile/delete.js +2 -1
- package/dist/commands/profile/rename.js +1 -1
- package/dist/commands/push.js +2 -3
- package/dist/commands/revive.js +0 -2
- package/dist/commands/surface/node/placement.js +2 -1
- package/dist/commands/surface-edit.js +2 -1
- package/dist/commands/sys/config.js +1 -4
- package/dist/commands/sys/daemon.js +0 -10
- package/dist/commands/sys/doctor.js +3 -2
- package/dist/commands/sys/panels/broker-limits-panel.d.ts +2 -2
- package/dist/commands/sys/panels/broker-limits-panel.js +4 -4
- package/dist/commands/sys/panels/dependencies-panel.d.ts +2 -2
- package/dist/commands/sys/panels/dependencies-panel.js +2 -2
- package/dist/commands/sys/panels/keybindings-panel.d.ts +1 -1
- package/dist/commands/sys/panels/keybindings-panel.js +5 -5
- package/dist/commands/sys/panels/models-panel.d.ts +4 -4
- package/dist/commands/sys/panels/models-panel.js +11 -10
- package/dist/commands/sys/panels/plugins-panel.d.ts +2 -2
- package/dist/commands/sys/panels/plugins-panel.js +2 -2
- package/dist/commands/sys/panels/prefs-panel.d.ts +2 -2
- package/dist/commands/sys/panels/prefs-panel.js +4 -4
- package/dist/commands/sys/panels/profiles-panel.d.ts +1 -1
- package/dist/commands/sys/panels/profiles-panel.js +14 -13
- package/dist/commands/sys/panels/provider-panel.d.ts +3 -3
- package/dist/commands/sys/panels/provider-panel.js +8 -8
- package/dist/commands/sys/settings-shell.d.ts +3 -3
- package/dist/commands/sys/settings-shell.js +15 -15
- package/dist/commands/sys/setup-settings-runner.d.ts +3 -3
- package/dist/commands/sys/setup-settings-runner.js +5 -5
- package/dist/commands/sys/setup-wizard.d.ts +4 -4
- package/dist/commands/sys/setup-wizard.js +8 -8
- package/dist/commands/sys/support/prepare.js +4 -4
- package/dist/commands/sys/support/submit.js +2 -2
- package/dist/commands/sys/sync-deps.js +0 -2
- package/dist/commands/sys/sync-project-guidance.js +2 -1
- package/dist/commands/sys/sysprompt.js +2 -1
- package/dist/commands/sys.js +1 -0
- package/dist/core/__tests__/boot.test.js +0 -8
- package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +23 -1
- package/dist/core/__tests__/canvas-db-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/canvas-db-boundary.test.js +46 -0
- package/dist/core/__tests__/canvas.test.js +1 -1
- package/dist/core/__tests__/child-death-wake.test.js +0 -2
- package/dist/core/__tests__/cli-help-contract.test.d.ts +1 -0
- package/dist/core/__tests__/cli-help-contract.test.js +150 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.d.ts +1 -0
- package/dist/core/__tests__/cron-armed-context-failure.test.js +145 -0
- package/dist/core/__tests__/daemon-wedge.test.js +0 -4
- package/dist/core/__tests__/dead-node-policy-table.test.js +0 -4
- package/dist/core/__tests__/fixtures/fake-engine.js +4 -14
- package/dist/core/__tests__/fixtures/fake-pi-host.js +5 -5
- package/dist/core/__tests__/focuses.test.js +0 -6
- package/dist/core/__tests__/fs-utils.test.d.ts +1 -0
- package/dist/core/__tests__/fs-utils.test.js +50 -0
- package/dist/core/__tests__/helpers/harness.js +1 -1
- package/dist/core/__tests__/inline-memory-refs.test.js +0 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +0 -2
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +3 -16
- package/dist/core/__tests__/integration/command-plugins.test.js +21 -24
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +0 -6
- package/dist/core/__tests__/integration/flagship-lifecycle.test.js +0 -26
- package/dist/core/__tests__/integration/live-mutation-verbs.test.js +0 -4
- package/dist/core/__tests__/integration/live-mutation.test.js +1 -5
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +1 -5
- package/dist/core/__tests__/integration/revive.test.js +0 -12
- package/dist/core/__tests__/integration/subscription-delivery.test.js +0 -6
- package/dist/core/__tests__/integration/tmux-surface.test.js +24 -8
- package/dist/core/__tests__/integration/worktree-reap.test.js +0 -6
- package/dist/core/__tests__/lifecycle.test.js +0 -18
- package/dist/core/__tests__/memory-resolver-precedence.test.js +1 -1
- package/dist/core/__tests__/migration.test.js +2 -2
- package/dist/core/__tests__/on-read-dedup-resume.test.js +3 -3
- package/dist/core/__tests__/pid-identity-match.test.js +1 -1
- package/dist/core/__tests__/plugin-kinds.test.js +1 -1
- package/dist/core/__tests__/plugin-page-components.test.js +1 -1
- package/dist/core/__tests__/preview-registry-sync.test.js +42 -1
- package/dist/core/__tests__/respawn-throttle.test.js +0 -4
- package/dist/core/__tests__/revive-all.test.js +5 -5
- package/dist/core/__tests__/revive-parked-fresh.test.js +62 -11
- package/dist/core/__tests__/seam/broker-attach-multiclient.test.js +0 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +0 -8
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +0 -2
- package/dist/core/__tests__/tmux-driver-boundary.test.d.ts +1 -0
- package/dist/core/__tests__/tmux-driver-boundary.test.js +50 -0
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +11 -6
- package/dist/core/activity-signal.d.ts +7 -0
- package/dist/core/activity-signal.js +38 -0
- package/dist/core/auto-update.js +2 -1
- package/dist/core/bootstrap.js +2 -1
- package/dist/core/canvas/__tests__/remote-canvas-source.test.js +1 -1
- package/dist/core/canvas/__tests__/remote-transport.test.js +1 -1
- package/dist/core/canvas/__tests__/render-remote.test.js +1 -1
- package/dist/core/canvas/browse/app.js +3 -2
- package/dist/core/canvas/browse/model.d.ts +1 -1
- package/dist/core/canvas/browse/model.js +0 -4
- package/dist/core/canvas/canvas.d.ts +22 -0
- package/dist/core/canvas/canvas.js +61 -19
- package/dist/core/canvas/crons.js +0 -6
- package/dist/core/canvas/db.d.ts +14 -20
- package/dist/core/canvas/db.js +30 -1332
- package/dist/core/canvas/focuses.js +0 -4
- package/dist/core/canvas/history.js +2 -1
- package/dist/core/canvas/meta-file.js +18 -27
- package/dist/core/canvas/migrations.d.ts +20 -0
- package/dist/core/canvas/migrations.js +1339 -0
- package/dist/core/canvas/nav-model.js +1 -11
- package/dist/core/canvas/nav-render.js +0 -8
- package/dist/core/canvas/remote-canvas-source.d.ts +8 -0
- package/dist/core/canvas/remote-canvas-source.js +9 -3
- package/dist/core/canvas/render-source.js +31 -13
- package/dist/core/command-manifests/manifest.js +0 -10
- package/dist/core/command-manifests/registry.d.ts +2 -0
- package/dist/core/command-manifests/schema.js +0 -4
- package/dist/core/command-plugins/compose.js +4 -2
- package/dist/core/command-plugins/discovery.d.ts +1 -0
- package/dist/core/command-plugins/discovery.js +1 -1
- package/dist/core/command-plugins/transport/http-invoke.js +0 -14
- package/dist/core/command.js +2 -6
- package/dist/core/config.js +2 -1
- package/dist/core/fault-classifier.js +8 -0
- package/dist/core/feed/inbox.d.ts +10 -0
- package/dist/core/feed/inbox.js +18 -12
- package/dist/core/fs-utils.d.ts +9 -2
- package/dist/core/fs-utils.js +7 -15
- package/dist/core/help.js +0 -8
- package/dist/core/host-exports/export.d.ts +2 -2
- package/dist/core/host-exports/export.js +9 -12
- package/dist/core/human/answer.d.ts +2 -2
- package/dist/core/human/convention.d.ts +2 -5
- package/dist/core/human/convention.js +3 -13
- package/dist/core/human/page-schema.d.ts +2 -2
- package/dist/core/human/page-schema.js +2 -2
- package/dist/core/human/root.js +6 -23
- package/dist/core/human/scan.js +24 -7
- package/dist/core/human/tickets.d.ts +4 -1
- package/dist/core/human/tickets.js +20 -6
- package/dist/core/io.js +0 -12
- package/dist/core/memory/identity.js +0 -4
- package/dist/core/memory/inline-ref-inventory.js +3 -2
- package/dist/core/memory/lint.js +3 -6
- package/dist/core/memory-resolver.d.ts +5 -0
- package/dist/core/memory-resolver.js +14 -12
- package/dist/core/pagination.d.ts +2 -0
- package/dist/core/pagination.js +2 -3
- package/dist/core/preview-registry.d.ts +14 -0
- package/dist/core/preview-registry.js +2 -4
- package/dist/core/preview-result-path.js +2 -1
- package/dist/core/profiles/manifest.d.ts +37 -5
- package/dist/core/profiles/manifest.js +44 -24
- package/dist/core/profiles/select.js +0 -4
- package/dist/core/review/signal.js +4 -23
- package/dist/core/review/ticket-filter.d.ts +3 -3
- package/dist/core/review/ticket-filter.js +4 -9
- package/dist/core/runtime/__tests__/engine-route.test.js +1 -1
- package/dist/core/runtime/__tests__/spawn-env.test.js +0 -8
- package/dist/core/runtime/bearings-render.d.ts +56 -0
- package/dist/core/runtime/bearings-render.js +241 -0
- package/dist/core/runtime/bearings.d.ts +2 -17
- package/dist/core/runtime/bearings.js +12 -198
- package/dist/core/runtime/broker/auth-reload.d.ts +39 -0
- package/dist/core/runtime/broker/auth-reload.js +149 -0
- package/dist/core/runtime/broker/engine-drive.d.ts +26 -0
- package/dist/core/runtime/broker/engine-drive.js +257 -0
- package/dist/core/runtime/broker/engine-routing.d.ts +143 -0
- package/dist/core/runtime/broker/engine-routing.js +211 -0
- package/dist/core/runtime/broker/event-projection.js +3 -2
- package/dist/core/runtime/broker/fault-retry.js +11 -4
- package/dist/core/runtime/broker/frame-client.d.ts +38 -0
- package/dist/core/runtime/broker/frame-client.js +129 -0
- package/dist/core/runtime/broker/frame-dispatch.d.ts +12 -189
- package/dist/core/runtime/broker/frame-dispatch.js +89 -1476
- package/dist/core/runtime/broker/frame-engine-control.d.ts +20 -0
- package/dist/core/runtime/broker/frame-engine-control.js +231 -0
- package/dist/core/runtime/broker/frame-memory-refs.d.ts +19 -0
- package/dist/core/runtime/broker/frame-memory-refs.js +41 -0
- package/dist/core/runtime/broker/frame-model-query.d.ts +13 -0
- package/dist/core/runtime/broker/frame-model-query.js +69 -0
- package/dist/core/runtime/broker/frame-read.d.ts +19 -0
- package/dist/core/runtime/broker/frame-read.js +116 -0
- package/dist/core/runtime/broker/frame-replies.d.ts +24 -0
- package/dist/core/runtime/broker/frame-replies.js +64 -0
- package/dist/core/runtime/broker/frame-session.d.ts +34 -0
- package/dist/core/runtime/broker/frame-session.js +203 -0
- package/dist/core/runtime/broker/rebind.js +50 -0
- package/dist/core/runtime/broker/turn-ignition.d.ts +42 -0
- package/dist/core/runtime/broker/turn-ignition.js +74 -0
- package/dist/core/runtime/broker-extension-render.js +9 -85
- package/dist/core/runtime/broker-protocol.js +0 -4
- package/dist/core/runtime/broker-sdk.js +2 -1
- package/dist/core/runtime/broker.d.ts +1 -1
- package/dist/core/runtime/broker.js +5 -23
- package/dist/core/runtime/fault.js +3 -2
- package/dist/core/runtime/headless-pi.js +3 -2
- package/dist/core/runtime/host.js +2 -3
- package/dist/core/runtime/kickoff.js +0 -4
- package/dist/core/runtime/launch-target.js +2 -1
- package/dist/core/runtime/launch.d.ts +2 -2
- package/dist/core/runtime/launch.js +20 -10
- package/dist/core/runtime/lifecycle.js +17 -26
- package/dist/core/runtime/managed-provider-cooling.d.ts +1 -1
- package/dist/core/runtime/naming.js +0 -2
- package/dist/core/runtime/nodes.js +2 -1
- package/dist/core/runtime/persona.js +0 -6
- package/dist/core/runtime/placement-tmux.js +2 -5
- package/dist/core/runtime/placement.js +4 -11
- package/dist/core/runtime/recap.js +4 -3
- package/dist/core/runtime/reopen.js +4 -7
- package/dist/core/runtime/reset.js +0 -4
- package/dist/core/runtime/resume-root.js +0 -2
- package/dist/core/runtime/revive.js +17 -13
- package/dist/core/runtime/session-list-cache.js +2 -2
- package/dist/core/runtime/shell-expansion.js +0 -2
- package/dist/core/runtime/spawn.js +0 -2
- package/dist/core/runtime/stop-guard.js +28 -16
- package/dist/core/runtime/stream-watchdog.d.ts +0 -1
- package/dist/core/runtime/stream-watchdog.js +13 -18
- package/dist/core/runtime/tmux-bindings.js +0 -2
- package/dist/core/runtime/tmux-driver.d.ts +12 -0
- package/dist/core/runtime/tmux-driver.js +18 -13
- package/dist/core/runtime/warm-pool.js +0 -4
- package/dist/core/scope.js +4 -3
- package/dist/core/spawn.js +2 -3
- package/dist/core/subscription-state.js +10 -17
- package/dist/core/substrate/__tests__/surface-match-pre-command.test.js +3 -3
- package/dist/core/substrate/frontmatter-validation.d.ts +1 -0
- package/dist/core/substrate/frontmatter-validation.js +1 -1
- package/dist/core/substrate/render.js +0 -12
- package/dist/core/substrate/schema.js +0 -12
- package/dist/core/substrate/surface-match.js +0 -2
- package/dist/core/termrender/display.js +2 -1
- package/dist/core/tui/page-host.d.ts +3 -3
- package/dist/core/tui/page-host.js +4 -4
- package/dist/core/tui/panel.js +3 -3
- package/dist/core/wake.js +0 -12
- package/dist/core/worktree.js +0 -2
- package/dist/daemon/__tests__/reconciler-signature.test.d.ts +1 -0
- package/dist/daemon/__tests__/reconciler-signature.test.js +36 -0
- package/dist/daemon/api/__tests__/error-seam.test.js +27 -0
- package/dist/daemon/api/__tests__/seam/api-server.test.js +2 -16
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +3 -11
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +0 -6
- package/dist/daemon/api/handlers/attach.js +2 -1
- package/dist/daemon/api/handlers/broker-ops.js +3 -6
- package/dist/daemon/api/handlers/canvas.js +12 -18
- package/dist/daemon/api/handlers/feedback-comments.js +0 -8
- package/dist/daemon/api/handlers/health.js +3 -2
- package/dist/daemon/api/handlers/human-requests.js +0 -10
- package/dist/daemon/api/handlers/human.js +1 -5
- package/dist/daemon/api/handlers/inbox.js +0 -18
- package/dist/daemon/api/handlers/memory.js +1 -1
- package/dist/daemon/api/handlers/messages.js +16 -20
- package/dist/daemon/api/handlers/nodes.js +23 -22
- package/dist/daemon/api/handlers/reports.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -6
- package/dist/daemon/api/handlers/worktree.js +6 -22
- package/dist/daemon/api/map.d.ts +4 -2
- package/dist/daemon/api/map.js +22 -8
- package/dist/daemon/api/router.js +0 -4
- package/dist/daemon/api/server.js +2 -5
- package/dist/daemon/boot-migrations.d.ts +14 -0
- package/dist/daemon/boot-migrations.js +31 -0
- package/dist/daemon/cron/armed-context.d.ts +21 -0
- package/dist/daemon/cron/armed-context.js +100 -0
- package/dist/daemon/cron/capture.d.ts +20 -0
- package/dist/daemon/cron/capture.js +45 -0
- package/dist/daemon/cron/disposition.d.ts +19 -0
- package/dist/daemon/cron/disposition.js +52 -0
- package/dist/daemon/cron/escalation.d.ts +12 -0
- package/dist/daemon/cron/escalation.js +124 -0
- package/dist/daemon/cron/held.d.ts +4 -0
- package/dist/daemon/cron/held.js +20 -0
- package/dist/daemon/cron/lease-recovery.d.ts +3 -0
- package/dist/daemon/cron/lease-recovery.js +119 -0
- package/dist/daemon/cron/live-runs.d.ts +11 -0
- package/dist/daemon/cron/live-runs.js +23 -0
- package/dist/daemon/cron/passes.d.ts +11 -0
- package/dist/daemon/cron/passes.js +78 -0
- package/dist/daemon/cron/settle.d.ts +28 -0
- package/dist/daemon/cron/settle.js +37 -0
- package/dist/daemon/cron/sinks.d.ts +2 -0
- package/dist/daemon/cron/sinks.js +100 -0
- package/dist/daemon/cron-run.d.ts +5 -41
- package/dist/daemon/cron-run.js +193 -882
- package/dist/daemon/crtrd-cli.js +2 -1
- package/dist/daemon/crtrd.js +22 -22
- package/dist/daemon/fleet.js +0 -4
- package/dist/daemon/human/deliver-action.js +2 -1
- package/dist/daemon/human/sweep.js +15 -4
- package/dist/daemon/manage.d.ts +2 -2
- package/dist/daemon/manage.js +4 -13
- package/dist/daemon/pidfile.js +2 -2
- package/dist/daemon/reconcilers/broker-supervision.js +27 -30
- package/dist/daemon/reconcilers/dormant-inbox.d.ts +1 -1
- package/dist/daemon/reconcilers/dormant-inbox.js +2 -1
- package/dist/daemon/reconcilers/live-obligation.js +2 -2
- package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +2 -1
- package/dist/daemon/review/companion.js +2 -2
- package/dist/daemon/review/sweep.js +8 -3
- package/dist/migrations/001-surfaces-frontmatter.js +0 -6
- package/dist/migrations/corpus.js +2 -5
- package/dist/migrations/registry.js +15 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +0 -4
- package/dist/pi-extensions/broker-local.js +2 -1
- package/dist/pi-extensions/canvas-bash-valve.js +7 -20
- package/dist/pi-extensions/canvas-context-intro.js +2 -7
- package/dist/pi-extensions/canvas-doc-substrate.js +2 -3
- package/dist/pi-extensions/canvas-goal-capture.js +2 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +5 -12
- package/dist/pi-extensions/canvas-passive-context.js +2 -5
- package/dist/pi-extensions/canvas-preview-result.js +2 -1
- package/dist/pi-extensions/canvas-prompt-scrub.js +2 -1
- package/dist/pi-extensions/canvas-recap.js +3 -16
- package/dist/pi-extensions/canvas-review-boundary.js +2 -5
- package/dist/pi-extensions/canvas-stophook.js +2 -26
- package/dist/pi-extensions/canvas-structured-output.js +2 -1
- package/dist/pi-extensions/canvas-tool-guide.js +2 -1
- package/dist/shared/__tests__/env-boundary.test.d.ts +1 -0
- package/dist/shared/__tests__/env-boundary.test.js +93 -0
- package/dist/shared/env.d.ts +68 -0
- package/dist/shared/env.js +171 -0
- package/package.json +3 -1
- package/runtime.lock.json +2 -2
- package/dist/core/canvas/render.d.ts +0 -47
- package/dist/core/canvas/render.js +0 -245
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
3
|
+
import { CRON_DEATH_POLL_MS, CRON_KILL_GRACE_MS, EMPTY_STDOUT_SHA256 } from './capture.js';
|
|
4
|
+
import { cronDaemonInstanceId } from './live-runs.js';
|
|
5
|
+
import { crashedOneShotSummary, escalateFailure } from './escalation.js';
|
|
6
|
+
import { settleRun } from './settle.js';
|
|
7
|
+
import { killLeasedCronRun, runningCrons, setCronState, verifyLeasedCronRun, } from '../../core/canvas/crons.js';
|
|
8
|
+
import { emitEvent } from '../../core/events/emit.js';
|
|
9
|
+
/** Recover leases from prior daemon instances. Verify launch identity, not pid liveness: a reboot can recycle the pid, and killing its new owner would signal a stranger. */
|
|
10
|
+
export function recoverStaleCronLeases(now, options = {}) {
|
|
11
|
+
for (const c of runningCrons()) {
|
|
12
|
+
if (c.run_lease_owner === cronDaemonInstanceId)
|
|
13
|
+
continue;
|
|
14
|
+
if (!verifyLeasedCronRun(c)) {
|
|
15
|
+
settleCrashedRun(c, now, options);
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const startedAtMs = c.run_started_at != null ? new Date(c.run_started_at).getTime() : now;
|
|
19
|
+
if (now - startedAtMs < c.run_timeout_s * 1000)
|
|
20
|
+
continue;
|
|
21
|
+
if (!killLeasedCronRun(c)) {
|
|
22
|
+
settleCrashedRun(c, now, options);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const ctx = {
|
|
26
|
+
runId: randomUUID(),
|
|
27
|
+
startedAtIso: c.run_started_at ?? new Date(now).toISOString(),
|
|
28
|
+
exitCode: -1,
|
|
29
|
+
timedOut: true,
|
|
30
|
+
runTimeoutS: c.run_timeout_s,
|
|
31
|
+
processErrorMessage: null,
|
|
32
|
+
stdoutHead: '',
|
|
33
|
+
stdoutSha256: EMPTY_STDOUT_SHA256,
|
|
34
|
+
stderrHead: `run timed out after ${c.run_timeout_s}s (recovered stale lease from a prior daemon instance)`,
|
|
35
|
+
};
|
|
36
|
+
const settlement = (async () => {
|
|
37
|
+
await awaitLeasedRunDeath(c);
|
|
38
|
+
await settleRun(c, {
|
|
39
|
+
outOfBand: false,
|
|
40
|
+
outcome: { kind: 'disposed', ctx },
|
|
41
|
+
record: {
|
|
42
|
+
runId: ctx.runId,
|
|
43
|
+
startedAtIso: ctx.startedAtIso,
|
|
44
|
+
finishedAtMs: now,
|
|
45
|
+
durationMs: now - startedAtMs,
|
|
46
|
+
exitCode: -1,
|
|
47
|
+
stdoutHead: null,
|
|
48
|
+
stderrHead: ctx.stderrHead,
|
|
49
|
+
},
|
|
50
|
+
lease: { kind: 'clear' },
|
|
51
|
+
});
|
|
52
|
+
})();
|
|
53
|
+
options.register?.(settlement);
|
|
54
|
+
void settlement.catch((err) => {
|
|
55
|
+
emitEvent({ level: 'error', event: 'cron.stale_lease.settle_failed', error: err, fields: { cron_id: c.cron_id } });
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Wait after SIGTERM: a signal-trapping command can still produce side effects.
|
|
60
|
+
async function awaitLeasedRunDeath(c) {
|
|
61
|
+
const deadline = Date.now() + CRON_KILL_GRACE_MS;
|
|
62
|
+
while (Date.now() < deadline) {
|
|
63
|
+
await delay(CRON_DEATH_POLL_MS);
|
|
64
|
+
if (!verifyLeasedCronRun(c))
|
|
65
|
+
return; // gone
|
|
66
|
+
}
|
|
67
|
+
killLeasedCronRun(c, 'SIGKILL');
|
|
68
|
+
}
|
|
69
|
+
/** Record an unobserved crashed run. Pause one-shots rather than re-fire them: their side effects may already have landed. */
|
|
70
|
+
function settleCrashedRun(c, now, options) {
|
|
71
|
+
const oneShot = c.recur == null;
|
|
72
|
+
const startedAtMs = c.run_started_at != null ? new Date(c.run_started_at).getTime() : now;
|
|
73
|
+
const why = 'the daemon life that owned this run ended before it settled — the process is gone and its outcome was never observed';
|
|
74
|
+
const ctx = {
|
|
75
|
+
runId: randomUUID(),
|
|
76
|
+
startedAtIso: c.run_started_at ?? new Date(now).toISOString(),
|
|
77
|
+
exitCode: null,
|
|
78
|
+
timedOut: false,
|
|
79
|
+
runTimeoutS: c.run_timeout_s,
|
|
80
|
+
processErrorMessage: why,
|
|
81
|
+
stdoutHead: '',
|
|
82
|
+
stdoutSha256: EMPTY_STDOUT_SHA256,
|
|
83
|
+
stderrHead: `run outcome unobserved: ${why}`,
|
|
84
|
+
};
|
|
85
|
+
const settlement = (async () => {
|
|
86
|
+
let delivered = `crashed: ${why}${oneShot ? '' : ' — the next occurrence is unaffected'}`;
|
|
87
|
+
if (oneShot) {
|
|
88
|
+
// Pause before escalation so a throw cannot re-fire the past-due one-shot.
|
|
89
|
+
setCronState(c.cron_id, 'paused');
|
|
90
|
+
delivered =
|
|
91
|
+
c.on_output === 'silent'
|
|
92
|
+
? `crashed: ${why} — one-shot paused, not re-fired (silent: not escalated)`
|
|
93
|
+
: `crashed one-shot: ${await escalateFailure(c, ctx, crashedOneShotSummary(why))}`;
|
|
94
|
+
}
|
|
95
|
+
await settleRun(c, {
|
|
96
|
+
outOfBand: false,
|
|
97
|
+
outcome: { kind: 'stated', delivered, paused: oneShot },
|
|
98
|
+
record: {
|
|
99
|
+
runId: ctx.runId,
|
|
100
|
+
startedAtIso: ctx.startedAtIso,
|
|
101
|
+
finishedAtMs: now,
|
|
102
|
+
durationMs: Math.max(0, now - startedAtMs),
|
|
103
|
+
exitCode: null,
|
|
104
|
+
stdoutHead: null,
|
|
105
|
+
stderrHead: ctx.stderrHead,
|
|
106
|
+
},
|
|
107
|
+
lease: 'release',
|
|
108
|
+
});
|
|
109
|
+
emitEvent({
|
|
110
|
+
level: 'warn',
|
|
111
|
+
event: 'cron.run.unobserved',
|
|
112
|
+
fields: { cron_id: c.cron_id, name: c.name, one_shot: oneShot },
|
|
113
|
+
});
|
|
114
|
+
})();
|
|
115
|
+
options.register?.(settlement);
|
|
116
|
+
void settlement.catch((err) => {
|
|
117
|
+
emitEvent({ level: 'error', event: 'cron.crashed_run.settle_failed', error: err, fields: { cron_id: c.cron_id } });
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const cronDaemonInstanceId: `${string}-${string}-${string}-${string}-${string}`;
|
|
2
|
+
export interface LiveRun {
|
|
3
|
+
runId: string;
|
|
4
|
+
replaced: boolean;
|
|
5
|
+
selfCanceled: boolean;
|
|
6
|
+
kill(): void;
|
|
7
|
+
}
|
|
8
|
+
export declare function liveRunFor(cronId: string): LiveRun | undefined;
|
|
9
|
+
export declare function registerLiveRun(cronId: string, run: LiveRun): void;
|
|
10
|
+
export declare function clearLiveRun(cronId: string, runId: string): void;
|
|
11
|
+
export declare function markSelfCanceledCronRun(cronId: string, runId: string): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
export const cronDaemonInstanceId = randomUUID();
|
|
3
|
+
const liveRuns = new Map();
|
|
4
|
+
export function liveRunFor(cronId) {
|
|
5
|
+
return liveRuns.get(cronId);
|
|
6
|
+
}
|
|
7
|
+
export function registerLiveRun(cronId, run) {
|
|
8
|
+
liveRuns.set(cronId, run);
|
|
9
|
+
}
|
|
10
|
+
// An earlier close handler must not evict a later run.
|
|
11
|
+
export function clearLiveRun(cronId, runId) {
|
|
12
|
+
const live = liveRuns.get(cronId);
|
|
13
|
+
if (live !== undefined && live.runId === runId)
|
|
14
|
+
liveRuns.delete(cronId);
|
|
15
|
+
}
|
|
16
|
+
// Only that exact process may finish after its row is removed.
|
|
17
|
+
export function markSelfCanceledCronRun(cronId, runId) {
|
|
18
|
+
const live = liveRuns.get(cronId);
|
|
19
|
+
if (live === undefined || live.runId !== runId)
|
|
20
|
+
return false;
|
|
21
|
+
live.selfCanceled = true;
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Cron } from '../../core/canvas/crons.js';
|
|
2
|
+
export interface RunDueCronOptions {
|
|
3
|
+
/** Registers settlement work for graceful-teardown draining. */
|
|
4
|
+
register?: (work: Promise<void>) => void;
|
|
5
|
+
/** Node-launching runs need capacity; absent means all runs are admitted. */
|
|
6
|
+
hasBrokerCapacity?: () => boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function cronLaunchesNode(c: Cron): boolean;
|
|
9
|
+
export declare function expireDueCrons(nowIso: string): void;
|
|
10
|
+
export declare function applyOverlapPolicies(now: number, nowIso: string): void;
|
|
11
|
+
export declare function emitCapacityDeferral(now: number, deferred: number): void;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { cronDaemonInstanceId, liveRunFor } from './live-runs.js';
|
|
3
|
+
import { advanceCron, cancelCron, dueOverlapCrons, expiredIdleCrons, listCronRuns, recordCronRun, } from '../../core/canvas/crons.js';
|
|
4
|
+
import { emitEvent } from '../../core/events/emit.js';
|
|
5
|
+
import { nextSlotAfter } from '../../core/wake.js';
|
|
6
|
+
import { parseSink } from '../cron-sink.js';
|
|
7
|
+
/** Lead of a `cron_runs.delivered` string written by the overlap=skip pass.
|
|
8
|
+
* Matched (not just written) — see `latestRunIsSkip`. */
|
|
9
|
+
const SKIP_MARKER = 'skipped (overlap=skip)';
|
|
10
|
+
// A false negative is an ungated run; a false positive delays one poll at capacity.
|
|
11
|
+
const NODE_LAUNCHING_COMMAND = /\bcrtr\b[^\n]*?\bnode\s+lifecycle\s+revive\b|\bcrtr\b[^\n]*?\bnode\s+new\b|\bcrtr\b[^\n]*?\bcanvas\s+revive\b|\bcrtr\b[^\n]*?\bnode\s+message\s+send\b[^\n]*?\s--fresh\b/;
|
|
12
|
+
export function cronLaunchesNode(c) {
|
|
13
|
+
if (parseSink(c.sink)?.kind === 'spawn')
|
|
14
|
+
return true;
|
|
15
|
+
return NODE_LAUNCHING_COMMAND.test(c.command);
|
|
16
|
+
}
|
|
17
|
+
export function expireDueCrons(nowIso) {
|
|
18
|
+
for (const c of expiredIdleCrons(nowIso)) {
|
|
19
|
+
cancelCron(c.cron_id);
|
|
20
|
+
emitEvent({
|
|
21
|
+
level: 'info',
|
|
22
|
+
event: 'cron.expired',
|
|
23
|
+
fields: { cron_id: c.cron_id, name: c.name, expires_at: c.expires_at },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function latestRunIsSkip(cronId) {
|
|
28
|
+
return listCronRuns(cronId)[0]?.delivered?.startsWith(SKIP_MARKER) === true;
|
|
29
|
+
}
|
|
30
|
+
export function applyOverlapPolicies(now, nowIso) {
|
|
31
|
+
for (const c of dueOverlapCrons(nowIso)) {
|
|
32
|
+
if (c.overlap === 'queue')
|
|
33
|
+
continue;
|
|
34
|
+
if (c.overlap === 'skip') {
|
|
35
|
+
let nextFire;
|
|
36
|
+
try {
|
|
37
|
+
nextFire = nextSlotAfter(c.recur, new Date(now));
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
continue; // paused + escalated by the run path when it next fires
|
|
41
|
+
}
|
|
42
|
+
advanceCron(c.cron_id, nextFire);
|
|
43
|
+
// One marker per streak preserves real runs in the 20-entry ring.
|
|
44
|
+
if (!latestRunIsSkip(c.cron_id)) {
|
|
45
|
+
recordCronRun({
|
|
46
|
+
run_id: randomUUID(),
|
|
47
|
+
cron_id: c.cron_id,
|
|
48
|
+
started: nowIso,
|
|
49
|
+
finished: nowIso,
|
|
50
|
+
duration_ms: 0,
|
|
51
|
+
exit_code: null,
|
|
52
|
+
stdout_head: null,
|
|
53
|
+
stderr_head: null,
|
|
54
|
+
delivered: `${SKIP_MARKER}: fire landed while the previous run was in flight (consecutive skips are not re-recorded until a run settles)`,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// replace
|
|
60
|
+
const live = liveRunFor(c.cron_id);
|
|
61
|
+
if (c.run_lease_owner === cronDaemonInstanceId && live !== undefined && !live.replaced) {
|
|
62
|
+
live.replaced = true;
|
|
63
|
+
live.kill();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const CAPACITY_DEFER_LOG_THROTTLE_MS = 30_000;
|
|
68
|
+
let lastCapacityDeferLogAt = Number.NEGATIVE_INFINITY;
|
|
69
|
+
export function emitCapacityDeferral(now, deferred) {
|
|
70
|
+
if (now - lastCapacityDeferLogAt < CAPACITY_DEFER_LOG_THROTTLE_MS)
|
|
71
|
+
return;
|
|
72
|
+
lastCapacityDeferLogAt = now;
|
|
73
|
+
emitEvent({
|
|
74
|
+
level: 'warn',
|
|
75
|
+
event: 'cron.capacity.run_deferred',
|
|
76
|
+
fields: { deferred_runs: deferred },
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type Cron, type CronRunRecord, type HeldSettle } from '../../core/canvas/crons.js';
|
|
2
|
+
import { type RunSettleContext } from './disposition.js';
|
|
3
|
+
export type LeaseSettlement = 'none' | 'release' | HeldSettle;
|
|
4
|
+
export type SettleOutcome = {
|
|
5
|
+
kind: 'disposed';
|
|
6
|
+
ctx: RunSettleContext;
|
|
7
|
+
selfCanceled?: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'stated';
|
|
10
|
+
delivered: string;
|
|
11
|
+
paused?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export interface SettleRecord {
|
|
14
|
+
runId: string;
|
|
15
|
+
startedAtIso: string;
|
|
16
|
+
finishedAtMs: number;
|
|
17
|
+
durationMs: number;
|
|
18
|
+
exitCode: number | null;
|
|
19
|
+
stdoutHead: string | null;
|
|
20
|
+
stderrHead: string | null;
|
|
21
|
+
}
|
|
22
|
+
export interface SettleRunInput {
|
|
23
|
+
outOfBand: boolean;
|
|
24
|
+
outcome: SettleOutcome;
|
|
25
|
+
record: SettleRecord;
|
|
26
|
+
lease: LeaseSettlement;
|
|
27
|
+
}
|
|
28
|
+
export declare function settleRun(c: Cron, input: SettleRunInput): Promise<CronRunRecord>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { consumeCron, recordCronRun, releaseCronRunLease, } from '../../core/canvas/crons.js';
|
|
2
|
+
import { disposeSettledRun } from './disposition.js';
|
|
3
|
+
function occurrenceStaysOwed(lease) {
|
|
4
|
+
return typeof lease === 'object' && (lease.kind === 'park' || lease.kind === 'redue');
|
|
5
|
+
}
|
|
6
|
+
export async function settleRun(c, input) {
|
|
7
|
+
const { outOfBand, outcome, record, lease } = input;
|
|
8
|
+
let delivered;
|
|
9
|
+
let paused;
|
|
10
|
+
if (outcome.kind === 'disposed') {
|
|
11
|
+
const disposition = await disposeSettledRun(c, outcome.ctx, outOfBand, outcome.selfCanceled ?? false);
|
|
12
|
+
delivered = disposition.delivered;
|
|
13
|
+
paused = disposition.paused;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
delivered = outcome.delivered;
|
|
17
|
+
paused = outcome.paused ?? false;
|
|
18
|
+
}
|
|
19
|
+
const written = {
|
|
20
|
+
run_id: record.runId,
|
|
21
|
+
cron_id: c.cron_id,
|
|
22
|
+
started: record.startedAtIso,
|
|
23
|
+
finished: new Date(record.finishedAtMs).toISOString(),
|
|
24
|
+
duration_ms: record.durationMs,
|
|
25
|
+
exit_code: record.exitCode,
|
|
26
|
+
stdout_head: record.stdoutHead,
|
|
27
|
+
stderr_head: record.stderrHead,
|
|
28
|
+
delivered,
|
|
29
|
+
};
|
|
30
|
+
recordCronRun(written);
|
|
31
|
+
if (lease !== 'none')
|
|
32
|
+
releaseCronRunLease(c.cron_id, lease === 'release' ? undefined : lease);
|
|
33
|
+
// Retain out-of-band, paused, and held rows; their occurrence is not spent.
|
|
34
|
+
if (!outOfBand && c.recur == null && !paused && !occurrenceStaysOwed(lease))
|
|
35
|
+
consumeCron(c.cron_id);
|
|
36
|
+
return written;
|
|
37
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { rmSync } from 'node:fs';
|
|
3
|
+
import { synthesizedPageDocument, writeSynthesizedPage } from '../../core/human/page-synth.js';
|
|
4
|
+
import { ticketDir } from '../../core/human/root.js';
|
|
5
|
+
import { preparePage, publishPage } from '../../core/human/tickets.js';
|
|
6
|
+
import { resolvePageComponents } from '../../core/config.js';
|
|
7
|
+
import { getNode } from '../../core/canvas/canvas.js';
|
|
8
|
+
import { appendInbox } from '../../core/feed/inbox.js';
|
|
9
|
+
import { hasNoNaturalCycle } from '../../core/runtime/revive-all.js';
|
|
10
|
+
import { isParked } from '../../core/runtime/lifecycle.js';
|
|
11
|
+
import { reviveNode } from '../../core/runtime/revive.js';
|
|
12
|
+
import { isBrokerLive } from '../../core/runtime/model-swap.js';
|
|
13
|
+
import { spawnChild } from '../../core/runtime/spawn.js';
|
|
14
|
+
import { cronWakeOrigin } from '../../core/runtime/bearings.js';
|
|
15
|
+
import { parseSink } from '../cron-sink.js';
|
|
16
|
+
import { resolveLiveProfile, resolveLiveProfileName } from './armed-context.js';
|
|
17
|
+
function deliverNodeSink(c, target, stdout) {
|
|
18
|
+
const meta = getNode(target);
|
|
19
|
+
if (meta === null)
|
|
20
|
+
throw new Error(`node sink ${target} is gone`);
|
|
21
|
+
// A cron is an explicit next cycle for a clock-parked node, not other done nodes.
|
|
22
|
+
if (hasNoNaturalCycle(meta) && !isParked(meta)) {
|
|
23
|
+
throw new Error(`node sink ${target} has no natural cycle ahead (done or finalized)`);
|
|
24
|
+
}
|
|
25
|
+
const from = c.created_by != null && getNode(c.created_by) !== null ? c.created_by : null;
|
|
26
|
+
appendInbox(target, {
|
|
27
|
+
from,
|
|
28
|
+
tier: c.tier,
|
|
29
|
+
kind: 'message',
|
|
30
|
+
label: `⏰ cron ${c.name}`,
|
|
31
|
+
data: { body: stdout },
|
|
32
|
+
});
|
|
33
|
+
// The durable append succeeds even if its best-effort wake fails.
|
|
34
|
+
if (c.tier !== 'deferred' && !isBrokerLive(meta)) {
|
|
35
|
+
try {
|
|
36
|
+
reviveNode(target, { resume: true });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
/* best-effort wake — the entry is durably appended regardless */
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
async function deliverSpawnSink(c, kind, stdout) {
|
|
44
|
+
const creatorAlive = c.created_by != null && getNode(c.created_by) !== null;
|
|
45
|
+
const prompt = [
|
|
46
|
+
`Scheduled cron "${c.name}" (${c.cron_id}) fired and delivered its output to you as your kickoff.`,
|
|
47
|
+
'',
|
|
48
|
+
'## Command output',
|
|
49
|
+
'',
|
|
50
|
+
stdout,
|
|
51
|
+
].join('\n');
|
|
52
|
+
const res = await spawnChild({
|
|
53
|
+
kind,
|
|
54
|
+
cwd: c.cwd,
|
|
55
|
+
prompt,
|
|
56
|
+
// Creatorless sinks are terminal roots so each run reaps without stealing focus.
|
|
57
|
+
...(creatorAlive ? { parent: c.created_by } : { root: true, rootLifecycle: 'terminal' }),
|
|
58
|
+
readiness: 'launch',
|
|
59
|
+
profile: resolveLiveProfile(c),
|
|
60
|
+
wakeOrigin: cronWakeOrigin(c, 'node_birth'),
|
|
61
|
+
});
|
|
62
|
+
return res.node.node_id;
|
|
63
|
+
}
|
|
64
|
+
function deliverHumanSink(c, stdout) {
|
|
65
|
+
const synthesized = writeSynthesizedPage(synthesizedPageDocument(`⏰ cron ${c.name}`, `Scheduled cron "${c.name}" delivered output for your attention.`, stdout, false));
|
|
66
|
+
// Validate verbatim stdout before minting a ticket to avoid a half-built page.
|
|
67
|
+
let prepared;
|
|
68
|
+
try {
|
|
69
|
+
const profileName = resolveLiveProfileName(c);
|
|
70
|
+
prepared = preparePage({
|
|
71
|
+
sourceFile: synthesized.path,
|
|
72
|
+
source: {
|
|
73
|
+
sessionName: `cron ${c.name} (${c.cron_id})`,
|
|
74
|
+
...(profileName === undefined ? {} : { profileName }),
|
|
75
|
+
},
|
|
76
|
+
productKinds: resolvePageComponents(),
|
|
77
|
+
delivery: { placement: 'inline', inbox: true, reply: false },
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
rmSync(synthesized.dir, { recursive: true, force: true });
|
|
82
|
+
}
|
|
83
|
+
const id = `page-${randomBytes(4).toString('hex')}`;
|
|
84
|
+
publishPage(ticketDir(id), prepared);
|
|
85
|
+
}
|
|
86
|
+
export async function deliverToSink(c, stdout) {
|
|
87
|
+
const sink = parseSink(c.sink);
|
|
88
|
+
if (sink === null)
|
|
89
|
+
return 'no sink armed — nothing delivered';
|
|
90
|
+
if (sink.kind === 'node') {
|
|
91
|
+
deliverNodeSink(c, sink.node, stdout);
|
|
92
|
+
return `delivered: node ${sink.node}`;
|
|
93
|
+
}
|
|
94
|
+
if (sink.kind === 'spawn') {
|
|
95
|
+
const nodeId = await deliverSpawnSink(c, sink.spawn, stdout);
|
|
96
|
+
return `delivered: spawned ${nodeId}`;
|
|
97
|
+
}
|
|
98
|
+
deliverHumanSink(c, stdout);
|
|
99
|
+
return 'delivered: human send --inbox';
|
|
100
|
+
}
|
|
@@ -1,45 +1,9 @@
|
|
|
1
|
+
import { type RunDueCronOptions } from './cron/passes.js';
|
|
1
2
|
import { type Cron, type CronRunRecord } from '../core/canvas/crons.js';
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* daemon left behind. */
|
|
7
|
-
export declare const cronDaemonInstanceId: `${string}-${string}-${string}-${string}-${string}`;
|
|
8
|
-
export interface RunDueCronOptions {
|
|
9
|
-
/** Invoked synchronously the instant each settlement promise is created, so
|
|
10
|
-
* the caller can register it for a graceful-teardown drain. */
|
|
11
|
-
register?: (work: Promise<void>) => void;
|
|
12
|
-
/** Broker-capacity admission for a run that will LAUNCH OR REVIVE a node
|
|
13
|
-
* (`cronLaunchesNode`). Returns false when the live fleet is at the
|
|
14
|
-
* automatic-revive cap; the daemon wires in its own `hasBrokerCapacity`
|
|
15
|
-
* (crtrd.ts), which owns the fleet count and the throttled capacity event.
|
|
16
|
-
* Absent → every run is admitted (out-of-band/test callers own no fleet). */
|
|
17
|
-
hasBrokerCapacity?: () => boolean;
|
|
18
|
-
}
|
|
19
|
-
/** Will this cron's run consume broker capacity? True when its armed sink
|
|
20
|
-
* births a node, or its command invokes a node-launching crtr verb. A cron
|
|
21
|
-
* that merely runs a shell command or sends a message reads false and is
|
|
22
|
-
* never gated. */
|
|
23
|
-
export declare function cronLaunchesNode(c: Cron): boolean;
|
|
24
|
-
/** Mark a cancellation as originating from the live cron run it names. Only
|
|
25
|
-
* that exact process may finish after its row is removed, so an external cancel
|
|
26
|
-
* retains its normal process-group kill behavior. */
|
|
27
|
-
export declare function markSelfCanceledCronRun(cronId: string, runId: string): boolean;
|
|
28
|
-
/** Recover stale 'running' rows left by a PRIOR daemon instance: a pid that is
|
|
29
|
-
* not VERIFIABLY still the process this lease launched resets straight to
|
|
30
|
-
* idle; a confirmed-live process group past its own run_timeout_s is killed
|
|
31
|
-
* and settled as a timeout run through the SAME failure path a live timeout
|
|
32
|
-
* takes (pause + escalation unless silent). Rows this SAME instance owns are
|
|
33
|
-
* genuinely in flight and left alone.
|
|
34
|
-
*
|
|
35
|
-
* The verification is `verifyLeasedCronRun`, not `isPidAlive`, and it is
|
|
36
|
-
* FAIL-CLOSED: this row was written by a daemon life that has since ended, so
|
|
37
|
-
* after a host reboot its `run_pid` names a slot in a dead kernel's pid space
|
|
38
|
-
* that the OS has probably recycled, and the timeout comparison below is
|
|
39
|
-
* trivially satisfied by any downtime. Liveness alone would therefore SIGTERM
|
|
40
|
-
* a stranger's process group. Only a matching launch-time identity authorizes
|
|
41
|
-
* the signal; everything else releases the lease. */
|
|
42
|
-
export declare function recoverStaleCronLeases(now: number, options?: RunDueCronOptions): void;
|
|
3
|
+
export { CRON_OUTPUT_HEAD_BYTES } from './cron/capture.js';
|
|
4
|
+
export { cronDaemonInstanceId, markSelfCanceledCronRun } from './cron/live-runs.js';
|
|
5
|
+
export { cronLaunchesNode, type RunDueCronOptions } from './cron/passes.js';
|
|
6
|
+
export { recoverStaleCronLeases } from './cron/lease-recovery.js';
|
|
43
7
|
/** Kick off ONE cron run and return its settlement promise, resolving with
|
|
44
8
|
* the settled run record (null = the idle→running lease was lost, or the row
|
|
45
9
|
* was quarantined — nothing was recorded by THIS call). The subprocess
|