@north-light/crouter 0.3.312 → 0.3.314
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 +757 -746
- package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
- package/dist/clients/inbox/controller.d.ts +42 -14
- package/dist/clients/inbox/controller.js +240 -124
- package/dist/clients/inbox/dto-adapt.d.ts +28 -0
- package/dist/clients/inbox/dto-adapt.js +93 -0
- package/dist/clients/inbox/page-adapter.d.ts +5 -4
- package/dist/clients/inbox/page-adapter.js +12 -12
- package/dist/clients/inbox/resolve.d.ts +10 -5
- package/dist/clients/inbox/resolve.js +13 -12
- package/dist/clients/inbox/review/review-client.d.ts +0 -1
- package/dist/clients/inbox/review/review-client.js +0 -4
- package/dist/clients/inbox/review-adapter.d.ts +2 -1
- package/dist/clients/inbox/review-adapter.js +3 -5
- package/dist/clients/inbox/surface.d.ts +2 -2
- package/dist/clients/inbox/surface.js +19 -8
- package/dist/clients/inbox/tui.d.ts +3 -3
- package/dist/commands/__tests__/human.test.js +31 -15
- package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
- package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
- package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
- package/dist/commands/api-client.d.ts +5 -4
- package/dist/commands/api-client.js +13 -7
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-roster.js +1 -1
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/human/feedback.js +20 -17
- package/dist/commands/human/prompts.js +45 -36
- package/dist/commands/human/queue.js +73 -123
- package/dist/commands/human/review.js +6 -16
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
- package/dist/commands/node-inspect-artifacts.js +1 -1
- package/dist/commands/node-lifecycle-revive.d.ts +2 -2
- package/dist/commands/node-lifecycle-revive.js +9 -19
- package/dist/commands/pkg/plugin-manage.js +0 -1
- package/dist/commands/profile/show.js +4 -12
- package/dist/commands/surface-tmux-spread.js +1 -5
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
- package/dist/commands/sys/branch.d.ts +2 -0
- package/dist/commands/sys/branch.js +19 -0
- package/dist/commands/sys/config.js +106 -33
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/sys/daemon.js +130 -7
- package/dist/commands/sys/doctor.js +5 -15
- package/dist/commands/sys/migrate.js +21 -92
- package/dist/commands/sys/setup-settings-runner.js +4 -2
- package/dist/commands/sys.js +2 -15
- package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
- package/dist/core/__tests__/boot.test.js +32 -25
- package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
- package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
- package/dist/core/__tests__/canvas.test.js +18 -47
- package/dist/core/__tests__/child-death-wake.test.js +29 -7
- package/dist/core/__tests__/cli-help-contract.test.js +2 -0
- package/dist/core/__tests__/close.test.js +29 -10
- package/dist/core/__tests__/collectible.test.js +2 -1
- package/dist/core/__tests__/config-change-delta.test.js +2 -0
- package/dist/core/__tests__/context-intro.test.js +13 -1
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/fresh-home-commands.test.js +49 -0
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
- package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/command.js +11 -0
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +3 -2
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +8 -2
- package/dist/core/runtime/reset.js +22 -6
- package/dist/core/runtime/revive.js +226 -218
- package/dist/core/runtime/spawn.js +14 -3
- package/dist/core/scoped-state/db.d.ts +18 -0
- package/dist/core/scoped-state/db.js +135 -0
- package/dist/core/scoped-state/migrate.d.ts +8 -0
- package/dist/core/scoped-state/migrate.js +181 -0
- package/dist/core/scoped-state/paths.d.ts +9 -0
- package/dist/core/scoped-state/paths.js +27 -0
- package/dist/core/scoped-state/profiles.d.ts +12 -0
- package/dist/core/scoped-state/profiles.js +62 -0
- package/dist/core/scoped-state/providers.d.ts +16 -0
- package/dist/core/scoped-state/providers.js +8 -0
- package/dist/core/scoped-state/schema.d.ts +3 -0
- package/dist/core/scoped-state/schema.js +26 -0
- package/dist/core/scoped-state/settings.d.ts +28 -0
- package/dist/core/scoped-state/settings.js +82 -0
- package/dist/core/subscription-state.d.ts +29 -48
- package/dist/core/subscription-state.js +176 -712
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +2 -2
- package/dist/core/worktree-sweep.js +11 -16
- package/dist/core/worktree.js +6 -12
- package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
- package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
- package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
- package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
- package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -151
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.js +7 -13
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.js +0 -256
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
- package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
- package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
- package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-store.test.js +0 -144
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
- package/dist/core/canvas/human-deliveries.d.ts +0 -39
- package/dist/core/canvas/human-deliveries.js +0 -75
- package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
- package/dist/core/canvas/node-outcome-deliveries.js +0 -159
- package/dist/core/feed/passive.d.ts +0 -3
- package/dist/core/feed/passive.js +0 -53
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
- package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
- package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
- package/dist/core/human/__tests__/page-tickets.test.js +0 -161
- package/dist/core/review/ticket-filter.d.ts +0 -17
- package/dist/core/review/ticket-filter.js +0 -21
- package/dist/core/runtime/broker/passive.d.ts +0 -17
- package/dist/core/runtime/broker/passive.js +0 -44
- package/dist/core/runtime/busy.d.ts +0 -46
- package/dist/core/runtime/busy.js +0 -150
- package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
- package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
- package/dist/daemon/human/deliver-action.d.ts +0 -3
- package/dist/daemon/human/deliver-action.js +0 -9
- package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
- package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
- package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
- package/dist/daemon/startup-block-marker.d.ts +0 -25
- package/dist/daemon/startup-block-marker.js +0 -99
- /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
- /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
- /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
- /package/dist/core/__tests__/{human-deliver.test.d.ts → integration/fresh-home-commands.test.d.ts} +0 -0
|
@@ -1,304 +1,107 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { readTicketActionBinding } from '../../core/human/action-binding.js';
|
|
6
|
-
import { completionEventFor, composeHumanCompletion } from '../../core/human/completion.js';
|
|
7
|
-
import { enqueueActionDelivery } from '../../core/canvas/human-deliveries.js';
|
|
8
|
-
import { parsePage } from '../../core/human/page.js';
|
|
9
|
-
import { cancelTicket, projectReviewOutput, readTicketResult, takeoverAndCompletePage, } from '../../core/human/tickets.js';
|
|
10
|
-
import { describePageAnswer } from '../../core/human/answer.js';
|
|
11
|
-
import { renderAnswerText } from '../../core/human/answer-text.js';
|
|
12
|
-
import { pagePath, readTicketReplyRoute, responsePath } from '../../core/human/convention.js';
|
|
13
|
-
import { readPageFeedback } from '../../core/human/feedback.js';
|
|
14
|
-
import { pageDocumentSha256 } from '../../core/human/feedback-companion.js';
|
|
15
|
-
import { appendInbox } from '../../core/feed/inbox.js';
|
|
16
|
-
import { FinalDeliveryError, pushFinal, pushUpdate } from '../../core/feed/feed.js';
|
|
17
|
-
import { transition } from '../../core/runtime/lifecycle.js';
|
|
18
|
-
import { emitEvent } from '../../core/events/emit.js';
|
|
1
|
+
import { getRequest, getRequestByInboxTicket } from '../../core/human/requests.js';
|
|
2
|
+
import { buildPageSummary } from '../../core/human/summary.js';
|
|
3
|
+
import { validateFinalPageResponses } from '../../core/human/tickets.js';
|
|
4
|
+
import { composeHumanCompletion } from '../../core/human/completion.js';
|
|
19
5
|
import { retireCompanion } from '../companion-retire.js';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const companionNodeId = readPageFeedback(ticketDir(ticketId)).companionNodeId;
|
|
28
|
-
if (companionNodeId !== undefined)
|
|
29
|
-
await retireCompanion(companionNodeId, outcome);
|
|
30
|
-
}
|
|
31
|
-
catch (error) {
|
|
32
|
-
emitEvent({ level: 'warn', event: 'human.feedback_companion.retire_failed', error });
|
|
33
|
-
}
|
|
6
|
+
import { settleHumanRequest } from './settle.js';
|
|
7
|
+
function requestForTicket(ticketId) {
|
|
8
|
+
const request = getRequest(ticketId) ?? getRequestByInboxTicket(ticketId);
|
|
9
|
+
if (request === null || request.kind !== 'page')
|
|
10
|
+
throw new Error(`unknown page request: ${ticketId}`);
|
|
11
|
+
return request;
|
|
34
12
|
}
|
|
35
|
-
|
|
36
|
-
* cancellation alike: a change notice when the final page differs from the
|
|
37
|
-
* version first commented on, and each still-open item's quote and note.
|
|
38
|
-
* Silent when the page is unchanged and no feedback remains open; never a
|
|
39
|
-
* manufactured prose diff. */
|
|
40
|
-
function feedbackAddendum(dir) {
|
|
41
|
-
let sections;
|
|
13
|
+
function manifest(request) {
|
|
42
14
|
try {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (feedback.firstCommentedSha256 !== undefined && pageDocumentSha256(dir) !== feedback.firstCommentedSha256) {
|
|
48
|
-
sections.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${feedback.companionNodeId}) revised it in place. ` +
|
|
49
|
-
`Reread the final page at ${pagePath(dir, 'jsx')} before interpreting this outcome.`);
|
|
50
|
-
}
|
|
51
|
-
const open = feedback.comments.filter((comment) => comment.status === 'open');
|
|
52
|
-
if (open.length > 0) {
|
|
53
|
-
const items = open.map((comment) => [
|
|
54
|
-
...comment.quote.split('\n').map((line) => `> ${line}`),
|
|
55
|
-
comment.note,
|
|
56
|
-
].join('\n'));
|
|
57
|
-
sections.push([
|
|
58
|
-
`Feedback left unresolved at settlement — the companion conversation (node ${feedback.companionNodeId}) had not dealt with these items:`,
|
|
59
|
-
...items,
|
|
60
|
-
].join('\n\n'));
|
|
61
|
-
}
|
|
15
|
+
const value = JSON.parse(request.specification_json);
|
|
16
|
+
if (typeof value !== 'object' || value === null)
|
|
17
|
+
throw new Error('not an object');
|
|
18
|
+
return value;
|
|
62
19
|
}
|
|
63
|
-
catch {
|
|
64
|
-
|
|
65
|
-
return '';
|
|
20
|
+
catch (error) {
|
|
21
|
+
throw new Error(`corrupt page specification: ${request.request_id}`, { cause: error });
|
|
66
22
|
}
|
|
67
|
-
return sections.length === 0 ? '' : `\n\n${sections.join('\n\n')}`;
|
|
68
23
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return [
|
|
72
|
-
'The page manifest could not be read, so the raw response is provided.',
|
|
73
|
-
'',
|
|
74
|
-
JSON.stringify(result.responses),
|
|
75
|
-
'',
|
|
76
|
-
`Response record: ${resultPath}`,
|
|
77
|
-
].join('\n');
|
|
78
|
-
}
|
|
79
|
-
function pageTitle(dir) {
|
|
80
|
-
try {
|
|
81
|
-
return parsePage(dir).title;
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
24
|
+
function completionAction(request, result) {
|
|
25
|
+
if (request.action_json === null)
|
|
84
26
|
return undefined;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/** Person-authored response values, derived from the structured answer rather
|
|
88
|
-
* than display prose. Empty values have no words to attribute. */
|
|
89
|
-
function personWords(answer) {
|
|
90
|
-
if (answer.kind === 'acknowledgement')
|
|
91
|
-
return '';
|
|
92
|
-
const words = [];
|
|
93
|
-
for (const slot of answer.slots) {
|
|
94
|
-
if (slot.state !== 'answered')
|
|
95
|
-
continue;
|
|
96
|
-
if (slot.raw !== undefined) {
|
|
97
|
-
words.push(JSON.stringify(slot.raw));
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
if (slot.text !== undefined) {
|
|
101
|
-
if (slot.text.edited || slot.text.singleLine === true)
|
|
102
|
-
words.push(slot.text.value);
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
for (const group of slot.groups)
|
|
106
|
-
words.push(...group.picked.map((item) => item.label));
|
|
107
|
-
if (slot.freetext !== undefined)
|
|
108
|
-
words.push(slot.freetext);
|
|
109
|
-
words.push(...slot.comments.map((comment) => comment.text));
|
|
110
|
-
}
|
|
111
|
-
return words.filter((word) => word !== '').join('\n\n');
|
|
112
|
-
}
|
|
113
|
-
/** The answer push: the person's words alone when the page captured any, tagged
|
|
114
|
-
* so every reader attributes them to the person without re-deriving it from
|
|
115
|
-
* prose. A page that captured nothing stays an ordinary report carrying the
|
|
116
|
-
* full record, because there is nothing of the person's to attribute. */
|
|
117
|
-
function renderPageAnswer(dir, result, resultPath) {
|
|
118
|
-
let manifest;
|
|
119
27
|
try {
|
|
120
|
-
|
|
28
|
+
const binding = JSON.parse(request.action_json);
|
|
29
|
+
if (binding.schema !== 'crtr.human-action-binding/v1' || !Array.isArray(binding.argv) || typeof binding.cwd !== 'string')
|
|
30
|
+
throw new Error('invalid binding');
|
|
31
|
+
return {
|
|
32
|
+
destinationId: binding.name,
|
|
33
|
+
adapter: { adapter: 'subprocess', argv: binding.argv, cwd: binding.cwd },
|
|
34
|
+
bodyJson: composeHumanCompletion({ requestId: request.request_id, result: result, binding, source: manifest(request).source ?? {} }),
|
|
35
|
+
};
|
|
121
36
|
}
|
|
122
|
-
catch {
|
|
123
|
-
|
|
37
|
+
catch (error) {
|
|
38
|
+
throw new Error(`corrupt frozen completion action: ${request.request_id}`, { cause: error });
|
|
124
39
|
}
|
|
125
|
-
const answer = describePageAnswer(manifest, result.responses, { completedAt: result.completedAt });
|
|
126
|
-
const rendered = renderAnswerText(answer, resultPath);
|
|
127
|
-
const addendum = feedbackAddendum(dir);
|
|
128
|
-
const words = personWords(answer);
|
|
129
|
-
return words === ''
|
|
130
|
-
? { body: rendered + addendum }
|
|
131
|
-
: { body: words, disposition: 'human-answer', ...(addendum === '' ? {} : { feedback: addendum.trim() }) };
|
|
132
40
|
}
|
|
133
|
-
function
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (error instanceof FinalDeliveryError) {
|
|
138
|
-
return new ApiError(500, 'delivery_failed', `The answer is recorded and the bridge node is finalized; its report is at ${error.reportPath}. Notifying ${error.failedTo.join(', ')} failed and will not be retried.`);
|
|
139
|
-
}
|
|
140
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
141
|
-
return new ApiError(500, 'delivery_failed', `The answer is recorded and delivery will be retried: ${detail}`);
|
|
41
|
+
function notification(request, disposition, bodyJson) {
|
|
42
|
+
if (request.requester_node_id === null)
|
|
43
|
+
return undefined;
|
|
44
|
+
return { label: disposition === 'human-answer' ? 'human request answered' : 'human request canceled', disposition, body_json: bodyJson };
|
|
142
45
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await deliverTerminalResult(ticketId);
|
|
146
|
-
}
|
|
147
|
-
catch (error) {
|
|
148
|
-
throw deliveryFailed(error);
|
|
149
|
-
}
|
|
150
|
-
throw new ApiError(409, 'ticket_already_resolved', 'ticket already resolved');
|
|
46
|
+
function retire(request) {
|
|
47
|
+
return request.companion_node_id === null ? undefined : { retire: async (nodeId, outcome) => { await retireCompanion(nodeId, outcome); } };
|
|
151
48
|
}
|
|
152
|
-
/**
|
|
153
|
-
* The one completion path for a page ticket: claim takeover, exclusive result
|
|
154
|
-
* publication, then optional reply delivery. Every addressing surface routes
|
|
155
|
-
* through this function, so the reply-route descriptor is the sole authority
|
|
156
|
-
* on whether completion reaches a bridge.
|
|
157
|
-
*/
|
|
49
|
+
/** Settle a page request directly in human_requests; result files and bridge nodes are not part of this path. */
|
|
158
50
|
export async function resolvePageTicket(ticketId, responses, opts = {}) {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
51
|
+
const request = requestForTicket(ticketId);
|
|
52
|
+
const page = manifest(request);
|
|
53
|
+
const parsedResponses = validateFinalPageResponses(page, responses);
|
|
54
|
+
const result = {
|
|
55
|
+
schema: 'crtr.page-response/v1', kind: 'page', responses: parsedResponses,
|
|
56
|
+
summary: buildPageSummary(page, parsedResponses), completedAt: opts.completedAt ?? new Date().toISOString(),
|
|
57
|
+
...(opts.actor === undefined ? {} : { actor: opts.actor }),
|
|
58
|
+
};
|
|
59
|
+
const settled = await settleHumanRequest({
|
|
60
|
+
request_id: request.request_id,
|
|
61
|
+
outcome: 'answered',
|
|
62
|
+
result_json: JSON.stringify(result),
|
|
63
|
+
...(notification(request, 'human-answer', result) === undefined ? {} : { notification: notification(request, 'human-answer', result) }),
|
|
64
|
+
...(completionAction(request, result) === undefined ? {} : { completion_action: completionAction(request, result) }),
|
|
65
|
+
...(retire(request) === undefined ? {} : { post_commit: retire(request) }),
|
|
66
|
+
});
|
|
67
|
+
if (settled.outcome === 'already_settled') {
|
|
68
|
+
if (settled.request.result_json === null)
|
|
69
|
+
throw new Error(`settled page request lacks a result: ${request.request_id}`);
|
|
70
|
+
return JSON.parse(settled.request.result_json);
|
|
71
|
+
}
|
|
72
|
+
return result;
|
|
170
73
|
}
|
|
171
|
-
/** Cancel a ticket with the store's first-writer-wins publication. */
|
|
172
74
|
export async function cancelHumanTicket(ticketId, opts) {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
75
|
+
const request = requestForTicket(ticketId);
|
|
76
|
+
const at = new Date().toISOString();
|
|
77
|
+
const result = {
|
|
78
|
+
schema: 'humanloop.cancel/v1', kind: 'canceled', canceledAt: at,
|
|
79
|
+
...(opts.reason === undefined ? {} : { reason: opts.reason }),
|
|
80
|
+
...(opts.actor === undefined ? {} : { actor: opts.actor }),
|
|
81
|
+
...(opts.disposition === undefined ? {} : { disposition: opts.disposition }),
|
|
82
|
+
};
|
|
83
|
+
const settled = await settleHumanRequest({
|
|
84
|
+
request_id: request.request_id,
|
|
85
|
+
outcome: opts.disposition === 'dismissed' ? 'dismissed' : 'canceled',
|
|
86
|
+
result_json: JSON.stringify(result),
|
|
87
|
+
...(notification(request, 'human-canceled', result) === undefined ? {} : { notification: notification(request, 'human-canceled', result) }),
|
|
88
|
+
...(completionAction(request, result) === undefined ? {} : { completion_action: completionAction(request, result) }),
|
|
89
|
+
...(retire(request) === undefined ? {} : { post_commit: retire(request) }),
|
|
90
|
+
});
|
|
91
|
+
if (settled.outcome === 'already_settled') {
|
|
92
|
+
if (settled.request.result_json === null)
|
|
93
|
+
throw new Error(`settled page request lacks a result: ${request.request_id}`);
|
|
94
|
+
return JSON.parse(settled.request.result_json);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
184
97
|
}
|
|
185
|
-
/**
|
|
186
|
-
* settlement winner calls this; the daemon-start sweep replays it for a
|
|
187
|
-
* settlement that died before enqueueing, and the insert is idempotent on the
|
|
188
|
-
* request id so neither path can create a second delivery. */
|
|
189
|
-
export function releaseActionDelivery(ticketId) {
|
|
190
|
-
try {
|
|
191
|
-
const dir = ticketDir(ticketId);
|
|
192
|
-
const binding = readTicketActionBinding(dir);
|
|
193
|
-
if (binding === null)
|
|
194
|
-
return;
|
|
195
|
-
const result = readTicketResult(dir);
|
|
196
|
-
if (result === null || result.kind === 'review')
|
|
197
|
-
return;
|
|
198
|
-
const requestId = opaqueInboxTicketId(ticketId);
|
|
199
|
-
enqueueActionDelivery({
|
|
200
|
-
requestId,
|
|
201
|
-
argv: binding.argv,
|
|
202
|
-
cwd: binding.cwd,
|
|
203
|
-
completion: composeHumanCompletion({ requestId, result, binding, source: pageSource(dir) }),
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
catch (error) {
|
|
207
|
-
// The canonical outcome is already durable; the sweep replays this.
|
|
208
|
-
emitEvent({ level: 'error', event: 'human.action_delivery.enqueue_failed', node_id: ticketId, error });
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
function pageSource(dir) {
|
|
212
|
-
try {
|
|
213
|
-
return parsePage(dir).source ?? {};
|
|
214
|
-
}
|
|
215
|
-
catch {
|
|
216
|
-
return {};
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* Deliver a terminal ticket result to its bridge. The canonical response is the
|
|
221
|
-
* receipt: every action below is replay-safe, so lost delivery can be retried
|
|
222
|
-
* by a later resolve/cancel attempt or the daemon-start sweep.
|
|
223
|
-
*/
|
|
98
|
+
/** Legacy callers use this as a replay hook. Settlement effects are repaired by sweepHumanRequests. */
|
|
224
99
|
export async function deliverTerminalResult(ticketId) {
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
// its companion. The daemon-start sweep settles the tickets that die before
|
|
233
|
-
// reaching this call.
|
|
234
|
-
await settleFeedbackCompanion(ticketId, result.kind === 'canceled' ? 'canceled' : 'approved');
|
|
235
|
-
const replyRoute = readTicketReplyRoute(dir);
|
|
236
|
-
if (replyRoute === null)
|
|
237
|
-
return false;
|
|
238
|
-
const bridgeNodeId = replyRoute.bridge_node_id;
|
|
239
|
-
projectReviewOutput(dir);
|
|
240
|
-
// The ROW, not node metadata: a bridge whose row has been pruned may retain
|
|
241
|
-
// its ticket files, but no lifecycle target remains. No row means nothing is
|
|
242
|
-
// left to deliver to.
|
|
243
|
-
const node = getRow(bridgeNodeId);
|
|
244
|
-
if (node === null || node.status === 'dead' || node.status === 'canceled' || (node.status === 'done' && node.final_report !== null)) {
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
if (result.kind === 'canceled') {
|
|
248
|
-
const title = pageTitle(dir);
|
|
249
|
-
const reason = result.reason !== undefined && result.reason !== '' ? result.reason : 'no reason was given';
|
|
250
|
-
// A dismissal is a rejection, not a routing event: say so plainly so the
|
|
251
|
-
// agent acts on the "no" instead of re-raising the same ask.
|
|
252
|
-
const dismissed = completionEventFor(result) === 'dismissed';
|
|
253
|
-
const subject = dismissed
|
|
254
|
-
? (title === undefined ? `human interaction ${ticketId} dismissed without answering` : `human interaction ${ticketId} — “${title}” dismissed without answering`)
|
|
255
|
-
: (title === undefined ? `human interaction ${ticketId} canceled — no answer is coming` : `human interaction ${ticketId} — “${title}” canceled, no answer is coming`);
|
|
256
|
-
// Dismissal and withdrawal are settlement paths too: the sender still
|
|
257
|
-
// needs any unresolved feedback and the exceptional page-change notice.
|
|
258
|
-
const body = (dismissed
|
|
259
|
-
? `The user dismissed ${title === undefined ? `the human interaction ${ticketId}` : `“${title}”`} without answering — a deliberate “no, I'm not answering this.” Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`
|
|
260
|
-
: (title === undefined ? `The human interaction ${ticketId} was canceled — ${reason}. No response will arrive, and any partial answers the user had entered were discarded unsent.` : `The page “${title}” was canceled — ${reason}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)) + feedbackAddendum(dir);
|
|
261
|
-
// One failing subscriber must not silence the rest, and the bridge stays
|
|
262
|
-
// live until every notice lands: a partial fanout leaves the ticket for the
|
|
263
|
-
// next resolve/cancel attempt or the daemon-start sweep to replay. A
|
|
264
|
-
// subscriber notified twice reads the same idempotent "no answer is coming";
|
|
265
|
-
// a subscriber never notified waits forever.
|
|
266
|
-
const failedTo = [];
|
|
267
|
-
for (const subscriber of subscribersOf(bridgeNodeId)) {
|
|
268
|
-
if (result.actor !== undefined && subscriber.node_id === result.actor)
|
|
269
|
-
continue;
|
|
270
|
-
try {
|
|
271
|
-
appendInbox(subscriber.node_id, {
|
|
272
|
-
from: bridgeNodeId,
|
|
273
|
-
tier: 'normal',
|
|
274
|
-
kind: 'message',
|
|
275
|
-
label: subject,
|
|
276
|
-
data: { body },
|
|
277
|
-
disposition: 'human-canceled',
|
|
278
|
-
});
|
|
279
|
-
cancelCronsOnWake(subscriber.node_id);
|
|
280
|
-
}
|
|
281
|
-
catch {
|
|
282
|
-
failedTo.push(subscriber.node_id);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (failedTo.length > 0)
|
|
286
|
-
throw new Error(`cancellation notice failed for ${failedTo.join(', ')}`);
|
|
287
|
-
// Parking the bridge done is the cancellation's END STATE, not a step it
|
|
288
|
-
// owes: a bridge already done — parked by an earlier cancel replay, or by a
|
|
289
|
-
// close that finished it while the page was still pending — is already
|
|
290
|
-
// there, and `finish` is illegal from done. Re-running it would turn a
|
|
291
|
-
// recorded, delivered cancellation into delivery_failed and make every
|
|
292
|
-
// retry repeat that error.
|
|
293
|
-
if (node.status !== 'done')
|
|
294
|
-
transition(bridgeNodeId, 'finish');
|
|
295
|
-
return true;
|
|
296
|
-
}
|
|
297
|
-
if (result.kind === 'page') {
|
|
298
|
-
const answer = renderPageAnswer(dir, result, responsePath(dir));
|
|
299
|
-
if (answer.feedback !== undefined)
|
|
300
|
-
await pushUpdate(bridgeNodeId, answer.feedback);
|
|
301
|
-
await pushFinal(bridgeNodeId, answer.body, answer.disposition === undefined ? undefined : { disposition: answer.disposition });
|
|
302
|
-
}
|
|
303
|
-
return true;
|
|
100
|
+
const request = requestForTicket(ticketId);
|
|
101
|
+
return request.state === 'settled';
|
|
102
|
+
}
|
|
103
|
+
export async function settleFeedbackCompanion(ticketId, outcome) {
|
|
104
|
+
const request = requestForTicket(ticketId);
|
|
105
|
+
if (request.companion_node_id !== null)
|
|
106
|
+
await retireCompanion(request.companion_node_id, outcome);
|
|
304
107
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type ExternalActionAdapter } from '../../core/feed/messages.js';
|
|
2
|
+
import { type HumanRequestOutcome, type HumanRequestRecord } from '../../core/human/requests.js';
|
|
3
|
+
export interface SettleHumanRequestInput {
|
|
4
|
+
request_id: string;
|
|
5
|
+
outcome: HumanRequestOutcome;
|
|
6
|
+
result_json: string;
|
|
7
|
+
settled_at?: string;
|
|
8
|
+
notification?: {
|
|
9
|
+
label: string;
|
|
10
|
+
disposition: string;
|
|
11
|
+
body_ref?: string;
|
|
12
|
+
body_json?: unknown;
|
|
13
|
+
};
|
|
14
|
+
completion_action?: {
|
|
15
|
+
destinationId: string;
|
|
16
|
+
adapter: ExternalActionAdapter;
|
|
17
|
+
bodyJson: unknown;
|
|
18
|
+
};
|
|
19
|
+
post_commit?: {
|
|
20
|
+
project?: (request: HumanRequestRecord) => Promise<void> | void;
|
|
21
|
+
retire?: (companionNodeId: string, outcome: 'approved' | 'canceled') => Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export type SettleHumanRequestOutcome = {
|
|
25
|
+
outcome: 'settled';
|
|
26
|
+
request: HumanRequestRecord;
|
|
27
|
+
} | {
|
|
28
|
+
outcome: 'already_settled';
|
|
29
|
+
request: HumanRequestRecord;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The only terminal transition. The conditional update is first-writer-wins;
|
|
33
|
+
* the winner's result and every obligation are committed in the same canvas write.
|
|
34
|
+
*/
|
|
35
|
+
export declare function settleHumanRequest(input: SettleHumanRequestInput): Promise<SettleHumanRequestOutcome>;
|
|
36
|
+
/** Projection and companion retirement happen after settlement because filesystem and node lifecycle cannot join SQLite. */
|
|
37
|
+
export declare function projectAndRetire(request: HumanRequestRecord, effects: {
|
|
38
|
+
project?: (request: HumanRequestRecord) => Promise<void> | void;
|
|
39
|
+
retire?: (companionNodeId: string, outcome: 'approved' | 'canceled') => Promise<void>;
|
|
40
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { withCanvasWrite } from '../../core/canvas/db.js';
|
|
2
|
+
import { cancelDelivery, enqueueExternalAction, enqueueNodeMail, } from '../../core/feed/messages.js';
|
|
3
|
+
import { getRequest, markCompanionRetired, markProjected, markProjectionError, setSettlementDeliveryMarksLocked, settleRequestLocked, } from '../../core/human/requests.js';
|
|
4
|
+
/**
|
|
5
|
+
* The only terminal transition. The conditional update is first-writer-wins;
|
|
6
|
+
* the winner's result and every obligation are committed in the same canvas write.
|
|
7
|
+
*/
|
|
8
|
+
export async function settleHumanRequest(input) {
|
|
9
|
+
const committed = withCanvasWrite((db) => {
|
|
10
|
+
const settledAt = input.settled_at ?? new Date().toISOString();
|
|
11
|
+
const won = settleRequestLocked(db, {
|
|
12
|
+
request_id: input.request_id,
|
|
13
|
+
outcome: input.outcome,
|
|
14
|
+
result_json: input.result_json,
|
|
15
|
+
settled_at: settledAt,
|
|
16
|
+
});
|
|
17
|
+
if (won === null) {
|
|
18
|
+
const winner = getRequest(input.request_id);
|
|
19
|
+
if (winner === null)
|
|
20
|
+
throw new Error(`human request disappeared while settling: ${input.request_id}`);
|
|
21
|
+
return { outcome: 'already_settled', request: winner };
|
|
22
|
+
}
|
|
23
|
+
if (won.requester_node_id !== null && input.notification === undefined) {
|
|
24
|
+
throw new Error(`request ${won.request_id} needs a requester notification`);
|
|
25
|
+
}
|
|
26
|
+
if (won.action_json !== null && won.kind === 'page' && input.completion_action === undefined) {
|
|
27
|
+
throw new Error(`request ${won.request_id} needs its frozen completion action`);
|
|
28
|
+
}
|
|
29
|
+
if (won.kind === 'review' && won.projected_at === null && input.post_commit?.project === undefined) {
|
|
30
|
+
throw new Error(`review ${won.request_id} needs a projection effect`);
|
|
31
|
+
}
|
|
32
|
+
if (won.companion_node_id !== null && won.companion_retired_at === null && input.post_commit?.retire === undefined) {
|
|
33
|
+
throw new Error(`request ${won.request_id} needs a companion retirement effect`);
|
|
34
|
+
}
|
|
35
|
+
let settlementDeliveryId = null;
|
|
36
|
+
let actionDeliveryId = null;
|
|
37
|
+
if (won.requester_node_id !== null) {
|
|
38
|
+
const notification = input.notification;
|
|
39
|
+
if (notification === undefined)
|
|
40
|
+
throw new Error(`request ${won.request_id} needs a requester notification`);
|
|
41
|
+
settlementDeliveryId = enqueueNodeMail(won.requester_node_id, {
|
|
42
|
+
kind: 'completed', label: notification.label, senderName: 'crtrd',
|
|
43
|
+
...(notification.body_ref === undefined ? {} : { bodyRef: notification.body_ref }),
|
|
44
|
+
...(notification.body_json === undefined ? {} : { bodyJson: notification.body_json }),
|
|
45
|
+
disposition: notification.disposition === 'human-answer' ? 'human-answer' : 'human-canceled', urgency: 'normal', wake: 1,
|
|
46
|
+
}).deliveryId;
|
|
47
|
+
}
|
|
48
|
+
if (won.action_json !== null && input.completion_action !== undefined && won.kind === 'page') {
|
|
49
|
+
actionDeliveryId = enqueueExternalAction({
|
|
50
|
+
...input.completion_action,
|
|
51
|
+
idempotencyKey: `human-action:${won.inbox_ticket_id}`,
|
|
52
|
+
}).deliveryId;
|
|
53
|
+
}
|
|
54
|
+
if (won.submit_note_delivery_id !== null)
|
|
55
|
+
cancelDelivery(won.submit_note_delivery_id);
|
|
56
|
+
setSettlementDeliveryMarksLocked(db, won.request_id, {
|
|
57
|
+
settlement_delivery_id: settlementDeliveryId,
|
|
58
|
+
action_delivery_id: actionDeliveryId,
|
|
59
|
+
});
|
|
60
|
+
const request = getRequest(won.request_id);
|
|
61
|
+
if (request === null)
|
|
62
|
+
throw new Error(`settled human request disappeared: ${won.request_id}`);
|
|
63
|
+
return { outcome: 'settled', request };
|
|
64
|
+
});
|
|
65
|
+
if (committed.outcome === 'settled' && input.post_commit !== undefined)
|
|
66
|
+
await projectAndRetire(committed.request, input.post_commit);
|
|
67
|
+
return committed;
|
|
68
|
+
}
|
|
69
|
+
/** Projection and companion retirement happen after settlement because filesystem and node lifecycle cannot join SQLite. */
|
|
70
|
+
export async function projectAndRetire(request, effects) {
|
|
71
|
+
if (request.kind === 'review' && request.projected_at === null && effects.project !== undefined) {
|
|
72
|
+
try {
|
|
73
|
+
await effects.project(request);
|
|
74
|
+
markProjected(request.request_id, new Date().toISOString());
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
markProjectionError(request.request_id, error instanceof Error ? error.message : String(error));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (request.companion_node_id !== null && request.companion_retired_at === null && effects.retire !== undefined) {
|
|
81
|
+
try {
|
|
82
|
+
await effects.retire(request.companion_node_id, request.outcome === 'canceled' || request.outcome === 'dismissed' ? 'canceled' : 'approved');
|
|
83
|
+
markCompanionRetired(request.request_id, new Date().toISOString());
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// The durable NULL mark is the authoritative retry obligation for the sweep.
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,6 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { type HumanRequestRecord } from '../../core/human/requests.js';
|
|
2
|
+
export interface HumanRequestSweepEffects {
|
|
3
|
+
realizeReview(requestId: string): Promise<HumanRequestRecord>;
|
|
4
|
+
projectReview(request: HumanRequestRecord): Promise<void> | void;
|
|
5
|
+
retireCompanion(nodeId: string, outcome: 'approved' | 'canceled'): Promise<void>;
|
|
6
|
+
}
|
|
7
|
+
export interface HumanRequestSweepResult {
|
|
8
|
+
realized: number;
|
|
9
|
+
collected: number;
|
|
10
|
+
reprojected: number;
|
|
11
|
+
retired: number;
|
|
5
12
|
failed: number;
|
|
6
|
-
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The one startup repair pass for SQL-authoritative pages and reviews. It does
|
|
16
|
+
* not infer a missing notification or action delivery: settlement created both
|
|
17
|
+
* atomically. The two remaining filesystem effects retain their durable marks.
|
|
18
|
+
*/
|
|
19
|
+
/** Direct outbox rows are created in the settlement transaction; there is no separate ticket-delivery repair pass. */
|
|
20
|
+
export declare function reconcileUndeliveredTickets(): Promise<void>;
|
|
21
|
+
export declare function sweepHumanRequests(effects: HumanRequestSweepEffects): Promise<HumanRequestSweepResult>;
|