@north-light/crouter 0.3.311 → 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 +17 -5
- 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 +312 -1
- 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 +62 -19
- 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 +4 -3
- package/dist/core/__tests__/on-read-dedup-resume.test.js +8 -7
- package/dist/core/__tests__/on-read-nested-store.test.js +8 -7
- 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 +35 -32
- 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 +5 -4
- 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 +19 -5
- 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/command-hooks/artifact.d.ts +6 -0
- package/dist/core/command-hooks/artifact.js +22 -6
- package/dist/core/command-hooks/discovery.d.ts +2 -0
- package/dist/core/command-hooks/discovery.js +2 -0
- package/dist/core/command-hooks/lifecycle-catalog.d.ts +20 -2
- package/dist/core/command-hooks/lifecycle-catalog.js +7 -2
- package/dist/core/command-hooks/lifecycle-create.d.ts +4 -0
- package/dist/core/command-hooks/lifecycle-create.js +51 -0
- package/dist/core/command-hooks/schema.d.ts +2 -2
- package/dist/core/command-hooks/schema.js +5 -4
- package/dist/core/command-hooks/transport/exec-invoke.js +3 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +18 -8
- package/dist/core/command-hooks/transport/exec-lifecycle.js +89 -30
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/errors.d.ts +1 -0
- package/dist/core/errors.js +4 -0
- 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 +4 -3
- 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/companion.d.ts +1 -1
- package/dist/core/review/companion.js +2 -2
- 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/nodes.d.ts +5 -1
- package/dist/core/runtime/nodes.js +26 -11
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +24 -14
- package/dist/core/runtime/reset.js +26 -7
- package/dist/core/runtime/revive.js +226 -217
- package/dist/core/runtime/spawn.d.ts +4 -1
- package/dist/core/runtime/spawn.js +43 -5
- package/dist/core/runtime/warm-pool.d.ts +2 -2
- package/dist/core/runtime/warm-pool.js +23 -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 +41 -17
- 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 +6 -3
- 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 +29 -43
- 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 -148
- 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.d.ts +1 -0
- package/dist/daemon/api/handlers/nodes.js +41 -42
- 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/hook-authoring.d.ts +28 -2
- package/dist/hook-authoring.js +53 -1
- package/dist/index.d.ts +3 -2
- 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
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { openDb, withCanvasWrite } from './db.js';
|
|
2
|
+
function json(value) {
|
|
3
|
+
const encoded = JSON.stringify(value);
|
|
4
|
+
if (encoded === undefined)
|
|
5
|
+
throw new TypeError('worktree value must be JSON-serializable');
|
|
6
|
+
return encoded;
|
|
7
|
+
}
|
|
8
|
+
function parse(value) {
|
|
9
|
+
if (typeof value !== 'string')
|
|
10
|
+
return undefined;
|
|
11
|
+
return JSON.parse(value);
|
|
12
|
+
}
|
|
13
|
+
export function readWorktree(nodeId) {
|
|
14
|
+
const row = openDb().prepare('SELECT * FROM worktrees WHERE node_id = ?').get(nodeId);
|
|
15
|
+
if (row === undefined)
|
|
16
|
+
return null;
|
|
17
|
+
const sweepObserved = parse(row['sweep_observed_json']);
|
|
18
|
+
const attempts = row['attempts'];
|
|
19
|
+
const sweep = sweepObserved === undefined ? undefined : {
|
|
20
|
+
reason: row['sweep_reason'],
|
|
21
|
+
...(row['sweep_detail'] === null ? {} : { detail: row['sweep_detail'] }),
|
|
22
|
+
observed: sweepObserved,
|
|
23
|
+
attempts,
|
|
24
|
+
last_attempt: row['sweep_last_at'],
|
|
25
|
+
next_attempt: row['next_attempt_at'],
|
|
26
|
+
...(row['quarantined'] === 1 ? { quarantined: true } : {}),
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
state: row['state'],
|
|
30
|
+
...(row['cleanup_state'] === null ? {} : { cleanup: row['cleanup_state'] }),
|
|
31
|
+
path: row['path'],
|
|
32
|
+
branch: row['branch'],
|
|
33
|
+
repo_root: row['repo_root'],
|
|
34
|
+
base_ref: row['base_ref'],
|
|
35
|
+
base_sha: row['base_sha'],
|
|
36
|
+
created: row['created_at'],
|
|
37
|
+
...(row['closed_at'] === null ? {} : { closed: row['closed_at'] }),
|
|
38
|
+
...(parse(row['abandoned_json']) === undefined ? {} : { abandoned: parse(row['abandoned_json']) }),
|
|
39
|
+
...(parse(row['land_intent_json']) === undefined ? {} : { land_intent: parse(row['land_intent_json']) }),
|
|
40
|
+
...(sweep === undefined ? {} : { sweep }),
|
|
41
|
+
...(parse(row['disposal_json']) === undefined ? {} : { disposal: parse(row['disposal_json']) }),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export function openWorktree(nodeId, worktree, db = openDb()) {
|
|
45
|
+
db.prepare(`INSERT INTO worktrees (node_id, state, cleanup_state, path, branch, repo_root, base_ref, base_sha, created_at, closed_at, next_attempt_at, attempts, quarantined, sweep_reason, sweep_detail, sweep_last_at, sweep_observed_json, abandoned_json, land_intent_json, disposal_json) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL)`).run(nodeId, worktree.state, worktree.cleanup ?? null, worktree.path, worktree.branch, worktree.repo_root, worktree.base_ref, worktree.base_sha, worktree.created, worktree.closed ?? null);
|
|
46
|
+
}
|
|
47
|
+
export function closeWorktree(nodeId, input) {
|
|
48
|
+
openDb().prepare("UPDATE worktrees SET state = 'closed', cleanup_state = ?, closed_at = ?, land_intent_json = NULL, sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(input.cleanup, input.closedAt, nodeId);
|
|
49
|
+
}
|
|
50
|
+
/** Complete a worktree close and repoint the node in the same SQL transaction.
|
|
51
|
+
* A close invalidates the active transcript because Pi remains in the old
|
|
52
|
+
* checkout; the next launch starts from the durable base checkout. */
|
|
53
|
+
export function closeWorktreeAndRepoint(nodeId, input) {
|
|
54
|
+
withCanvasWrite((db) => {
|
|
55
|
+
db.prepare('UPDATE nodes SET cwd = ? WHERE node_id = ?').run(input.cwd, nodeId);
|
|
56
|
+
if (input.unbindSession)
|
|
57
|
+
db.prepare('UPDATE sessions SET unbound_at = ? WHERE node_id = ? AND unbound_at IS NULL').run(input.closedAt, nodeId);
|
|
58
|
+
db.prepare("UPDATE worktrees SET state = 'closed', cleanup_state = ?, closed_at = ?, land_intent_json = NULL, sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(input.cleanup, input.closedAt, nodeId);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
export function abandonWorktree(nodeId, abandoned) {
|
|
62
|
+
openDb().prepare("UPDATE worktrees SET state = 'abandoned', abandoned_json = ? WHERE node_id = ? AND abandoned_json IS NULL").run(json(abandoned), nodeId);
|
|
63
|
+
}
|
|
64
|
+
export function abandonWorktreeAndRepoint(nodeId, input) {
|
|
65
|
+
withCanvasWrite((db) => {
|
|
66
|
+
db.prepare('UPDATE nodes SET cwd = ? WHERE node_id = ?').run(input.cwd, nodeId);
|
|
67
|
+
db.prepare("UPDATE worktrees SET state = 'abandoned', abandoned_json = ? WHERE node_id = ? AND abandoned_json IS NULL").run(json(input.abandoned), nodeId);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export function recordLandIntent(nodeId, intent) {
|
|
71
|
+
openDb().prepare('UPDATE worktrees SET land_intent_json = ? WHERE node_id = ? AND land_intent_json IS NULL').run(json(intent), nodeId);
|
|
72
|
+
}
|
|
73
|
+
export function recordDisposalGrant(nodeId, disposal) {
|
|
74
|
+
openDb().prepare('UPDATE worktrees SET disposal_json = ? WHERE node_id = ? AND disposal_json IS NULL').run(json(disposal), nodeId);
|
|
75
|
+
}
|
|
76
|
+
export function recordSweepAttempt(nodeId, input) {
|
|
77
|
+
openDb().prepare('UPDATE worktrees SET sweep_reason = ?, sweep_detail = ?, sweep_observed_json = ?, attempts = ?, sweep_last_at = ?, next_attempt_at = ?, quarantined = ? WHERE node_id = ?').run(input.reason, input.detail ?? null, json(input.observed), input.attempts, input.lastAttemptAt, input.nextAttemptAt, input.quarantined ? 1 : 0, nodeId);
|
|
78
|
+
}
|
|
79
|
+
export function completeCleanup(nodeId) {
|
|
80
|
+
openDb().prepare("UPDATE worktrees SET state = 'closed', cleanup_state = 'complete', sweep_reason = NULL, sweep_detail = NULL, sweep_last_at = NULL, sweep_observed_json = NULL, next_attempt_at = NULL, attempts = 0, quarantined = 0 WHERE node_id = ?").run(nodeId);
|
|
81
|
+
}
|
|
82
|
+
export function hasUnreconciledWorktree(nodeId) {
|
|
83
|
+
return openDb().prepare("SELECT 1 FROM worktrees WHERE node_id = ? AND state != 'abandoned' AND (state = 'open' OR cleanup_state IS NULL OR cleanup_state != 'complete')").get(nodeId) !== undefined;
|
|
84
|
+
}
|
|
85
|
+
export function sweepCandidates(now) {
|
|
86
|
+
return openDb().prepare(`SELECT w.node_id FROM worktrees w JOIN nodes n ON n.node_id = w.node_id WHERE n.status IN ('done', 'dead', 'canceled') AND n.frozen_at IS NULL AND w.state IN ('open', 'closed') AND (w.state = 'open' OR w.cleanup_state IS NULL OR w.cleanup_state != 'complete') AND (w.state = 'closed' OR (n.status = 'done' AND n.final_report IS NOT NULL)) AND (w.next_attempt_at IS NULL OR w.next_attempt_at <= ?) ORDER BY w.next_attempt_at, w.node_id`).all(now).map(({ node_id }) => node_id);
|
|
87
|
+
}
|
|
88
|
+
export function quarantinedWorktrees() {
|
|
89
|
+
return openDb().prepare('SELECT node_id FROM worktrees WHERE quarantined = 1 ORDER BY sweep_last_at').all().flatMap(({ node_id }) => {
|
|
90
|
+
const worktree = readWorktree(node_id);
|
|
91
|
+
return worktree === null ? [] : [{ nodeId: node_id, worktree }];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import type { PluginManifest } from '../../types.js';
|
|
2
2
|
import { type HookManifestIssue, type ValidatedHookManifest } from './schema.js';
|
|
3
|
+
export interface LifecycleDeclarationCandidate {
|
|
4
|
+
event: string;
|
|
5
|
+
op: string;
|
|
6
|
+
index: number;
|
|
7
|
+
}
|
|
3
8
|
export interface HookArtifactValidation {
|
|
4
9
|
manifestPath?: string;
|
|
5
10
|
executablePath?: string;
|
|
6
11
|
manifest?: ValidatedHookManifest;
|
|
12
|
+
lifecycleCandidates: readonly LifecycleDeclarationCandidate[];
|
|
7
13
|
issues: HookManifestIssue[];
|
|
8
14
|
}
|
|
9
15
|
/** Statically validates the local hook artifact a source plugin ships. */
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { readFileSync, realpathSync, statSync } from 'node:fs';
|
|
2
2
|
import { isAbsolute, resolve, sep } from 'node:path';
|
|
3
3
|
import { validateHookManifest } from './schema.js';
|
|
4
|
+
function lifecycleCandidates(raw) {
|
|
5
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
|
|
6
|
+
return [];
|
|
7
|
+
const lifecycle = raw['lifecycle'];
|
|
8
|
+
if (!Array.isArray(lifecycle))
|
|
9
|
+
return [];
|
|
10
|
+
return lifecycle.flatMap((value, index) => {
|
|
11
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
12
|
+
return [];
|
|
13
|
+
const declaration = value;
|
|
14
|
+
return typeof declaration['event'] === 'string'
|
|
15
|
+
? [{ event: declaration['event'], op: typeof declaration['op'] === 'string' ? declaration['op'] : '<invalid>', index }]
|
|
16
|
+
: [];
|
|
17
|
+
});
|
|
18
|
+
}
|
|
4
19
|
function safeFilePath(root, pointer) {
|
|
5
20
|
if (isAbsolute(pointer))
|
|
6
21
|
return null;
|
|
@@ -29,10 +44,10 @@ export function validatePluginHookArtifact(root, manifest) {
|
|
|
29
44
|
expected: 'both hooks and hookExecutable',
|
|
30
45
|
next: hasHooks ? 'Add plugin.json.hookExecutable or remove hooks.' : 'Add plugin.json.hooks or remove hookExecutable.',
|
|
31
46
|
});
|
|
32
|
-
return { issues };
|
|
47
|
+
return { lifecycleCandidates: [], issues };
|
|
33
48
|
}
|
|
34
49
|
if (!hasHooks)
|
|
35
|
-
return { issues };
|
|
50
|
+
return { lifecycleCandidates: [], issues };
|
|
36
51
|
if (typeof hooks !== 'string' || hooks.length === 0) {
|
|
37
52
|
issues.push({
|
|
38
53
|
code: 'hook_manifest_invalid',
|
|
@@ -54,7 +69,7 @@ export function validatePluginHookArtifact(root, manifest) {
|
|
|
54
69
|
});
|
|
55
70
|
}
|
|
56
71
|
if (issues.length > 0)
|
|
57
|
-
return { issues };
|
|
72
|
+
return { lifecycleCandidates: [], issues };
|
|
58
73
|
const hooksPointer = hooks;
|
|
59
74
|
const executablePointer = executable;
|
|
60
75
|
const manifestPath = safeFilePath(root, hooksPointer);
|
|
@@ -90,7 +105,7 @@ export function validatePluginHookArtifact(root, manifest) {
|
|
|
90
105
|
});
|
|
91
106
|
}
|
|
92
107
|
if (manifestPath === null)
|
|
93
|
-
return { ...(executablePath === null ? {} : { executablePath }), issues };
|
|
108
|
+
return { lifecycleCandidates: [], ...(executablePath === null ? {} : { executablePath }), issues };
|
|
94
109
|
let text;
|
|
95
110
|
try {
|
|
96
111
|
text = readFileSync(manifestPath, 'utf8');
|
|
@@ -103,7 +118,7 @@ export function validatePluginHookArtifact(root, manifest) {
|
|
|
103
118
|
expected: 'a readable JSON file',
|
|
104
119
|
next: 'Reinstall or update the plugin.',
|
|
105
120
|
});
|
|
106
|
-
return { manifestPath, ...(executablePath === null ? {} : { executablePath }), issues };
|
|
121
|
+
return { manifestPath, lifecycleCandidates: [], ...(executablePath === null ? {} : { executablePath }), issues };
|
|
107
122
|
}
|
|
108
123
|
let raw;
|
|
109
124
|
try {
|
|
@@ -117,11 +132,12 @@ export function validatePluginHookArtifact(root, manifest) {
|
|
|
117
132
|
expected: 'a JSON object',
|
|
118
133
|
next: 'Regenerate hooks.json.',
|
|
119
134
|
});
|
|
120
|
-
return { manifestPath, ...(executablePath === null ? {} : { executablePath }), issues };
|
|
135
|
+
return { manifestPath, lifecycleCandidates: [], ...(executablePath === null ? {} : { executablePath }), issues };
|
|
121
136
|
}
|
|
122
137
|
const validation = validateHookManifest(raw);
|
|
123
138
|
return {
|
|
124
139
|
manifestPath,
|
|
140
|
+
lifecycleCandidates: lifecycleCandidates(raw),
|
|
125
141
|
...(executablePath === null ? {} : { executablePath }),
|
|
126
142
|
...(validation.manifest === undefined ? {} : { manifest: validation.manifest }),
|
|
127
143
|
issues: [...issues, ...validation.issues],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { InstalledPlugin } from '../../types.js';
|
|
2
|
+
import { type LifecycleDeclarationCandidate } from './artifact.js';
|
|
2
3
|
import type { CoreHookCatalog } from './catalog.js';
|
|
3
4
|
import type { HookManifestIssue, HookPhase, LifecycleHookPhase, ValidatedHookManifest } from './schema.js';
|
|
4
5
|
import type { LifecycleEvent } from './lifecycle-catalog.js';
|
|
@@ -65,6 +66,7 @@ export interface HookPluginValidation {
|
|
|
65
66
|
manifestPath?: string;
|
|
66
67
|
executablePath?: string;
|
|
67
68
|
manifest?: ValidatedHookManifest;
|
|
69
|
+
lifecycleCandidates: readonly LifecycleDeclarationCandidate[];
|
|
68
70
|
hooks: readonly EffectiveHook[];
|
|
69
71
|
issues: readonly HookDiscoveryIssue[];
|
|
70
72
|
}
|
|
@@ -109,6 +109,7 @@ export function compileHookRegistry(catalog, plugins) {
|
|
|
109
109
|
...(artifact.manifestPath === undefined ? {} : { manifestPath: artifact.manifestPath }),
|
|
110
110
|
...(artifact.executablePath === undefined ? {} : { executablePath: artifact.executablePath }),
|
|
111
111
|
...(artifact.manifest === undefined ? {} : { manifest: artifact.manifest }),
|
|
112
|
+
lifecycleCandidates: Object.freeze([...artifact.lifecycleCandidates]),
|
|
112
113
|
hooks: Object.freeze(compiled),
|
|
113
114
|
issues: Object.freeze(pluginIssues),
|
|
114
115
|
}));
|
|
@@ -183,6 +184,7 @@ export function compileLifecycleHookRegistry(plugins) {
|
|
|
183
184
|
...(artifact.manifestPath === undefined ? {} : { manifestPath: artifact.manifestPath }),
|
|
184
185
|
...(artifact.executablePath === undefined ? {} : { executablePath: artifact.executablePath }),
|
|
185
186
|
...(artifact.manifest === undefined ? {} : { manifest: artifact.manifest }),
|
|
187
|
+
lifecycleCandidates: Object.freeze([...artifact.lifecycleCandidates]),
|
|
186
188
|
hooks: Object.freeze([]),
|
|
187
189
|
issues: Object.freeze(pluginIssues),
|
|
188
190
|
}));
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
|
|
1
|
+
export declare const LIFECYCLE_CATALOG: {
|
|
2
|
+
readonly 'node:create': {
|
|
3
|
+
readonly phase: "before";
|
|
4
|
+
readonly hookTimeoutMs: 5000;
|
|
5
|
+
readonly eventBudgetMs: 10000;
|
|
6
|
+
};
|
|
7
|
+
readonly 'node:start': {
|
|
8
|
+
readonly phase: "on";
|
|
9
|
+
readonly hookTimeoutMs: 5000;
|
|
10
|
+
readonly eventBudgetMs: 10000;
|
|
11
|
+
};
|
|
12
|
+
readonly 'node:close': {
|
|
13
|
+
readonly phase: "on";
|
|
14
|
+
readonly hookTimeoutMs: 120000;
|
|
15
|
+
readonly eventBudgetMs: 180000;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
export type LifecycleEvent = keyof typeof LIFECYCLE_CATALOG;
|
|
19
|
+
export type LifecycleHookPhase = (typeof LIFECYCLE_CATALOG)[LifecycleEvent]['phase'];
|
|
20
|
+
export declare const LIFECYCLE_EVENTS: readonly ("node:create" | "node:start" | "node:close")[];
|
|
3
21
|
export declare function isLifecycleEvent(value: string): value is LifecycleEvent;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const LIFECYCLE_CATALOG = {
|
|
2
|
+
'node:create': { phase: 'before', hookTimeoutMs: 5_000, eventBudgetMs: 10_000 },
|
|
3
|
+
'node:start': { phase: 'on', hookTimeoutMs: 5_000, eventBudgetMs: 10_000 },
|
|
4
|
+
'node:close': { phase: 'on', hookTimeoutMs: 120_000, eventBudgetMs: 180_000 },
|
|
5
|
+
};
|
|
6
|
+
export const LIFECYCLE_EVENTS = Object.freeze(Object.keys(LIFECYCLE_CATALOG));
|
|
2
7
|
export function isLifecycleEvent(value) {
|
|
3
|
-
return
|
|
8
|
+
return Object.hasOwn(LIFECYCLE_CATALOG, value);
|
|
4
9
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { NodeCreateHookRequest } from '../../hook-authoring.js';
|
|
2
|
+
export type NodeCreateRequest = NodeCreateHookRequest['create'];
|
|
3
|
+
/** Admit one node creation and return the release that must run after its row exists. */
|
|
4
|
+
export declare function admitNodeCreate(create: NodeCreateRequest): Promise<() => void>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { crtrHome } from '../canvas/paths.js';
|
|
2
|
+
import { nodeCreateRefused } from '../errors.js';
|
|
3
|
+
import { discoverLifecycleHookRegistry } from './discovery.js';
|
|
4
|
+
import { invokeBlockingLifecycleHooks } from './transport/exec-lifecycle.js';
|
|
5
|
+
let nodeCreateGate = Promise.resolve();
|
|
6
|
+
async function enterNodeCreateGate() {
|
|
7
|
+
let resolve;
|
|
8
|
+
const previous = nodeCreateGate;
|
|
9
|
+
nodeCreateGate = new Promise((release) => { resolve = release; });
|
|
10
|
+
await previous;
|
|
11
|
+
let released = false;
|
|
12
|
+
return () => {
|
|
13
|
+
if (released)
|
|
14
|
+
return;
|
|
15
|
+
released = true;
|
|
16
|
+
resolve();
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function refusedCreateHookDiscovery(cwd, profileId) {
|
|
20
|
+
const registry = discoverLifecycleHookRegistry(cwd, profileId);
|
|
21
|
+
const plan = registry.plans.get('node:create') ?? [];
|
|
22
|
+
const failed = registry.validations.flatMap((validation) => validation.lifecycleCandidates
|
|
23
|
+
.filter((candidate) => candidate.event === 'node:create' && !plan.some((hook) => hook.plugin.name === validation.plugin.name && hook.declarationIndex === candidate.index))
|
|
24
|
+
.map((candidate) => ({
|
|
25
|
+
validation,
|
|
26
|
+
candidate,
|
|
27
|
+
issue: validation.issues.find((issue) => issue.path === `lifecycle[${candidate.index}]` || issue.path?.startsWith(`lifecycle[${candidate.index}].`)) ?? validation.issues[0],
|
|
28
|
+
})))[0];
|
|
29
|
+
if (failed === undefined)
|
|
30
|
+
return registry;
|
|
31
|
+
const { validation, candidate, issue } = failed;
|
|
32
|
+
throw nodeCreateRefused(`plugin "${validation.plugin.name}" lifecycle hook "${candidate.op}" for node:create could not be discovered: ${issue.message}`, `Refused by plugin ${validation.plugin.name}, op ${candidate.op}.`);
|
|
33
|
+
}
|
|
34
|
+
/** Admit one node creation and return the release that must run after its row exists. */
|
|
35
|
+
export async function admitNodeCreate(create) {
|
|
36
|
+
const release = await enterNodeCreateGate();
|
|
37
|
+
try {
|
|
38
|
+
const registry = refusedCreateHookDiscovery(create.cwd, create.profile);
|
|
39
|
+
const refusal = await invokeBlockingLifecycleHooks(registry.plans.get('node:create') ?? [], {
|
|
40
|
+
create,
|
|
41
|
+
runtime: { canvasHome: crtrHome(), profile: create.profile },
|
|
42
|
+
});
|
|
43
|
+
if (refusal !== null)
|
|
44
|
+
throw nodeCreateRefused(refusal.message, refusal.next);
|
|
45
|
+
return release;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
release();
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type LifecycleEvent } from './lifecycle-catalog.js';
|
|
1
|
+
import { type LifecycleEvent, type LifecycleHookPhase } from './lifecycle-catalog.js';
|
|
2
|
+
export type { LifecycleHookPhase } from './lifecycle-catalog.js';
|
|
2
3
|
export type HookPhase = 'before' | 'after' | 'replace';
|
|
3
|
-
export type LifecycleHookPhase = 'on';
|
|
4
4
|
export interface DeclaredHook {
|
|
5
5
|
target: string;
|
|
6
6
|
phase: HookPhase;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isRecord } from '../../shared/predicates.js';
|
|
2
|
-
import { LIFECYCLE_EVENTS, isLifecycleEvent } from './lifecycle-catalog.js';
|
|
2
|
+
import { LIFECYCLE_CATALOG, LIFECYCLE_EVENTS, isLifecycleEvent } from './lifecycle-catalog.js';
|
|
3
3
|
function typeName(value) {
|
|
4
4
|
if (value === null)
|
|
5
5
|
return 'null';
|
|
@@ -61,8 +61,9 @@ function validateLifecycleDeclaration(value, index, issue) {
|
|
|
61
61
|
issue('hook_manifest_invalid', 'event must name a supported lifecycle event', String(value['event']), LIFECYCLE_EVENTS.join(' | '), `Set event to one of: ${LIFECYCLE_EVENTS.join(', ')}.`, `${path}.event`);
|
|
62
62
|
return undefined;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const phase = LIFECYCLE_CATALOG[value['event']].phase;
|
|
65
|
+
if (value['phase'] !== phase) {
|
|
66
|
+
issue('hook_manifest_invalid', `phase must be ${phase}`, String(value['phase']), phase, `Set phase to ${phase}.`, `${path}.phase`);
|
|
66
67
|
return undefined;
|
|
67
68
|
}
|
|
68
69
|
if (!isEffects(value['effects'])) {
|
|
@@ -71,7 +72,7 @@ function validateLifecycleDeclaration(value, index, issue) {
|
|
|
71
72
|
}
|
|
72
73
|
return {
|
|
73
74
|
event: value['event'],
|
|
74
|
-
phase
|
|
75
|
+
phase,
|
|
75
76
|
op: value['op'],
|
|
76
77
|
description: value['description'],
|
|
77
78
|
effects: value['effects'],
|
|
@@ -170,7 +170,9 @@ function buildRequest(spec, invocation, cwd) {
|
|
|
170
170
|
if (invocation.result !== undefined) {
|
|
171
171
|
throw protocolError(spec, invocation, `${spec.phase} hook invocation included a result`, 'result only for after hooks');
|
|
172
172
|
}
|
|
173
|
-
|
|
173
|
+
if (spec.phase === 'before')
|
|
174
|
+
return { ...base, phase: 'before' };
|
|
175
|
+
return { ...base, phase: 'replace' };
|
|
174
176
|
}
|
|
175
177
|
function parseEnvelope(spec, invocation, stdout) {
|
|
176
178
|
let value;
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import type { LifecycleHookRequest } from '../../../hook-authoring.js';
|
|
1
|
+
import type { LifecycleHookRequest, NodeCreateHookRequest } from '../../../hook-authoring.js';
|
|
2
2
|
import type { EffectiveLifecycleHook } from '../discovery.js';
|
|
3
|
-
export
|
|
4
|
-
export declare const LIFECYCLE_EVENT_BUDGET_MS = 10000;
|
|
5
|
-
export interface LifecycleHookInvocation {
|
|
3
|
+
export interface NodeLifecycleHookInvocation {
|
|
6
4
|
node: LifecycleHookRequest['node'];
|
|
7
5
|
runtime: LifecycleHookRequest['runtime'];
|
|
8
6
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
export interface NodeCreateHookInvocation {
|
|
8
|
+
create: NodeCreateHookRequest['create'];
|
|
9
|
+
runtime: NodeCreateHookRequest['runtime'];
|
|
10
|
+
}
|
|
11
|
+
export interface BlockingLifecycleHookRefusal {
|
|
12
|
+
hook: EffectiveLifecycleHook;
|
|
13
|
+
message: string;
|
|
14
|
+
next: string;
|
|
15
|
+
}
|
|
16
|
+
/** Runs one lifecycle hook. `node:start` and `node:close` remain best-effort. */
|
|
17
|
+
export declare function invokeLifecycleHook(hook: EffectiveLifecycleHook, invocation: NodeLifecycleHookInvocation, timeoutMs: number): Promise<void>;
|
|
18
|
+
/** Executes non-blocking lifecycle hooks in discovery order within the event's catalogued budget. */
|
|
19
|
+
export declare function invokeLifecycleHooks(hooks: readonly EffectiveLifecycleHook[], invocation: NodeLifecycleHookInvocation): Promise<void>;
|
|
20
|
+
/** Runs blocking `node:create` hooks. Every protocol or process failure refuses the create. */
|
|
21
|
+
export declare function invokeBlockingLifecycleHooks(hooks: readonly EffectiveLifecycleHook[], invocation: NodeCreateHookInvocation): Promise<BlockingLifecycleHookRefusal | null>;
|
|
22
|
+
export declare function lifecycleHookAttribution(hook: EffectiveLifecycleHook): string;
|
|
@@ -3,53 +3,109 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
import { PROCESS_GROUP_KILL_GRACE_MS, posixProcessGroupSpawnOptions, terminateProcessGroup } from '../../../hook-process.js';
|
|
4
4
|
import { isRecord } from '../../../shared/predicates.js';
|
|
5
5
|
import { diag } from '../../io.js';
|
|
6
|
+
import { LIFECYCLE_CATALOG } from '../lifecycle-catalog.js';
|
|
6
7
|
const MAX_STDOUT = 10 * 1024 * 1024;
|
|
7
|
-
|
|
8
|
-
export const LIFECYCLE_EVENT_BUDGET_MS = 10_000;
|
|
9
|
-
/** Runs one lifecycle hook. The node launch remains authoritative on every failure. */
|
|
8
|
+
/** Runs one lifecycle hook. `node:start` and `node:close` remain best-effort. */
|
|
10
9
|
export async function invokeLifecycleHook(hook, invocation, timeoutMs) {
|
|
11
10
|
try {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
event: hook.event,
|
|
16
|
-
phase: hook.phase,
|
|
17
|
-
operationId: randomBytes(16).toString('hex'),
|
|
18
|
-
node: invocation.node,
|
|
19
|
-
runtime: invocation.runtime,
|
|
20
|
-
context: { cwd: invocation.node.cwd },
|
|
21
|
-
};
|
|
22
|
-
const result = await runLifecycleProcess(hook, JSON.stringify(request), timeoutMs);
|
|
23
|
-
if (result.signal !== null)
|
|
24
|
-
throw new Error(`executable was killed by signal ${result.signal}`);
|
|
25
|
-
const envelope = parseEnvelope(result.stdout);
|
|
26
|
-
if (envelope.ok) {
|
|
27
|
-
if (result.status !== 0)
|
|
28
|
-
diag(`crtr: ${label(hook)} returned ok:true but exited ${result.status} (honoring the envelope)`);
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
diag(`crtr: ${label(hook)} failed: ${envelope.error.code}: ${envelope.error.message}`);
|
|
11
|
+
const envelope = await executeLifecycleHook(hook, invocation, timeoutMs);
|
|
12
|
+
if (!envelope.ok)
|
|
13
|
+
diag(`crtr: ${label(hook)} failed: ${envelope.error.code}: ${envelope.error.message}`);
|
|
32
14
|
}
|
|
33
15
|
catch (error) {
|
|
34
16
|
diag(`crtr: ${label(hook)} failed: ${describeError(error)}`);
|
|
35
17
|
}
|
|
36
18
|
}
|
|
37
|
-
/** Executes lifecycle hooks in discovery order
|
|
19
|
+
/** Executes non-blocking lifecycle hooks in discovery order within the event's catalogued budget. */
|
|
38
20
|
export async function invokeLifecycleHooks(hooks, invocation) {
|
|
39
|
-
|
|
21
|
+
if (hooks.length === 0)
|
|
22
|
+
return;
|
|
23
|
+
const { hookTimeoutMs, eventBudgetMs } = LIFECYCLE_CATALOG[hooks[0].event];
|
|
24
|
+
const deadline = Date.now() + eventBudgetMs;
|
|
40
25
|
for (const hook of hooks) {
|
|
41
26
|
const remaining = deadline - Date.now();
|
|
42
|
-
|
|
43
|
-
// process-group termination grace inside the event budget rather than
|
|
44
|
-
// letting the final cleanup extend the node-start critical path.
|
|
45
|
-
const timeoutMs = Math.min(LIFECYCLE_HOOK_TIMEOUT_MS, remaining - PROCESS_GROUP_KILL_GRACE_MS);
|
|
27
|
+
const timeoutMs = Math.min(hookTimeoutMs, remaining - PROCESS_GROUP_KILL_GRACE_MS);
|
|
46
28
|
if (timeoutMs <= 0) {
|
|
47
|
-
diag(`crtr: lifecycle hook event ${hook.event} exceeded its ${
|
|
29
|
+
diag(`crtr: lifecycle hook event ${hook.event} exceeded its ${eventBudgetMs}ms aggregate budget; skipped ${label(hook)}`);
|
|
48
30
|
return;
|
|
49
31
|
}
|
|
50
32
|
await invokeLifecycleHook(hook, invocation, timeoutMs);
|
|
51
33
|
}
|
|
52
34
|
}
|
|
35
|
+
/** Runs blocking `node:create` hooks. Every protocol or process failure refuses the create. */
|
|
36
|
+
export async function invokeBlockingLifecycleHooks(hooks, invocation) {
|
|
37
|
+
if (hooks.length === 0)
|
|
38
|
+
return null;
|
|
39
|
+
const { hookTimeoutMs, eventBudgetMs } = LIFECYCLE_CATALOG['node:create'];
|
|
40
|
+
const deadline = Date.now() + eventBudgetMs;
|
|
41
|
+
for (const hook of hooks) {
|
|
42
|
+
const remaining = deadline - Date.now();
|
|
43
|
+
const timeoutMs = Math.min(hookTimeoutMs, remaining - PROCESS_GROUP_KILL_GRACE_MS);
|
|
44
|
+
if (timeoutMs <= 0) {
|
|
45
|
+
return refusal(hook, `lifecycle hook event node:create exceeded its ${eventBudgetMs}ms aggregate budget`);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const envelope = await executeLifecycleHook(hook, invocation, timeoutMs);
|
|
49
|
+
if (!envelope.ok)
|
|
50
|
+
return {
|
|
51
|
+
hook,
|
|
52
|
+
message: envelope.error.message,
|
|
53
|
+
next: envelope.error.next ?? attribution(hook),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return refusal(hook, describeError(error));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
function refusal(hook, cause) {
|
|
63
|
+
return {
|
|
64
|
+
hook,
|
|
65
|
+
message: `${label(hook)} failed: ${cause}`,
|
|
66
|
+
next: attribution(hook),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
export function lifecycleHookAttribution(hook) {
|
|
70
|
+
return attribution(hook);
|
|
71
|
+
}
|
|
72
|
+
async function executeLifecycleHook(hook, invocation, timeoutMs) {
|
|
73
|
+
const request = hook.event === 'node:create'
|
|
74
|
+
? createRequest(hook, invocation)
|
|
75
|
+
: nodeRequest(hook, invocation);
|
|
76
|
+
const result = await runLifecycleProcess(hook, JSON.stringify(request), timeoutMs);
|
|
77
|
+
if (result.signal !== null)
|
|
78
|
+
throw new Error(`executable was killed by signal ${result.signal}`);
|
|
79
|
+
const envelope = parseEnvelope(result.stdout);
|
|
80
|
+
if (envelope.ok && result.status !== 0) {
|
|
81
|
+
diag(`crtr: ${label(hook)} returned ok:true but exited ${result.status} (honoring the envelope)`);
|
|
82
|
+
}
|
|
83
|
+
return envelope;
|
|
84
|
+
}
|
|
85
|
+
function nodeRequest(hook, invocation) {
|
|
86
|
+
return {
|
|
87
|
+
protocolVersion: 1,
|
|
88
|
+
op: hook.op,
|
|
89
|
+
event: hook.event,
|
|
90
|
+
phase: hook.phase,
|
|
91
|
+
operationId: randomBytes(16).toString('hex'),
|
|
92
|
+
node: invocation.node,
|
|
93
|
+
runtime: invocation.runtime,
|
|
94
|
+
context: { cwd: invocation.node.cwd },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function createRequest(hook, invocation) {
|
|
98
|
+
return {
|
|
99
|
+
protocolVersion: 1,
|
|
100
|
+
op: hook.op,
|
|
101
|
+
event: 'node:create',
|
|
102
|
+
phase: 'before',
|
|
103
|
+
operationId: randomBytes(16).toString('hex'),
|
|
104
|
+
create: invocation.create,
|
|
105
|
+
runtime: invocation.runtime,
|
|
106
|
+
context: { cwd: invocation.create.cwd },
|
|
107
|
+
};
|
|
108
|
+
}
|
|
53
109
|
async function runLifecycleProcess(hook, input, timeoutMs) {
|
|
54
110
|
let child;
|
|
55
111
|
try {
|
|
@@ -147,6 +203,9 @@ function exactKeys(value, required, optional = []) {
|
|
|
147
203
|
function label(hook) {
|
|
148
204
|
return `plugin "${hook.plugin.name}" lifecycle hook "${hook.op}" for ${hook.event}`;
|
|
149
205
|
}
|
|
206
|
+
function attribution(hook) {
|
|
207
|
+
return `Refused by plugin ${hook.plugin.name}, op ${hook.op}.`;
|
|
208
|
+
}
|
|
150
209
|
function describeError(error) {
|
|
151
210
|
return error instanceof Error ? error.message : String(error);
|
|
152
211
|
}
|
package/dist/core/config.d.ts
CHANGED
|
@@ -3,23 +3,28 @@ import { type BindingId } from './keybindings/catalog.js';
|
|
|
3
3
|
export declare function configPath(scope: Scope): string | null;
|
|
4
4
|
export declare function statePath(scope: Scope): string | null;
|
|
5
5
|
export declare function readConfig(scope: Scope): ResolvedScopeConfig;
|
|
6
|
-
/** Read the config that lives at an EXACT scope-root dir, rather than the
|
|
7
|
-
* resolved nearest root for a scope. Lets a caller iterate each visible
|
|
8
|
-
* project root's own config when several are in scope (nested `.crouter` dirs
|
|
9
|
-
* or a profile-widened stack), instead of collapsing them onto the nearest. */
|
|
10
6
|
export declare function readConfigAtRoot(root: string): ResolvedScopeConfig;
|
|
11
7
|
export declare function readState(scope: Scope): ScopeState;
|
|
8
|
+
export type RawSettingsTarget = {
|
|
9
|
+
scope: 'user';
|
|
10
|
+
} | {
|
|
11
|
+
scope: 'profile';
|
|
12
|
+
profileId: string;
|
|
13
|
+
};
|
|
14
|
+
export declare class InvalidRawSettingsError extends Error {
|
|
15
|
+
constructor(cause: unknown);
|
|
16
|
+
}
|
|
17
|
+
export declare function readRawSettingsForTarget(target: RawSettingsTarget): {
|
|
18
|
+
settings: Record<string, unknown> | null;
|
|
19
|
+
revision: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function replaceRawSettingsForTarget(target: RawSettingsTarget, next: Record<string, unknown>, ifRevision: string): {
|
|
22
|
+
revision: string;
|
|
23
|
+
changed: boolean;
|
|
24
|
+
};
|
|
12
25
|
type RawConfig = Record<string, unknown>;
|
|
13
26
|
export declare function updateRawConfigAtomically(scope: Scope, mutate: (latest: RawConfig) => RawConfig): RawConfig;
|
|
14
27
|
export declare function writeConfig(scope: Scope, config: ScopeConfig): void;
|
|
15
|
-
/** Persist a RAW PARTIAL config to a scope's config.json exactly as given.
|
|
16
|
-
* Unlike `writeConfig`, this makes no promise that every field is present --
|
|
17
|
-
* callers pass the sparse partial that should live on disk, so an untouched
|
|
18
|
-
* key stays absent (and `readConfig`/`mergeConfig` re-derive it live from
|
|
19
|
-
* whichever build is running). This is the single central primitive every
|
|
20
|
-
* mutation path funnels through so no writer ever freezes a fully
|
|
21
|
-
* materialized `modelLadders` (concrete model ids that go stale across
|
|
22
|
-
* builds -- the live-Hearth freeze bug) onto disk. */
|
|
23
28
|
export declare function writeRawConfig(scope: Scope, config: Partial<ScopeConfig>): void;
|
|
24
29
|
export declare function writeState(scope: Scope, state: ScopeState): void;
|
|
25
30
|
export declare function ensureScopeInitialized(scope: Scope, root: string): void;
|