@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
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mkdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
2
2
|
import { basename, isAbsolute, resolve } from 'node:path';
|
|
3
|
-
import { randomUUID } from 'node:crypto';
|
|
4
3
|
import { z } from 'zod';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { compilePage, deriveHtmlPageManifest, derivePageManifestFromDocument, parsePage, parsePageDelivery, PageAuthoringError } from './page.js';
|
|
9
|
-
import { isResponseBearingSlot, validatePageResponses, validatePartialPageResponses } from './page-schema.js';
|
|
4
|
+
import { pageModulePath, pagePath } from './convention.js';
|
|
5
|
+
import { parsePage } from './page.js';
|
|
6
|
+
import { validatePageResponses, validatePartialPageResponses } from './page-schema.js';
|
|
10
7
|
import { signalInboxActivity } from './root.js';
|
|
11
|
-
import {
|
|
12
|
-
import { checkReviewableFile } from './visible-paths.js';
|
|
8
|
+
import { createPageRequest, getRequestByDirectory, presentationDir, publishPageRevision, revisePageRequest, writeProgress as writeRequestProgress } from './requests.js';
|
|
13
9
|
const feedbackCommentSchema = z.object({ id: z.string().min(1), line: z.number().int().positive(), endLine: z.number().int().positive(), quote: z.string().optional(), colStart: z.number().int().nonnegative().optional(), colEnd: z.number().int().nonnegative().optional(), lineText: z.string(), comment: z.string().min(1), createdAt: z.string().min(1) }).strict();
|
|
14
10
|
const iso = z.string().datetime({ offset: true });
|
|
15
11
|
const feedbackSchema = z.object({ file: z.string().min(1).refine(isAbsolute, 'file must be absolute').refine((file) => resolve(file) === file, 'file must be canonical'), submitted: z.literal(true), approved: z.boolean(), comments: z.array(feedbackCommentSchema), submittedAt: iso, savedAt: iso, reviewId: z.string().optional(), changed: z.boolean().optional(), baselineSha256: z.string().optional(), approvedSha256: z.string().optional(), companionNodeId: z.string().optional(), commentsTotal: z.number().int().nonnegative().optional(), commentsUnresolved: z.number().int().nonnegative().optional() }).strict().superRefine((result, ctx) => {
|
|
@@ -27,20 +23,21 @@ const pageResultSchema = z.object({ schema: z.literal('crtr.page-response/v1'),
|
|
|
27
23
|
const pageProgressSchema = z.object({ kind: z.literal('page'), responses: z.record(z.string(), slotResponseSchema), savedAt: iso }).strict();
|
|
28
24
|
const reviewResultSchema = z.object({ schema: z.literal('humanloop.review-response/v1'), kind: z.literal('review'), result: feedbackSchema, completedAt: iso }).strict();
|
|
29
25
|
const canceledResultSchema = z.object({ schema: z.literal('humanloop.cancel/v1'), kind: z.literal('canceled'), canceledAt: iso, reason: z.string().optional(), actor: z.string().optional(), disposition: z.enum(['canceled', 'dismissed']).optional() }).strict();
|
|
30
|
-
/** Strict decoder for the
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* of surfacing it to whichever caller owns the failure boundary. */
|
|
26
|
+
/** Strict decoder for the canonical SQL terminal result. A corrupt result throws
|
|
27
|
+
* rather than being treated as absent, because that would hide data loss from
|
|
28
|
+
* the caller that owns the failure boundary. */
|
|
34
29
|
export function readTicketResult(dir) {
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
30
|
+
const request = getRequestByDirectory(dir);
|
|
31
|
+
if (request === null)
|
|
32
|
+
throw new Error(`unknown human request directory: ${dir}`);
|
|
33
|
+
if (request.state !== 'settled' || request.result_json === null)
|
|
37
34
|
return null;
|
|
38
35
|
let raw;
|
|
39
36
|
try {
|
|
40
|
-
raw = JSON.parse(
|
|
37
|
+
raw = JSON.parse(request.result_json);
|
|
41
38
|
}
|
|
42
39
|
catch (error) {
|
|
43
|
-
throw new Error(`corrupt
|
|
40
|
+
throw new Error(`corrupt human request result: ${request.request_id}`, { cause: error });
|
|
44
41
|
}
|
|
45
42
|
const page = pageResultSchema.safeParse(raw);
|
|
46
43
|
if (page.success)
|
|
@@ -49,107 +46,43 @@ export function readTicketResult(dir) {
|
|
|
49
46
|
if (review.success)
|
|
50
47
|
return review.data;
|
|
51
48
|
const canceled = canceledResultSchema.safeParse(raw);
|
|
52
|
-
|
|
49
|
+
if (canceled.success)
|
|
50
|
+
return canceled.data;
|
|
51
|
+
throw new Error(`human request has an invalid terminal result: ${request.request_id}`);
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
return [pageManifestPath(dir), pagePath(dir), pageModulePath(dir), reviewPath(dir), responsePath(dir), progressPath(dir), claimPath(dir)].some(existsSync);
|
|
56
|
-
}
|
|
57
|
-
function publishRequest(path, value) {
|
|
58
|
-
if (!publishJsonExclusive(path, value))
|
|
59
|
-
throw new Error(`ticket request already exists: ${path}`);
|
|
60
|
-
}
|
|
61
|
-
/** Validate one authored page document into publishable form. The single
|
|
62
|
-
* validation path: `preparePage` reads a file and lands here, and a
|
|
63
|
-
* programmatic request supplies the same text inline. */
|
|
64
|
-
export function preparePageSource(opts) {
|
|
65
|
-
const stamped = { ...(opts.source ?? {}), emittedAt: opts.source?.emittedAt ?? new Date().toISOString() };
|
|
66
|
-
const delivery = opts.delivery ?? { placement: 'inline', inbox: false, reply: false };
|
|
67
|
-
if (opts.dialect === 'html')
|
|
68
|
-
return { document: opts.document, manifest: deriveHtmlPageManifest(opts.document, stamped, delivery) };
|
|
69
|
-
return { document: opts.document, module: compilePage(opts.document), manifest: derivePageManifestFromDocument(opts.document, opts.productKinds ?? [], stamped, delivery) };
|
|
70
|
-
}
|
|
71
|
-
/** Validate one authored page source file into publishable form. Reads only: a
|
|
72
|
-
* page that fails authoring leaves nothing behind, so a caller that must create
|
|
73
|
-
* a bridge node prepares first and creates it only once the page is known good.
|
|
74
|
-
* The source is read exactly once, so the published document is the same bytes
|
|
75
|
-
* the manifest was derived from even if the file changes underneath. */
|
|
76
|
-
export function preparePage(opts) {
|
|
77
|
-
const html = /\.html?$/i.test(opts.sourceFile);
|
|
78
|
-
if (!html && !opts.sourceFile.endsWith('.tsx'))
|
|
79
|
-
throw new PageAuthoringError(`page source file must be .tsx, .html, or .htm: ${opts.sourceFile}`);
|
|
80
|
-
if (!existsSync(opts.sourceFile))
|
|
81
|
-
throw new PageAuthoringError(`page source file does not exist: ${opts.sourceFile}`);
|
|
82
|
-
const { sourceFile: _sourceFile, ...rest } = opts;
|
|
83
|
-
return preparePageSource({ ...rest, dialect: html ? 'html' : 'jsx', document: readFileSync(opts.sourceFile, 'utf8') });
|
|
84
|
-
}
|
|
85
|
-
/** Remove a stale generation file. The manifest always switches first, so a
|
|
86
|
-
* failed cleanup leaves one valid current record plus harmless old source. */
|
|
87
|
-
function unlinkIfPresent(path) {
|
|
88
|
-
try {
|
|
89
|
-
unlinkSync(path);
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
if (error.code !== 'ENOENT')
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/** Publish one prepared page ticket: the authored source plus its manifest.
|
|
97
|
-
* These writes are overwrites. A ticket's REQUEST is whatever page the agent
|
|
98
|
-
* currently wants on screen, and `crtr human send --replace` revises it in
|
|
99
|
-
* place while the human watches; only the ANSWER is write-once, which
|
|
100
|
-
* `publishJsonExclusive` still guarantees for response.json alone. The manifest
|
|
101
|
-
* switches after all new generation files exist, then stale media is removed. */
|
|
53
|
+
/** Publish an immutable revision, then atomically select it with its matching specification. */
|
|
102
54
|
export function publishPage(dir, prepared) {
|
|
103
55
|
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
104
56
|
const ticket = realpathSync(dir);
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
unlinkIfPresent(pagePath(ticket, 'html'));
|
|
111
|
-
else {
|
|
112
|
-
unlinkIfPresent(pagePath(ticket, 'jsx'));
|
|
113
|
-
unlinkIfPresent(pageModulePath(ticket));
|
|
57
|
+
const request = getRequestByDirectory(ticket);
|
|
58
|
+
if (request === null) {
|
|
59
|
+
const created = createPageRequest({ request_id: basename(ticket), prepared });
|
|
60
|
+
signalInboxActivity();
|
|
61
|
+
return { id: created.request_id, dir: created.request_dir, kind: 'page', manifest: prepared.manifest };
|
|
114
62
|
}
|
|
115
|
-
|
|
116
|
-
|
|
63
|
+
const revision = publishPageRevision(ticket, prepared);
|
|
64
|
+
if (!revisePageRequest(request.request_id, {
|
|
65
|
+
presentation_dir: revision,
|
|
66
|
+
specification_json: JSON.stringify(prepared.manifest),
|
|
67
|
+
title: prepared.manifest.title,
|
|
68
|
+
subtitle: prepared.manifest.subtitle ?? null,
|
|
69
|
+
inbox_listed: prepared.manifest.delivery.inbox,
|
|
70
|
+
settleable: prepared.manifest.delivery.inbox || prepared.manifest.delivery.reply,
|
|
71
|
+
}))
|
|
72
|
+
throw new Error(`page request is not open: ${request.request_id}`);
|
|
117
73
|
signalInboxActivity();
|
|
118
|
-
return { id:
|
|
74
|
+
return { id: request.request_id, dir: ticket, kind: 'page', manifest: prepared.manifest };
|
|
119
75
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return publishPage(opts.dir, preparePage(opts));
|
|
76
|
+
function pageRequest(dir) {
|
|
77
|
+
const request = getRequestByDirectory(dir);
|
|
78
|
+
if (request === null || request.kind !== 'page')
|
|
79
|
+
throw new Error(`unknown page request directory: ${dir}`);
|
|
80
|
+
return request;
|
|
126
81
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// and source code renders as a syntax-highlighted code panel.
|
|
130
|
-
if (!isAbsolute(opts.review.file) || !existsSync(opts.review.file))
|
|
131
|
-
throw new Error('review file must be an existing absolute path');
|
|
132
|
-
const reviewable = checkReviewableFile(opts.review.file);
|
|
133
|
-
if (!reviewable.ok)
|
|
134
|
-
throw new Error(`review file is not reviewable: ${reviewable.reason}`);
|
|
135
|
-
const source = realpathSync(opts.review.file);
|
|
136
|
-
mkdirSync(opts.dir, { recursive: true, mode: 0o700 });
|
|
137
|
-
const dir = realpathSync(opts.dir);
|
|
138
|
-
if (hasTicketProtocolState(dir))
|
|
139
|
-
throw new Error(`ticket protocol state already exists: ${dir}`);
|
|
140
|
-
const descriptor = validateReviewProjection(dir, { schema: 'humanloop.review/v1', file: source, output: resolve(opts.review.output ?? `${dir}/feedback.json`), title: opts.review.title, subtitle: opts.review.subtitle, source: opts.review.source, blockedSince: opts.review.blockedSince ?? new Date().toISOString() });
|
|
141
|
-
publishRequest(reviewPath(dir), descriptor);
|
|
142
|
-
signalInboxActivity();
|
|
143
|
-
return { id: basename(dir), dir, kind: 'review' };
|
|
144
|
-
}
|
|
145
|
-
function exclusiveResult(dir, result) {
|
|
146
|
-
return publishJsonExclusive(responsePath(dir), result);
|
|
147
|
-
}
|
|
148
|
-
function requireReview(dir) { return validateReviewDescriptor(JSON.parse(readFileSync(reviewPath(dir), 'utf8'))); }
|
|
82
|
+
/** Resolve a stable request directory to the SQL-selected immutable page revision. */
|
|
83
|
+
export function selectedPageDir(dir) { return presentationDir(pageRequest(dir)); }
|
|
149
84
|
function requirePage(dir) {
|
|
150
|
-
|
|
151
|
-
throw new Error(`not a page ticket: ${dir}`);
|
|
152
|
-
return parsePage(dir);
|
|
85
|
+
return parsePage(selectedPageDir(dir));
|
|
153
86
|
}
|
|
154
87
|
function requireSettleablePage(dir) {
|
|
155
88
|
const manifest = requirePage(dir);
|
|
@@ -157,166 +90,82 @@ function requireSettleablePage(dir) {
|
|
|
157
90
|
throw new Error('page_has_no_response_lifecycle');
|
|
158
91
|
return manifest;
|
|
159
92
|
}
|
|
160
|
-
function requireCancelablePage(dir) {
|
|
161
|
-
// Cancellation never interprets answers. Reading only this stable envelope
|
|
162
|
-
// keeps an older resident daemon able to retract a page authored by a newer CLI.
|
|
163
|
-
const delivery = parsePageDelivery(dir);
|
|
164
|
-
if (!delivery.inbox && !delivery.reply)
|
|
165
|
-
throw new Error('page_has_no_response_lifecycle');
|
|
166
|
-
}
|
|
167
93
|
function isEmptyResponseMap(responses) {
|
|
168
94
|
return typeof responses === 'object' && responses !== null && !Array.isArray(responses) && Object.keys(responses).length === 0;
|
|
169
95
|
}
|
|
170
96
|
/** Validate a final page response against its ticket's reply contract. */
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
// An inbox-only page accepts an empty acknowledgement without requiring an answer
|
|
174
|
-
// from every response-bearing component.
|
|
175
|
-
if (!manifest.delivery.reply && isEmptyResponseMap(responses)) {
|
|
97
|
+
export function validateFinalPageResponses(manifest, responses) {
|
|
98
|
+
if (!manifest.delivery.reply && isEmptyResponseMap(responses))
|
|
176
99
|
return validatePartialPageResponses(manifest, responses);
|
|
177
|
-
}
|
|
178
100
|
return validatePageResponses(manifest, responses);
|
|
179
101
|
}
|
|
180
|
-
|
|
102
|
+
function validateFinalPageTicketResponses(dir, responses) {
|
|
103
|
+
return validateFinalPageResponses(requireSettleablePage(dir), responses);
|
|
104
|
+
}
|
|
105
|
+
/** Validate a page resolution against its SQL-selected immutable revision. */
|
|
181
106
|
export function validatePageTicketResponses(dir, responses) {
|
|
182
|
-
|
|
183
|
-
return validateFinalPageTicketResponses(ticket, responses);
|
|
107
|
+
return validateFinalPageTicketResponses(dir, responses);
|
|
184
108
|
}
|
|
185
|
-
/**
|
|
109
|
+
/** Page state is derived from the SQL request row. */
|
|
186
110
|
export function pageTicketState(dir) {
|
|
187
|
-
const
|
|
188
|
-
if (!
|
|
111
|
+
const request = pageRequest(dir);
|
|
112
|
+
if (!request.settleable)
|
|
189
113
|
return 'passive';
|
|
190
|
-
|
|
191
|
-
if (result === null)
|
|
114
|
+
if (request.state !== 'settled')
|
|
192
115
|
return 'pending';
|
|
193
|
-
return
|
|
194
|
-
}
|
|
195
|
-
function readPageProgressFor(dir, manifest) {
|
|
196
|
-
let raw;
|
|
197
|
-
try {
|
|
198
|
-
raw = JSON.parse(readFileSync(progressPath(dir), 'utf8'));
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
if (error.code === 'ENOENT')
|
|
202
|
-
return null;
|
|
203
|
-
throw new Error(`page progress is not valid JSON: ${progressPath(dir)}`);
|
|
204
|
-
}
|
|
205
|
-
const parsed = pageProgressSchema.safeParse(raw);
|
|
206
|
-
if (!parsed.success)
|
|
207
|
-
throw new Error(`page progress is malformed: ${progressPath(dir)}`);
|
|
208
|
-
// A pending page's request can be replaced under saved work, so progress may
|
|
209
|
-
// name a component the current page no longer declares. Those entries are dropped
|
|
210
|
-
// and everything still declared hydrates; what remains is validated, so a
|
|
211
|
-
// saved answer that no longer fits its own component is still an error.
|
|
212
|
-
const declared = new Set(manifest.slots.filter(isResponseBearingSlot).map((slot) => slot.id));
|
|
213
|
-
const current = Object.fromEntries(Object.entries(parsed.data.responses).filter(([id]) => declared.has(id)));
|
|
214
|
-
return validatePartialPageResponses(manifest, current);
|
|
116
|
+
return request.outcome === 'canceled' || request.outcome === 'dismissed' ? 'canceled' : 'resolved';
|
|
215
117
|
}
|
|
216
118
|
/** Autosave partial page work. Every supplied response is validated; omitted components are permitted. */
|
|
217
119
|
export function writePageProgress(dir, responses) {
|
|
218
|
-
const
|
|
219
|
-
const validated = validatePartialPageResponses(requireSettleablePage(
|
|
220
|
-
|
|
120
|
+
const request = pageRequest(dir);
|
|
121
|
+
const validated = validatePartialPageResponses(requireSettleablePage(dir), responses);
|
|
122
|
+
if (!writeRequestProgress(request.inbox_ticket_id, validated))
|
|
123
|
+
throw new Error(`page request is not open and settleable: ${request.request_id}`);
|
|
221
124
|
return validated;
|
|
222
125
|
}
|
|
223
|
-
/** Saved partial work, or null when none exists.
|
|
126
|
+
/** Saved partial work from the request row, or null when none exists. */
|
|
224
127
|
export function readPageProgress(dir) {
|
|
225
|
-
const
|
|
226
|
-
|
|
128
|
+
const request = pageRequest(dir);
|
|
129
|
+
if (request.progress_json === null)
|
|
130
|
+
return null;
|
|
131
|
+
try {
|
|
132
|
+
const progress = JSON.parse(request.progress_json);
|
|
133
|
+
if (progress.kind !== 'page')
|
|
134
|
+
throw new Error('wrong kind');
|
|
135
|
+
return progress.responses;
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
throw new Error(`page progress is malformed for ${request.request_id}`, { cause: error });
|
|
139
|
+
}
|
|
227
140
|
}
|
|
228
141
|
/** Read one addressable page ticket — pending, resolved or canceled alike. */
|
|
229
142
|
export function readPageTicket(dir) {
|
|
230
|
-
const
|
|
231
|
-
const
|
|
143
|
+
const request = pageRequest(dir);
|
|
144
|
+
const presentation = presentationDir(request);
|
|
145
|
+
const manifest = parsePage(presentation);
|
|
232
146
|
return {
|
|
233
|
-
dir:
|
|
234
|
-
id:
|
|
147
|
+
dir: request.request_dir,
|
|
148
|
+
id: request.request_id,
|
|
235
149
|
manifest,
|
|
236
|
-
document: readFileSync(pagePath(
|
|
237
|
-
...(manifest.dialect === 'jsx' ? { module: readFileSync(pageModulePath(
|
|
238
|
-
state: pageTicketState(
|
|
239
|
-
progress: manifest.delivery.inbox || manifest.delivery.reply ?
|
|
150
|
+
document: readFileSync(pagePath(presentation, manifest.dialect), 'utf8'),
|
|
151
|
+
...(manifest.dialect === 'jsx' ? { module: readFileSync(pageModulePath(presentation), 'utf8') } : { module: undefined }),
|
|
152
|
+
state: pageTicketState(request.request_dir),
|
|
153
|
+
progress: manifest.delivery.inbox || manifest.delivery.reply ? readPageProgress(request.request_dir) : null,
|
|
240
154
|
};
|
|
241
155
|
}
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
}
|
|
246
|
-
function clearOwnedWork(dir, claimToken) { clearProgress(dir); releaseClaimLocked(dir, claimToken); }
|
|
247
|
-
/** Caller holds `.ticket-lock`. */
|
|
248
|
-
function completePageLocked(dir, responses, claimToken, opts) {
|
|
249
|
-
requireClaimOwnership(dir, claimToken);
|
|
250
|
-
const manifest = requirePage(dir);
|
|
251
|
-
const parsedResponses = validateFinalPageTicketResponses(dir, responses);
|
|
252
|
-
const result = { schema: 'crtr.page-response/v1', kind: 'page', responses: parsedResponses, summary: buildPageSummary(manifest, parsedResponses), completedAt: opts.completedAt ?? new Date().toISOString(), ...(opts.actor === undefined ? {} : { actor: opts.actor }) };
|
|
253
|
-
const won = exclusiveResult(dir, result);
|
|
254
|
-
clearOwnedWork(dir, claimToken);
|
|
255
|
-
// Lost the race: the winner's result must already be on disk, so a null read
|
|
256
|
-
// here is an anomaly worth surfacing rather than silently falling back to
|
|
257
|
-
// this loser's own uncommitted result.
|
|
258
|
-
return { won, result: won ? result : (readTicketResult(dir) ?? (() => { throw new Error(`lost the completion race but no winning result is on disk: ${dir}`); })()) };
|
|
259
|
-
}
|
|
260
|
-
export function completePage(dir, responses, claimToken, opts = {}) {
|
|
261
|
-
const ticket = requireTicket(dir);
|
|
262
|
-
const completed = withTicketLock(ticket, () => completePageLocked(ticket, responses, claimToken, opts));
|
|
263
|
-
if (completed.won)
|
|
264
|
-
signalInboxActivity();
|
|
265
|
-
return completed;
|
|
266
|
-
}
|
|
267
|
-
function takeoverClaim(dir, owner) {
|
|
268
|
-
const existing = readTicketClaim(dir);
|
|
269
|
-
if (existing !== null)
|
|
270
|
-
unlinkSync(claimPath(dir));
|
|
271
|
-
const token = randomUUID();
|
|
272
|
-
const now = new Date().toISOString();
|
|
273
|
-
writeFileSync(claimPath(dir), `${JSON.stringify({ token, host: owner.host, pid: owner.pid, claimedAt: now, heartbeatAt: now })}\n`, { flag: 'wx', mode: 0o600 });
|
|
274
|
-
return token;
|
|
156
|
+
/** Page settlement must go through daemon/human/finish, which records its SQL result and direct obligations together. */
|
|
157
|
+
export function completePage(_dir, _responses, _claimToken, _opts = {}) {
|
|
158
|
+
throw new Error('page completion must use settleHumanRequest');
|
|
275
159
|
}
|
|
276
|
-
/**
|
|
277
|
-
export function takeoverAndCompletePage(
|
|
278
|
-
|
|
279
|
-
const completed = withTicketLock(ticket, () => {
|
|
280
|
-
const token = takeoverClaim(ticket, owner);
|
|
281
|
-
try {
|
|
282
|
-
return completePageLocked(ticket, responses, token, opts);
|
|
283
|
-
}
|
|
284
|
-
finally {
|
|
285
|
-
releaseClaimLocked(ticket, token);
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
if (completed.won)
|
|
289
|
-
signalInboxActivity();
|
|
290
|
-
return completed;
|
|
160
|
+
/** Page settlement must go through daemon/human/finish, which records its SQL result and direct obligations together. */
|
|
161
|
+
export function takeoverAndCompletePage(_dir, _responses, _owner, _opts = {}) {
|
|
162
|
+
throw new Error('page completion must use settleHumanRequest');
|
|
291
163
|
}
|
|
292
|
-
/**
|
|
293
|
-
export function cancelTicket(
|
|
294
|
-
|
|
295
|
-
const canceled = withTicketLock(ticket, () => {
|
|
296
|
-
if (existsSync(pageManifestPath(ticket)))
|
|
297
|
-
requireCancelablePage(ticket);
|
|
298
|
-
const result = { schema: 'humanloop.cancel/v1', kind: 'canceled', canceledAt: new Date().toISOString(), ...(opts.reason === undefined ? {} : { reason: opts.reason }), ...(opts.actor === undefined ? {} : { actor: opts.actor }), ...(opts.disposition === undefined ? {} : { disposition: opts.disposition }) };
|
|
299
|
-
const won = exclusiveResult(ticket, result);
|
|
300
|
-
// Same anomaly as completePageLocked: losing the race with no winning
|
|
301
|
-
// result on disk means the ticket state is broken, not just contended.
|
|
302
|
-
return {
|
|
303
|
-
status: won ? 'canceled' : 'already_resolved',
|
|
304
|
-
result: won ? result : (readTicketResult(ticket) ?? (() => { throw new Error(`lost the cancellation race but no winning result is on disk: ${ticket}`); })()),
|
|
305
|
-
};
|
|
306
|
-
});
|
|
307
|
-
if (canceled.status === 'canceled')
|
|
308
|
-
signalInboxActivity();
|
|
309
|
-
return canceled;
|
|
164
|
+
/** Page settlement must go through daemon/human/finish, which records its SQL result and direct obligations together. */
|
|
165
|
+
export function cancelTicket(_dir, _opts = {}) {
|
|
166
|
+
throw new Error('page cancellation must use settleHumanRequest');
|
|
310
167
|
}
|
|
311
|
-
/**
|
|
312
|
-
export function projectReviewOutput(
|
|
313
|
-
|
|
314
|
-
if (result === null)
|
|
315
|
-
return 'no_result';
|
|
316
|
-
if (result.kind !== 'review')
|
|
317
|
-
return 'not_a_review';
|
|
318
|
-
const ticket = requireTicket(dir);
|
|
319
|
-
const descriptor = validateReviewProjection(ticket, requireReview(ticket));
|
|
320
|
-
atomicWriteJson(descriptor.output, result.result);
|
|
321
|
-
return 'projected';
|
|
168
|
+
/** Review projection is performed by daemon/review/finish after its SQL terminal transition. */
|
|
169
|
+
export function projectReviewOutput(_dir) {
|
|
170
|
+
throw new Error('review projection must use projectReviewResult');
|
|
322
171
|
}
|
|
@@ -36,6 +36,8 @@ export interface ClaimSummary {
|
|
|
36
36
|
interface TicketSummaryBase {
|
|
37
37
|
dir: string;
|
|
38
38
|
id: string;
|
|
39
|
+
/** Stored opaque inbox identity. It may differ from `id` after legacy migration. */
|
|
40
|
+
inboxTicketId: string;
|
|
39
41
|
title: string;
|
|
40
42
|
subtitle: string;
|
|
41
43
|
blockedSince: string;
|
|
@@ -51,6 +53,8 @@ export interface ReviewTicketSummary extends TicketSummaryBase {
|
|
|
51
53
|
export interface PageTicketSummary {
|
|
52
54
|
dir: string;
|
|
53
55
|
id: string;
|
|
56
|
+
/** Stored opaque inbox identity. It may differ from `id` after legacy migration. */
|
|
57
|
+
inboxTicketId: string;
|
|
54
58
|
kind: 'page';
|
|
55
59
|
title: string;
|
|
56
60
|
subtitle: string;
|
|
@@ -109,6 +113,6 @@ export interface CanceledTicketResult {
|
|
|
109
113
|
* requester (`canceled`). Absent on records written before the field. */
|
|
110
114
|
disposition?: 'canceled' | 'dismissed';
|
|
111
115
|
}
|
|
112
|
-
/** The
|
|
116
|
+
/** The canonical terminal-result union stored in the human request row. */
|
|
113
117
|
export type TicketResult = PageTicketResult | ReviewTicketResult | CanceledTicketResult;
|
|
114
118
|
export {};
|
|
@@ -12,8 +12,13 @@ import { CONFIG_FILE } from '../types.js';
|
|
|
12
12
|
import { listDirs, pathExists, readJsonIfExists } from './fs-utils.js';
|
|
13
13
|
import { readPluginManifest } from './manifest.js';
|
|
14
14
|
import { awaitBundleSwap, bundleSwapInFlightElsewhere } from './plugin-swap-lock.js';
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
import { userStore } from './scoped-state/paths.js';
|
|
16
|
+
import { readRawSettings } from './scoped-state/settings.js';
|
|
17
|
+
function pluginConfigForRoot(scope, root) {
|
|
18
|
+
const store = scope === 'user' ? userStore(root) : undefined;
|
|
19
|
+
const cfg = store
|
|
20
|
+
? readRawSettings({ store, key: 'user', kind: 'user', root: store.root })
|
|
21
|
+
: readJsonIfExists(join(root, CONFIG_FILE));
|
|
17
22
|
return cfg && cfg.plugins && typeof cfg.plugins === 'object' ? cfg.plugins : {};
|
|
18
23
|
}
|
|
19
24
|
/**
|
|
@@ -38,7 +43,7 @@ export function listInstalledPluginsInRoot(scope, scopeRootPath) {
|
|
|
38
43
|
const dir = join(scopeRootPath, 'plugins');
|
|
39
44
|
if (!pathExists(dir))
|
|
40
45
|
return [];
|
|
41
|
-
const cfg = pluginConfigForRoot(scopeRootPath);
|
|
46
|
+
const cfg = pluginConfigForRoot(scope, scopeRootPath);
|
|
42
47
|
const first = collectInstalledPlugins(scope, dir, cfg);
|
|
43
48
|
const waiting = swapsToWaitOut(scopeRootPath, cfg, new Set(first.map((plugin) => plugin.name)));
|
|
44
49
|
if (waiting.length === 0)
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { after, before, beforeEach, test } from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { mkdtempSync, mkdirSync,
|
|
3
|
+
import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
6
|
import { KeybindingConcurrentEditError, KeybindingValidationError, canonicalTerminalStroke, matchesTerminalInput, normalizeSparseOverrides, persistUserKeybindings, resolveKeybindings, resolveUserKeybindings, } from '../index.js';
|
|
7
|
-
import { readConfig } from '../../config.js';
|
|
7
|
+
import { ensureScopeInitialized, readConfig, readRawScopeConfig, updateRawConfigAtomically, writeRawConfig } from '../../config.js';
|
|
8
|
+
import { closeScopedStores } from '../../scoped-state/db.js';
|
|
9
|
+
import { resetScopeCache } from '../../scope.js';
|
|
8
10
|
const typeCheckedBindingId = 'crtr.graph.down';
|
|
9
11
|
// @ts-expect-error The catalog type rejects IDs that are not built in.
|
|
10
12
|
const rejectedBindingId = 'crtr.graph.not-real';
|
|
@@ -24,15 +26,21 @@ beforeEach(() => {
|
|
|
24
26
|
home = mkdtempSync(join(tmpdir(), 'crtr-keybindings-'));
|
|
25
27
|
process.env['HOME'] = home;
|
|
26
28
|
process.chdir(realCwd);
|
|
29
|
+
resetScopeCache();
|
|
30
|
+
ensureScopeInitialized('user', join(home, '.crouter'));
|
|
27
31
|
});
|
|
28
32
|
after(() => {
|
|
33
|
+
closeScopedStores();
|
|
29
34
|
process.chdir(realCwd);
|
|
30
35
|
if (realHome === undefined)
|
|
31
36
|
delete process.env['HOME'];
|
|
32
37
|
else
|
|
33
38
|
process.env['HOME'] = realHome;
|
|
34
39
|
});
|
|
35
|
-
test.afterEach(() =>
|
|
40
|
+
test.afterEach(() => {
|
|
41
|
+
closeScopedStores();
|
|
42
|
+
rmSync(home, { recursive: true, force: true });
|
|
43
|
+
});
|
|
36
44
|
test('terminal literal space matches named space bindings', () => {
|
|
37
45
|
const raw = { input: ' ' };
|
|
38
46
|
assert.equal(canonicalTerminalStroke(raw), 'space');
|
|
@@ -106,8 +114,7 @@ test('sparsification omits defaults, preserves explicit unbinds, and reset remov
|
|
|
106
114
|
assert.throws(() => normalizeSparseOverrides({ 'crtr.graph.down': ['k'] }), KeybindingValidationError);
|
|
107
115
|
});
|
|
108
116
|
test('user resolution ignores project keybindings', () => {
|
|
109
|
-
|
|
110
|
-
writeFileSync(join(home, '.crouter', 'config.json'), JSON.stringify({ keybindings: { 'crtr.graph.down': ['down'] } }));
|
|
117
|
+
writeRawConfig('user', { keybindings: { 'crtr.graph.down': ['down'] } });
|
|
111
118
|
const project = mkdtempSync(join(tmpdir(), 'crtr-keybindings-project-'));
|
|
112
119
|
mkdirSync(join(project, '.crouter'), { recursive: true });
|
|
113
120
|
writeFileSync(join(project, '.crouter', 'config.json'), JSON.stringify({ keybindings: { 'crtr.graph.down': ['up'] } }));
|
|
@@ -121,8 +128,7 @@ test('user resolution ignores project keybindings', () => {
|
|
|
121
128
|
}
|
|
122
129
|
});
|
|
123
130
|
test('config hard cut exposes only sparse keybindings and ignores unsupported raw fields', () => {
|
|
124
|
-
|
|
125
|
-
writeFileSync(join(home, '.crouter', 'config.json'), JSON.stringify({
|
|
131
|
+
updateRawConfigAtomically('user', () => ({
|
|
126
132
|
canvasNav: { prefixKey: 'alt+x' },
|
|
127
133
|
keybindings: { 'crtr.graph.down': ['down'], bad: 3 },
|
|
128
134
|
}));
|
|
@@ -131,9 +137,7 @@ test('config hard cut exposes only sparse keybindings and ignores unsupported ra
|
|
|
131
137
|
assert.equal(Object.hasOwn(config, 'canvasNav'), false);
|
|
132
138
|
});
|
|
133
139
|
test('atomic persistence preserves latest unrelated fields and writes only sparse normalized overrides', () => {
|
|
134
|
-
|
|
135
|
-
const path = join(home, '.crouter', 'config.json');
|
|
136
|
-
writeFileSync(path, JSON.stringify({
|
|
140
|
+
updateRawConfigAtomically('user', () => ({
|
|
137
141
|
customFutureField: { retained: true },
|
|
138
142
|
max_panes_per_window: 4,
|
|
139
143
|
canvasNav: { prefixKey: 'alt+z' },
|
|
@@ -143,7 +147,7 @@ test('atomic persistence preserves latest unrelated fields and writes only spars
|
|
|
143
147
|
'crtr.graph.close-subtree': [],
|
|
144
148
|
'crtr.graph.down': ['j'],
|
|
145
149
|
});
|
|
146
|
-
const raw =
|
|
150
|
+
const raw = readRawScopeConfig('user');
|
|
147
151
|
assert.deepEqual(raw.customFutureField, { retained: true });
|
|
148
152
|
assert.equal(raw.max_panes_per_window, 4);
|
|
149
153
|
assert.deepEqual(raw.keybindings, {
|
|
@@ -153,17 +157,15 @@ test('atomic persistence preserves latest unrelated fields and writes only spars
|
|
|
153
157
|
assert.equal(raw.canvasNav, undefined);
|
|
154
158
|
});
|
|
155
159
|
test('reset-all removes the top-level member and concurrent keybinding edits are refused', () => {
|
|
156
|
-
mkdirSync(join(home, '.crouter'), { recursive: true });
|
|
157
|
-
const path = join(home, '.crouter', 'config.json');
|
|
158
160
|
const original = { 'crtr.graph.down': ['down'] };
|
|
159
|
-
|
|
161
|
+
updateRawConfigAtomically('user', () => ({ keybindings: original, retained: 1 }));
|
|
160
162
|
persistUserKeybindings({}, { expectedKeybindings: original });
|
|
161
|
-
let raw =
|
|
163
|
+
let raw = readRawScopeConfig('user');
|
|
162
164
|
assert.equal(raw.keybindings, undefined);
|
|
163
165
|
assert.equal(raw.retained, 1);
|
|
164
|
-
|
|
166
|
+
updateRawConfigAtomically('user', () => ({ keybindings: { 'crtr.graph.up': ['up'] }, retained: 2 }));
|
|
165
167
|
assert.throws(() => persistUserKeybindings({}, { expectedKeybindings: original }), KeybindingConcurrentEditError);
|
|
166
|
-
raw =
|
|
168
|
+
raw = readRawScopeConfig('user');
|
|
167
169
|
assert.deepEqual(raw.keybindings, { 'crtr.graph.up': ['up'] });
|
|
168
170
|
assert.equal(raw.retained, 2);
|
|
169
171
|
});
|
|
@@ -6,8 +6,9 @@ export type LockResult<T> = {
|
|
|
6
6
|
* from INSIDE the critical section must call it immediately before that write, because the
|
|
7
7
|
* post-`fn` check cannot un-write a file the callback already replaced. */
|
|
8
8
|
export type LockHeldGuard = () => void;
|
|
9
|
+
export type LockedFilePublish = (next: string) => void;
|
|
9
10
|
export interface LockedFileBackend {
|
|
10
|
-
withLockAsync<T>(fn: (current: string | undefined, assertLockHeld: LockHeldGuard) => Promise<LockResult<T>>): Promise<T>;
|
|
11
|
+
withLockAsync<T>(fn: (current: string | undefined, assertLockHeld: LockHeldGuard, publish: LockedFilePublish) => Promise<LockResult<T>>): Promise<T>;
|
|
11
12
|
/** The current whole-file contents, or undefined when the file does not exist yet.
|
|
12
13
|
* Lock-free: every writer replaces the file by atomic rename. */
|
|
13
14
|
readUnlocked(): string | undefined;
|
|
@@ -15,10 +16,12 @@ export interface LockedFileBackend {
|
|
|
15
16
|
/** A 0600 JSON file guarded by a cross-process `proper-lockfile` lock on its own path. */
|
|
16
17
|
export declare class LockedJsonFile implements LockedFileBackend {
|
|
17
18
|
private readonly path;
|
|
18
|
-
|
|
19
|
+
private readonly durable;
|
|
20
|
+
private readonly initialContent;
|
|
21
|
+
constructor(path: string, durable?: boolean, initialContent?: string);
|
|
19
22
|
readUnlocked(): string | undefined;
|
|
20
23
|
private ensureFile;
|
|
21
24
|
/** Acquire the lock without blocking the event loop, keeping every read-modify-write
|
|
22
25
|
* callback on the same asynchronous path. */
|
|
23
|
-
withLockAsync<T>(fn: (current: string | undefined, assertLockHeld: LockHeldGuard) => Promise<LockResult<T>>): Promise<T>;
|
|
26
|
+
withLockAsync<T>(fn: (current: string | undefined, assertLockHeld: LockHeldGuard, publish: LockedFilePublish) => Promise<LockResult<T>>): Promise<T>;
|
|
24
27
|
}
|