@north-light/crouter 0.3.312 → 0.3.313
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/client.d.ts +27 -30
- package/dist/api/client.js +80 -67
- package/dist/api/dto/broker-ops.d.ts +10 -20
- package/dist/api/dto/canvas.d.ts +1 -10
- package/dist/api/dto/health.d.ts +113 -0
- package/dist/api/dto/human-requests.d.ts +14 -3
- package/dist/api/dto/human.d.ts +2 -48
- package/dist/api/dto/human.js +3 -2
- package/dist/api/dto/inbox.d.ts +14 -0
- package/dist/api/dto/mail.d.ts +43 -0
- package/dist/api/dto/nodes.d.ts +11 -8
- package/dist/api/dto/recovery.d.ts +96 -0
- package/dist/api/dto/reviews.d.ts +2 -2
- package/dist/api/routes.d.ts +9 -6
- package/dist/api/routes.js +11 -11
- package/dist/build-root.d.ts +4 -0
- package/dist/build-root.js +11 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
- package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
- package/dist/cli.js +10 -1
- package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
- package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
- package/dist/clients/attach/chrome/canvas-panels.js +1 -1
- package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
- package/dist/clients/attach/chrome/inbox-strip.js +17 -9
- package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
- package/dist/clients/attach/chrome/ticket-panel.js +77 -46
- package/dist/clients/attach/overlays/graph.js +6 -9
- package/dist/clients/attach/render/chat-view.d.ts +5 -4
- package/dist/clients/attach/render/chat-view.js +22 -13
- package/dist/clients/attach/render/page-block.d.ts +11 -7
- package/dist/clients/attach/render/page-block.js +64 -55
- package/dist/clients/attach/viewer.js +746 -735
- package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
- package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
- package/dist/clients/inbox/controller.d.ts +42 -14
- package/dist/clients/inbox/controller.js +240 -124
- package/dist/clients/inbox/dto-adapt.d.ts +28 -0
- package/dist/clients/inbox/dto-adapt.js +93 -0
- package/dist/clients/inbox/page-adapter.d.ts +5 -4
- package/dist/clients/inbox/page-adapter.js +12 -12
- package/dist/clients/inbox/resolve.d.ts +10 -5
- package/dist/clients/inbox/resolve.js +13 -12
- package/dist/clients/inbox/review/review-client.d.ts +0 -1
- package/dist/clients/inbox/review/review-client.js +0 -4
- package/dist/clients/inbox/review-adapter.d.ts +2 -1
- package/dist/clients/inbox/review-adapter.js +3 -5
- package/dist/clients/inbox/surface.d.ts +2 -2
- package/dist/clients/inbox/surface.js +19 -8
- package/dist/clients/inbox/tui.d.ts +3 -3
- package/dist/commands/__tests__/human.test.js +31 -15
- package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
- package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
- package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
- package/dist/commands/api-client.d.ts +5 -4
- package/dist/commands/api-client.js +13 -7
- package/dist/commands/canvas-history/shared.js +1 -1
- package/dist/commands/canvas-history.js +1 -1
- package/dist/commands/canvas-roster.js +1 -1
- package/dist/commands/canvas.js +1 -2
- package/dist/commands/human/feedback.js +20 -17
- package/dist/commands/human/prompts.js +45 -36
- package/dist/commands/human/queue.js +73 -123
- package/dist/commands/human/review.js +6 -16
- package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
- package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
- package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
- package/dist/commands/node-inspect-artifacts.js +1 -1
- package/dist/commands/node-lifecycle-revive.d.ts +2 -2
- package/dist/commands/node-lifecycle-revive.js +9 -19
- package/dist/commands/pkg/plugin-manage.js +0 -1
- package/dist/commands/profile/show.js +4 -12
- package/dist/commands/surface-tmux-spread.js +1 -5
- package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
- package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
- package/dist/commands/sys/branch.d.ts +2 -0
- package/dist/commands/sys/branch.js +19 -0
- package/dist/commands/sys/config.js +106 -33
- package/dist/commands/sys/daemon.d.ts +2 -0
- package/dist/commands/sys/daemon.js +130 -7
- package/dist/commands/sys/doctor.js +5 -15
- package/dist/commands/sys/migrate.js +21 -92
- package/dist/commands/sys/setup-settings-runner.js +4 -2
- package/dist/commands/sys.js +2 -15
- package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
- package/dist/core/__tests__/boot.test.js +32 -25
- package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
- package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
- package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
- package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
- package/dist/core/__tests__/canvas.test.js +18 -47
- package/dist/core/__tests__/child-death-wake.test.js +29 -7
- package/dist/core/__tests__/cli-help-contract.test.js +2 -0
- package/dist/core/__tests__/close.test.js +29 -10
- package/dist/core/__tests__/collectible.test.js +2 -1
- package/dist/core/__tests__/config-change-delta.test.js +2 -0
- package/dist/core/__tests__/context-intro.test.js +13 -1
- package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
- package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
- package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
- package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
- package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
- package/dist/core/__tests__/daemon-boot.test.js +51 -14
- package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
- package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
- package/dist/core/__tests__/focuses.test.js +10 -5
- package/dist/core/__tests__/helpers/harness.js +50 -18
- package/dist/core/__tests__/history-inbox.test.js +12 -16
- package/dist/core/__tests__/human-action-delivery.test.js +48 -28
- package/dist/core/__tests__/human-actions.test.js +7 -3
- package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
- package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
- package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
- package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
- package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
- package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
- package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
- package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
- package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
- package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
- package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
- package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
- package/dist/core/__tests__/integration/revive.test.js +67 -21
- package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
- package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
- package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
- package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
- package/dist/core/__tests__/kickoff.test.js +36 -39
- package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
- package/dist/core/__tests__/lifecycle.test.js +2 -1
- package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
- package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
- package/dist/core/__tests__/migration.test.js +145 -31
- package/dist/core/__tests__/model-pin-durability.test.js +4 -1
- package/dist/core/__tests__/model-routes-config.test.js +13 -5
- package/dist/core/__tests__/node-outcome.test.js +93 -26
- package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
- package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
- package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
- package/dist/core/__tests__/passive-subscription.test.js +50 -157
- package/dist/core/__tests__/plugin-kinds.test.js +6 -4
- package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
- package/dist/core/__tests__/plugin-page-components.test.js +6 -4
- package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
- package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
- package/dist/core/__tests__/prune.test.js +11 -5
- package/dist/core/__tests__/push-final-guard.test.js +14 -7
- package/dist/core/__tests__/relaunch-root.test.js +30 -2
- package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
- package/dist/core/__tests__/repository-root-identity.test.js +4 -0
- package/dist/core/__tests__/review-model-floor.test.js +6 -3
- package/dist/core/__tests__/revive-all.test.js +13 -3
- package/dist/core/__tests__/revive-capacity.test.js +26 -4
- package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
- package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
- package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
- package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
- package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
- package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
- package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
- package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
- package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
- package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
- package/dist/core/__tests__/stop-guard.test.js +2 -1
- package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
- package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
- package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
- package/dist/core/bootstrap.js +2 -0
- package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
- package/dist/core/broker-client/transport-socket.d.ts +1 -0
- package/dist/core/broker-client/transport-socket.js +13 -5
- package/dist/core/canvas/__tests__/attention.test.js +29 -35
- package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
- package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
- package/dist/core/canvas/attention.d.ts +2 -5
- package/dist/core/canvas/attention.js +15 -64
- package/dist/core/canvas/boot.d.ts +6 -7
- package/dist/core/canvas/boot.js +5 -9
- package/dist/core/canvas/canvas.d.ts +13 -109
- package/dist/core/canvas/canvas.js +140 -401
- package/dist/core/canvas/crons.d.ts +2 -0
- package/dist/core/canvas/crons.js +16 -15
- package/dist/core/canvas/daemon-owner.js +10 -0
- package/dist/core/canvas/db.d.ts +2 -2
- package/dist/core/canvas/db.js +2 -18
- package/dist/core/canvas/deliveries.d.ts +104 -0
- package/dist/core/canvas/deliveries.js +354 -0
- package/dist/core/canvas/executions.d.ts +29 -0
- package/dist/core/canvas/executions.js +68 -0
- package/dist/core/canvas/history.js +35 -35
- package/dist/core/canvas/index.d.ts +3 -1
- package/dist/core/canvas/index.js +3 -1
- package/dist/core/canvas/migrations.js +20 -12
- package/dist/core/canvas/nav-model.js +1 -3
- package/dist/core/canvas/nav-render.d.ts +4 -4
- package/dist/core/canvas/nav-render.js +11 -21
- package/dist/core/canvas/node-sql-migration.d.ts +3 -0
- package/dist/core/canvas/node-sql-migration.js +261 -0
- package/dist/core/canvas/paths.d.ts +2 -16
- package/dist/core/canvas/paths.js +2 -31
- package/dist/core/canvas/recovery.d.ts +76 -0
- package/dist/core/canvas/recovery.js +588 -0
- package/dist/core/canvas/remote-canvas-source.js +4 -0
- package/dist/core/canvas/render-source.d.ts +16 -27
- package/dist/core/canvas/render-source.js +16 -45
- package/dist/core/canvas/sessions.d.ts +33 -0
- package/dist/core/canvas/sessions.js +78 -0
- package/dist/core/canvas/types.d.ts +33 -33
- package/dist/core/canvas/types.js +2 -5
- package/dist/core/canvas/waits.d.ts +18 -0
- package/dist/core/canvas/waits.js +70 -0
- package/dist/core/canvas/worktrees.d.ts +40 -0
- package/dist/core/canvas/worktrees.js +93 -0
- package/dist/core/config.d.ts +17 -12
- package/dist/core/config.js +106 -155
- package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
- package/dist/core/feed/feed.d.ts +0 -6
- package/dist/core/feed/feed.js +68 -56
- package/dist/core/feed/inbox.d.ts +7 -81
- package/dist/core/feed/inbox.js +46 -378
- package/dist/core/feed/messages.d.ts +58 -0
- package/dist/core/feed/messages.js +217 -0
- package/dist/core/fs-utils.d.ts +4 -0
- package/dist/core/fs-utils.js +21 -1
- package/dist/core/human/answer.d.ts +1 -1
- package/dist/core/human/answer.js +1 -1
- package/dist/core/human/claim.d.ts +1 -1
- package/dist/core/human/claim.js +2 -4
- package/dist/core/human/component-docs.js +1 -1
- package/dist/core/human/feedback-companion.js +3 -2
- package/dist/core/human/feedback.d.ts +5 -8
- package/dist/core/human/feedback.js +57 -85
- package/dist/core/human/page-authoring.d.ts +30 -0
- package/dist/core/human/page-authoring.js +19 -0
- package/dist/core/human/requests.d.ts +136 -0
- package/dist/core/human/requests.js +515 -0
- package/dist/core/human/root.d.ts +0 -7
- package/dist/core/human/root.js +0 -17
- package/dist/core/human/scan.d.ts +2 -7
- package/dist/core/human/scan.js +48 -132
- package/dist/core/human/summary.d.ts +1 -1
- package/dist/core/human/summary.js +1 -1
- package/dist/core/human/tickets.d.ts +23 -83
- package/dist/core/human/tickets.js +92 -243
- package/dist/core/human/types.d.ts +5 -1
- package/dist/core/installed-plugins.js +8 -3
- package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
- package/dist/core/locked-file.d.ts +6 -3
- package/dist/core/locked-file.js +36 -9
- package/dist/core/memory/extensions.js +2 -0
- package/dist/core/preview-registry.js +0 -1
- package/dist/core/profiles/__tests__/env-store.test.js +2 -0
- package/dist/core/profiles/default-binding.d.ts +0 -4
- package/dist/core/profiles/default-binding.js +12 -58
- package/dist/core/profiles/env-store.js +8 -3
- package/dist/core/profiles/manifest.d.ts +2 -37
- package/dist/core/profiles/manifest.js +35 -161
- package/dist/core/profiles/select.js +3 -0
- package/dist/core/review/__tests__/capture-origin.test.js +13 -2
- package/dist/core/review/__tests__/comments.test.js +28 -10
- package/dist/core/review/__tests__/remap.test.js +28 -10
- package/dist/core/review/__tests__/stage-identity.test.js +17 -7
- package/dist/core/review/birth.d.ts +1 -1
- package/dist/core/review/birth.js +34 -5
- package/dist/core/review/comments.js +1 -1
- package/dist/core/review/document.js +1 -1
- package/dist/core/review/project.d.ts +5 -1
- package/dist/core/review/project.js +14 -36
- package/dist/core/review/realize.d.ts +3 -6
- package/dist/core/review/realize.js +51 -168
- package/dist/core/review/remap.js +1 -1
- package/dist/core/review/stage.d.ts +3 -2
- package/dist/core/review/stage.js +2 -3
- package/dist/core/review/store.d.ts +3 -21
- package/dist/core/review/store.js +140 -186
- package/dist/core/review/types.d.ts +0 -1
- package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
- package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
- package/dist/core/runtime/broker/auth-reload.js +9 -10
- package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
- package/dist/core/runtime/broker/daemon-ops.js +42 -9
- package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
- package/dist/core/runtime/broker/extension-abort.js +11 -0
- package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
- package/dist/core/runtime/broker/fault-retry.js +142 -95
- package/dist/core/runtime/broker/inbox.d.ts +4 -32
- package/dist/core/runtime/broker/inbox.js +4 -92
- package/dist/core/runtime/broker/rebind.d.ts +1 -0
- package/dist/core/runtime/broker/rebind.js +21 -12
- package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
- package/dist/core/runtime/broker-persona-guidance.js +2 -13
- package/dist/core/runtime/broker.js +28 -22
- package/dist/core/runtime/close.d.ts +3 -9
- package/dist/core/runtime/close.js +16 -27
- package/dist/core/runtime/fault.d.ts +3 -93
- package/dist/core/runtime/fault.js +9 -419
- package/dist/core/runtime/kickoff.d.ts +3 -6
- package/dist/core/runtime/kickoff.js +12 -18
- package/dist/core/runtime/launch.js +1 -1
- package/dist/core/runtime/lifecycle.js +40 -7
- package/dist/core/runtime/placement.js +2 -2
- package/dist/core/runtime/recycle.js +8 -2
- package/dist/core/runtime/reset.js +22 -6
- package/dist/core/runtime/revive.js +226 -218
- package/dist/core/runtime/spawn.js +14 -3
- package/dist/core/scoped-state/db.d.ts +7 -0
- package/dist/core/scoped-state/db.js +92 -0
- package/dist/core/scoped-state/migrate.d.ts +11 -0
- package/dist/core/scoped-state/migrate.js +198 -0
- package/dist/core/scoped-state/paths.d.ts +9 -0
- package/dist/core/scoped-state/paths.js +27 -0
- package/dist/core/scoped-state/profiles.d.ts +12 -0
- package/dist/core/scoped-state/profiles.js +62 -0
- package/dist/core/scoped-state/providers.d.ts +16 -0
- package/dist/core/scoped-state/providers.js +8 -0
- package/dist/core/scoped-state/schema.d.ts +3 -0
- package/dist/core/scoped-state/schema.js +26 -0
- package/dist/core/scoped-state/settings.d.ts +28 -0
- package/dist/core/scoped-state/settings.js +82 -0
- package/dist/core/subscription-state.d.ts +29 -48
- package/dist/core/subscription-state.js +176 -712
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +2 -2
- package/dist/core/worktree-sweep.js +11 -16
- package/dist/core/worktree.js +6 -12
- package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
- package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
- package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
- package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
- package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
- package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
- package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
- package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
- package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
- package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
- package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
- package/dist/daemon/api/__tests__/model-config.test.js +8 -8
- package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
- package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
- package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
- package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
- package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
- package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
- package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
- package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
- package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
- package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
- package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
- package/dist/daemon/api/bridge.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +6 -7
- package/dist/daemon/api/handlers/broker-ops.js +47 -84
- package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
- package/dist/daemon/api/handlers/broker-recovery.js +251 -0
- package/dist/daemon/api/handlers/canvas.js +2 -44
- package/dist/daemon/api/handlers/daemon.js +41 -0
- package/dist/daemon/api/handlers/feedback-comments.js +2 -2
- package/dist/daemon/api/handlers/health.js +10 -5
- package/dist/daemon/api/handlers/human-requests.js +168 -188
- package/dist/daemon/api/handlers/human.js +3 -151
- package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
- package/dist/daemon/api/handlers/inbox-page.js +89 -0
- package/dist/daemon/api/handlers/inbox.js +21 -120
- package/dist/daemon/api/handlers/messages.d.ts +1 -0
- package/dist/daemon/api/handlers/messages.js +73 -15
- package/dist/daemon/api/handlers/node-outcomes.js +58 -13
- package/dist/daemon/api/handlers/nodes.js +7 -13
- package/dist/daemon/api/handlers/reviews.js +4 -29
- package/dist/daemon/api/map.d.ts +25 -3
- package/dist/daemon/api/map.js +84 -14
- package/dist/daemon/api/server.js +68 -9
- package/dist/daemon/control.d.ts +18 -0
- package/dist/daemon/cron/disposition.d.ts +2 -0
- package/dist/daemon/cron/disposition.js +8 -5
- package/dist/daemon/cron/settle.js +37 -13
- package/dist/daemon/cron/sinks.d.ts +18 -1
- package/dist/daemon/cron/sinks.js +47 -93
- package/dist/daemon/crtrd-cli.js +4 -19
- package/dist/daemon/crtrd.d.ts +2 -0
- package/dist/daemon/crtrd.js +206 -81
- package/dist/daemon/fleet.js +5 -6
- package/dist/daemon/human/finish.d.ts +12 -24
- package/dist/daemon/human/finish.js +88 -285
- package/dist/daemon/human/settle.d.ts +40 -0
- package/dist/daemon/human/settle.js +89 -0
- package/dist/daemon/human/sweep.d.ts +20 -5
- package/dist/daemon/human/sweep.js +56 -60
- package/dist/daemon/manage.d.ts +21 -16
- package/dist/daemon/manage.js +85 -51
- package/dist/daemon/messaging/node-message.d.ts +1 -1
- package/dist/daemon/messaging/node-message.js +9 -12
- package/dist/daemon/park-activity.js +3 -3
- package/dist/daemon/reconcilers/bash-deadline.js +6 -7
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +41 -19
- package/dist/daemon/reconcilers/controller-death.js +6 -18
- package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/delivery-lane.js +130 -0
- package/dist/daemon/reconcilers/live-obligation.js +3 -3
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
- package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
- package/dist/daemon/review/companion.js +5 -11
- package/dist/daemon/review/deliver.d.ts +1 -5
- package/dist/daemon/review/deliver.js +3 -52
- package/dist/daemon/review/finish.d.ts +2 -27
- package/dist/daemon/review/finish.js +79 -263
- package/dist/daemon/review/sweep.d.ts +3 -10
- package/dist/daemon/review/sweep.js +13 -131
- package/dist/daemon/startup-policy.d.ts +0 -5
- package/dist/daemon/startup-policy.js +0 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
- package/dist/migrations/__tests__/activation.test.js +9 -6
- package/dist/migrations/activation.d.ts +3 -2
- package/dist/migrations/activation.js +2 -4
- package/dist/migrations/corpus.d.ts +2 -5
- package/dist/migrations/corpus.js +9 -20
- package/dist/migrations/runner.d.ts +3 -1
- package/dist/migrations/runner.js +6 -2
- package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
- package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
- package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
- package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
- package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
- package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
- package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
- package/dist/pi-extensions/canvas-passive-context.js +85 -37
- package/dist/pi-extensions/canvas-stophook.js +47 -31
- package/dist/shared/env.d.ts +1 -0
- package/dist/shared/env.js +3 -0
- package/package.json +1 -1
- package/runtime.lock.json +5 -5
- package/dist/clients/attach/__tests__/page-block.test.js +0 -54
- package/dist/clients/inbox/review-visibility.d.ts +0 -5
- package/dist/clients/inbox/review-visibility.js +0 -19
- package/dist/commands/canvas-rebuild-index.d.ts +0 -2
- package/dist/commands/canvas-rebuild-index.js +0 -46
- package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
- package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
- package/dist/core/__tests__/human-deliver.test.js +0 -256
- package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
- package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
- package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
- package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
- package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
- package/dist/core/__tests__/phase4-review-store.test.js +0 -144
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
- package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
- package/dist/core/canvas/human-deliveries.d.ts +0 -39
- package/dist/core/canvas/human-deliveries.js +0 -75
- package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
- package/dist/core/canvas/node-outcome-deliveries.js +0 -159
- package/dist/core/feed/passive.d.ts +0 -3
- package/dist/core/feed/passive.js +0 -53
- package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
- package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
- package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
- package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
- package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
- package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
- package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
- package/dist/core/human/__tests__/page-tickets.test.js +0 -161
- package/dist/core/review/ticket-filter.d.ts +0 -17
- package/dist/core/review/ticket-filter.js +0 -21
- package/dist/core/runtime/broker/passive.d.ts +0 -17
- package/dist/core/runtime/broker/passive.js +0 -44
- package/dist/core/runtime/busy.d.ts +0 -46
- package/dist/core/runtime/busy.js +0 -150
- package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
- package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
- package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
- package/dist/daemon/human/deliver-action.d.ts +0 -3
- package/dist/daemon/human/deliver-action.js +0 -9
- package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
- package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
- package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
- package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
- package/dist/daemon/startup-block-marker.d.ts +0 -25
- package/dist/daemon/startup-block-marker.js +0 -99
- /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
- /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
- /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { existsSync,
|
|
2
|
-
import { basename } from 'node:path';
|
|
1
|
+
import { existsSync, watch } from 'node:fs';
|
|
3
2
|
import { visibleWidth } from '@earendil-works/pi-tui';
|
|
4
3
|
import { renderMarkdown } from '../../core/termrender/termrender.js';
|
|
5
4
|
import { BOLD, CYAN, DIM, GRAY, RESET, YELLOW, clipLine } from './tui/ansi.js';
|
|
6
5
|
import { buildInboxLines, recommendedLabel } from './tui.js';
|
|
7
6
|
import { inboxLayout } from './layout.js';
|
|
8
|
-
import { scanInbox } from '../../core/human/scan.js';
|
|
9
7
|
import { resolvePageComponents } from '../../core/config.js';
|
|
10
8
|
import { watchInboxActivity } from '../../core/human/root.js';
|
|
11
9
|
import { claimTicket, heartbeatClaim, releaseClaim } from '../../core/human/claim.js';
|
|
12
|
-
import {
|
|
13
|
-
import { claimPath, clearProgress, isResolved, pagePath, responsePath } from '../../core/human/convention.js';
|
|
10
|
+
import { claimPath, clearProgress } from '../../core/human/convention.js';
|
|
14
11
|
import { emitEvent } from '../../core/events/emit.js';
|
|
12
|
+
import { cliClient } from '../../commands/api-client.js';
|
|
15
13
|
import { projectPageDisplayMarkdown } from '../../core/human/page-markdown.js';
|
|
16
14
|
import { projectHtmlDocumentMarkdown } from '../../core/human/page-html-markdown.js';
|
|
17
15
|
import { pageBodyLines } from './tui/page-body.js';
|
|
16
|
+
import { byNewestFirst, inboxRowFromDTO, pageViewFromDTO, settledStatusOf } from './dto-adapt.js';
|
|
18
17
|
import { PageAdapter } from './page-adapter.js';
|
|
19
18
|
import { ReviewAdapter } from './review-adapter.js';
|
|
19
|
+
import { createReviewClient } from './review/review-client.js';
|
|
20
20
|
import { editBufferInEditor } from './review/roundtrip.js';
|
|
21
|
-
import {
|
|
21
|
+
import { daemonErrorMessage, dismissTicketViaDaemon, resolveFailureKind, resolveTicketPage, } from './resolve.js';
|
|
22
22
|
/** Host-agnostic model for scanning, stable selection, claims, and rendering. */
|
|
23
23
|
export class InboxController {
|
|
24
24
|
options;
|
|
@@ -42,39 +42,66 @@ export class InboxController {
|
|
|
42
42
|
heartbeat;
|
|
43
43
|
started = false;
|
|
44
44
|
closed = false;
|
|
45
|
-
/** The selected page's
|
|
46
|
-
*
|
|
45
|
+
/** The selected page's projection, kept across frames because fetching it is
|
|
46
|
+
* a round trip. `view` is held so a width change re-wraps without one. */
|
|
47
47
|
preview;
|
|
48
|
+
/** A preview read that failed, so the panel says so instead of staying blank. */
|
|
49
|
+
previewFailed;
|
|
50
|
+
/** In-flight preview fetch, keyed by dir: one request per selection at a time. */
|
|
51
|
+
previewFetching;
|
|
52
|
+
/** Set by `invalidate`: the held preview may no longer be the current revision. */
|
|
53
|
+
previewStale = false;
|
|
54
|
+
/** The revision the open detail was loaded from, so a replacement published
|
|
55
|
+
* while the reader has the page open reloads it. */
|
|
56
|
+
openRevision;
|
|
48
57
|
constructor(options) {
|
|
49
58
|
this.options = options;
|
|
50
59
|
this.host = options.host;
|
|
51
|
-
this.scan = options.scan ??
|
|
60
|
+
this.scan = options.scan ?? defaultScan;
|
|
52
61
|
this.cols = options.cols ?? 80;
|
|
53
62
|
this.rows = options.rows ?? 24;
|
|
54
63
|
// Seeded before the first rescan, which preserves a selected dir it finds.
|
|
55
64
|
this.selectedDir = options.initialSelection;
|
|
56
|
-
this.rescan();
|
|
65
|
+
void this.rescan();
|
|
57
66
|
}
|
|
58
67
|
snapshot() {
|
|
59
68
|
return { items: [...this.items], selectedDir: this.selectedDir, screen: this.screen, inputBuffer: this.adapter?.inputBuffer() };
|
|
60
69
|
}
|
|
61
|
-
rescan() {
|
|
70
|
+
async rescan() {
|
|
62
71
|
const priorDir = this.selectedDir;
|
|
63
72
|
const priorIndex = this.selectedIndex;
|
|
64
|
-
|
|
73
|
+
const claim = this.claim;
|
|
74
|
+
// The row list is a round trip, and most rescans are fired from inbox
|
|
75
|
+
// activity with nobody awaiting them. A failed read keeps the rows already
|
|
76
|
+
// on screen and says so in the status line, rather than rejecting into a
|
|
77
|
+
// caller that cannot handle it.
|
|
78
|
+
try {
|
|
79
|
+
this.items = await this.scan();
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (this.closed)
|
|
83
|
+
return;
|
|
84
|
+
this.status = daemonErrorMessage(error);
|
|
85
|
+
this.markDirty();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (this.closed)
|
|
89
|
+
return;
|
|
65
90
|
const found = priorDir === undefined ? -1 : this.items.findIndex((item) => item.dir === priorDir);
|
|
66
91
|
if (found >= 0) {
|
|
67
92
|
this.selectedIndex = found;
|
|
68
93
|
this.selectedDir = priorDir;
|
|
69
94
|
return;
|
|
70
95
|
}
|
|
71
|
-
if (this.adapter !== undefined && priorDir !== undefined) {
|
|
72
|
-
const canceled =
|
|
96
|
+
if (this.adapter !== undefined && priorDir !== undefined && claim !== undefined) {
|
|
97
|
+
const canceled = (await this.requestOrNull(claim.id))?.state === 'canceled';
|
|
98
|
+
if (this.closed)
|
|
99
|
+
return;
|
|
73
100
|
if (canceled)
|
|
74
101
|
clearProgress(priorDir);
|
|
75
102
|
// Suppress the "resolved elsewhere" banner when WE are the ones resolving
|
|
76
|
-
// this ticket: the
|
|
77
|
-
// mid-submit, and that is our own completion, not an external event.
|
|
103
|
+
// this ticket: the settlement we just submitted drops the row from the
|
|
104
|
+
// scan mid-submit, and that is our own completion, not an external event.
|
|
78
105
|
if (priorDir !== this.submittingDir)
|
|
79
106
|
this.status = canceled ? 'canceled by requester' : 'ticket resolved elsewhere';
|
|
80
107
|
this.leaveDetail(priorDir !== this.submittingDir);
|
|
@@ -97,7 +124,24 @@ export class InboxController {
|
|
|
97
124
|
heartbeatClaim(this.claim.dir, this.claim.token);
|
|
98
125
|
}, 10_000);
|
|
99
126
|
}
|
|
100
|
-
|
|
127
|
+
/** Inbox activity is the one signal a replacement always emits, and it is
|
|
128
|
+
* emitted after the new revision is selected — so an open page reloads here
|
|
129
|
+
* rather than from a file watch that cannot see a directory swap. */
|
|
130
|
+
async invalidate() {
|
|
131
|
+
// Activity is the one signal a replacement always emits, and it fires after
|
|
132
|
+
// the new revision is selected — so the held preview and any open page are
|
|
133
|
+
// re-read from the daemon here rather than from a file watch, which cannot
|
|
134
|
+
// see a directory swap at all.
|
|
135
|
+
this.previewStale = true;
|
|
136
|
+
await this.rescan();
|
|
137
|
+
if (this.closed)
|
|
138
|
+
return;
|
|
139
|
+
if (this.adapter !== undefined && this.claim !== undefined) {
|
|
140
|
+
await this.reloadSelectedPage();
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.markDirty();
|
|
144
|
+
}
|
|
101
145
|
resize(cols, rows) {
|
|
102
146
|
this.cols = cols;
|
|
103
147
|
this.rows = rows;
|
|
@@ -149,10 +193,10 @@ export class InboxController {
|
|
|
149
193
|
}
|
|
150
194
|
if (this.cancelConfirmation !== undefined) {
|
|
151
195
|
if (input === 'y' || input === 'Y') {
|
|
152
|
-
const
|
|
196
|
+
const item = this.cancelConfirmation.item;
|
|
153
197
|
this.cancelConfirmation = undefined;
|
|
154
198
|
this.status = 'canceling…';
|
|
155
|
-
void this.cancelFromInbox(
|
|
199
|
+
void this.cancelFromInbox(item);
|
|
156
200
|
}
|
|
157
201
|
else if (input === 'n' || input === 'N' || key.escape) {
|
|
158
202
|
this.cancelConfirmation = undefined;
|
|
@@ -164,7 +208,7 @@ export class InboxController {
|
|
|
164
208
|
if (input === 'x' || input === 'X') {
|
|
165
209
|
const selected = this.items[this.selectedIndex];
|
|
166
210
|
if (selected !== undefined) {
|
|
167
|
-
this.cancelConfirmation = {
|
|
211
|
+
this.cancelConfirmation = { item: selected };
|
|
168
212
|
this.status = undefined;
|
|
169
213
|
}
|
|
170
214
|
this.markDirty();
|
|
@@ -186,7 +230,7 @@ export class InboxController {
|
|
|
186
230
|
else if (input === 'g' || input === 'G')
|
|
187
231
|
void this.focusSelectedSource();
|
|
188
232
|
else if (key.return || input === 'a')
|
|
189
|
-
this.activate();
|
|
233
|
+
void this.activate();
|
|
190
234
|
this.markDirty();
|
|
191
235
|
}
|
|
192
236
|
/** Settle the selected ticket from the list with what crouter already put on
|
|
@@ -201,15 +245,18 @@ export class InboxController {
|
|
|
201
245
|
this.status = 'no recommended answer on this ticket — Enter opens it';
|
|
202
246
|
return;
|
|
203
247
|
}
|
|
248
|
+
// Settlement is a daemon-owned state, so a claim still succeeds on a
|
|
249
|
+
// settled request's directory. The record decides whether this row is
|
|
250
|
+
// stale; only then does a refused claim mean another inbox holds it.
|
|
251
|
+
const request = await this.requestOrNull(item.id);
|
|
252
|
+
if (isSettled(request)) {
|
|
253
|
+
this.status = settledStatus(request);
|
|
254
|
+
await this.rescan();
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
204
257
|
const claim = claimTicket(item.dir);
|
|
205
258
|
if (claim === null) {
|
|
206
|
-
|
|
207
|
-
// exists) or a live claim is held. Only the latter is "another inbox";
|
|
208
|
-
// the former is a stale row this scan should drop.
|
|
209
|
-
const resolved = isResolved(item.dir);
|
|
210
|
-
this.status = resolved ? safeCanonicalResultStatus(item.dir) : 'ticket is being edited by another inbox';
|
|
211
|
-
if (resolved)
|
|
212
|
-
this.rescan();
|
|
259
|
+
this.status = 'ticket is being edited by another inbox';
|
|
213
260
|
return;
|
|
214
261
|
}
|
|
215
262
|
const settled = item.fastAction.kind === 'acknowledge'
|
|
@@ -217,25 +264,30 @@ export class InboxController {
|
|
|
217
264
|
: `sent: ${recommendedLabel(item) ?? 'recommended answer'}`;
|
|
218
265
|
this.submittingDir = item.dir;
|
|
219
266
|
try {
|
|
220
|
-
await resolveTicketPage(item.
|
|
267
|
+
await resolveTicketPage(item.id, item.fastAction.responses);
|
|
221
268
|
this.status = settled;
|
|
222
269
|
}
|
|
223
270
|
catch (error) {
|
|
224
|
-
this.status = resolveFailureKind(error) === '
|
|
225
|
-
?
|
|
271
|
+
this.status = resolveFailureKind(error) === 'already_settled'
|
|
272
|
+
? settledStatus(await this.requestOrNull(item.id))
|
|
226
273
|
: daemonErrorMessage(error);
|
|
227
274
|
}
|
|
228
275
|
finally {
|
|
229
276
|
releaseClaim(item.dir, claim.token);
|
|
230
277
|
this.submittingDir = undefined;
|
|
231
|
-
this.rescan();
|
|
278
|
+
await this.rescan();
|
|
232
279
|
this.markDirty();
|
|
233
280
|
}
|
|
234
281
|
}
|
|
235
|
-
|
|
236
|
-
|
|
282
|
+
/** A review and a page are two different durable records; the inbox dismisses
|
|
283
|
+
* whichever one the selected row actually is. */
|
|
284
|
+
async cancelFromInbox(item) {
|
|
285
|
+
this.submittingDir = item.dir;
|
|
237
286
|
try {
|
|
238
|
-
|
|
287
|
+
if (item.kind === 'review')
|
|
288
|
+
await createReviewClient().cancel(item.id, 'Canceled from the inbox.');
|
|
289
|
+
else
|
|
290
|
+
await dismissTicketViaDaemon(item.id, { reason: 'Canceled from the inbox.', actor: 'human' });
|
|
239
291
|
this.status = 'canceled';
|
|
240
292
|
}
|
|
241
293
|
catch (error) {
|
|
@@ -243,46 +295,67 @@ export class InboxController {
|
|
|
243
295
|
}
|
|
244
296
|
finally {
|
|
245
297
|
this.submittingDir = undefined;
|
|
246
|
-
this.rescan();
|
|
298
|
+
await this.rescan();
|
|
247
299
|
this.markDirty();
|
|
248
300
|
}
|
|
249
301
|
}
|
|
250
|
-
activate() {
|
|
302
|
+
async activate() {
|
|
251
303
|
const item = this.items[this.selectedIndex];
|
|
252
304
|
if (item === undefined)
|
|
253
305
|
return;
|
|
254
306
|
if (item.kind === 'review') {
|
|
255
|
-
|
|
307
|
+
await this.activateReview(item);
|
|
256
308
|
return;
|
|
257
309
|
}
|
|
258
|
-
|
|
310
|
+
const request = await this.requestOrNull(item.id);
|
|
311
|
+
if (this.closed)
|
|
259
312
|
return;
|
|
313
|
+
if (isSettled(request)) {
|
|
314
|
+
this.status = settledStatus(request);
|
|
315
|
+
await this.rescan();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
260
318
|
const claim = claimTicket(item.dir);
|
|
261
319
|
if (claim === null) {
|
|
262
|
-
|
|
263
|
-
this.status = resolved ? safeCanonicalResultStatus(item.dir) : 'ticket is being edited by another inbox';
|
|
264
|
-
if (resolved)
|
|
265
|
-
this.rescan();
|
|
320
|
+
this.status = 'ticket is being edited by another inbox';
|
|
266
321
|
return;
|
|
267
322
|
}
|
|
268
|
-
|
|
269
|
-
|
|
323
|
+
// One projection carries the revision AND the content it belongs to, so
|
|
324
|
+
// there is no window between reading the two in which a replacement lands.
|
|
325
|
+
let view;
|
|
326
|
+
let revision;
|
|
270
327
|
try {
|
|
271
|
-
|
|
328
|
+
const page = await cliClient().getHumanInboxPage(item.inboxTicketId);
|
|
329
|
+
// The claim is a presenter lock, not settlement authority, so a request
|
|
330
|
+
// that settled between the pre-claim check and this read would still
|
|
331
|
+
// claim. This projection already carries the state that decides it.
|
|
332
|
+
if (page.state === 'resolved' || page.state === 'canceled') {
|
|
333
|
+
releaseClaim(item.dir, claim.token);
|
|
334
|
+
this.status = settledStatusOf(page);
|
|
335
|
+
await this.rescan();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
view = pageViewFromDTO(page);
|
|
339
|
+
revision = page.revision;
|
|
272
340
|
}
|
|
273
341
|
catch {
|
|
274
342
|
releaseClaim(item.dir, claim.token);
|
|
275
|
-
this.claim = undefined;
|
|
276
343
|
this.status = 'page could not be read';
|
|
277
|
-
this.invalidate();
|
|
344
|
+
await this.invalidate();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
// Another activation (or a close) may have landed while this read was in
|
|
348
|
+
// flight; that one owns the detail screen, so this claim is released.
|
|
349
|
+
if (this.closed || this.claim !== undefined || this.adapter !== undefined) {
|
|
350
|
+
releaseClaim(item.dir, claim.token);
|
|
278
351
|
return;
|
|
279
352
|
}
|
|
280
|
-
|
|
353
|
+
this.claim = { dir: item.dir, id: item.id, ticketId: item.inboxTicketId, token: claim.token };
|
|
281
354
|
this.screen = 'detail';
|
|
282
355
|
this.adapter = new PageAdapter({
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
productKinds,
|
|
356
|
+
ticketId: item.inboxTicketId,
|
|
357
|
+
page: view,
|
|
358
|
+
productKinds: resolvePageComponents(),
|
|
286
359
|
cols: this.detailSize().cols,
|
|
287
360
|
rows: this.detailSize().rows,
|
|
288
361
|
onDirty: () => this.markDirty(),
|
|
@@ -290,11 +363,13 @@ export class InboxController {
|
|
|
290
363
|
onBack: () => { this.leaveDetail(); this.markDirty(); },
|
|
291
364
|
onComplete: (responses) => { void this.complete(responses); },
|
|
292
365
|
});
|
|
366
|
+
this.openRevision = revision;
|
|
293
367
|
this.watchSelected(item.dir);
|
|
368
|
+
this.markDirty();
|
|
294
369
|
}
|
|
295
370
|
async activateReview(item) {
|
|
296
371
|
this.reviewAdapter = new ReviewAdapter({
|
|
297
|
-
|
|
372
|
+
reviewId: item.id,
|
|
298
373
|
host: this.host,
|
|
299
374
|
});
|
|
300
375
|
try {
|
|
@@ -305,7 +380,7 @@ export class InboxController {
|
|
|
305
380
|
}
|
|
306
381
|
finally {
|
|
307
382
|
this.reviewAdapter = undefined;
|
|
308
|
-
this.rescan();
|
|
383
|
+
await this.rescan();
|
|
309
384
|
this.markDirty();
|
|
310
385
|
}
|
|
311
386
|
}
|
|
@@ -317,13 +392,21 @@ export class InboxController {
|
|
|
317
392
|
this.markDirty();
|
|
318
393
|
}
|
|
319
394
|
}
|
|
320
|
-
|
|
321
|
-
|
|
395
|
+
/** Re-read the open page and reload it only when its revision actually moved. */
|
|
396
|
+
async reloadSelectedPage() {
|
|
397
|
+
const claim = this.claim;
|
|
398
|
+
if (this.adapter === undefined || claim === undefined) {
|
|
322
399
|
this.markDirty();
|
|
323
400
|
return;
|
|
324
401
|
}
|
|
325
402
|
try {
|
|
326
|
-
|
|
403
|
+
const page = await cliClient().getHumanInboxPage(claim.ticketId);
|
|
404
|
+
if (this.closed || this.claim !== claim || this.adapter === undefined)
|
|
405
|
+
return;
|
|
406
|
+
if (page.revision !== this.openRevision) {
|
|
407
|
+
this.openRevision = page.revision;
|
|
408
|
+
this.adapter.reload(pageViewFromDTO(page));
|
|
409
|
+
}
|
|
327
410
|
}
|
|
328
411
|
catch {
|
|
329
412
|
this.status = 'page could not be read';
|
|
@@ -353,7 +436,7 @@ export class InboxController {
|
|
|
353
436
|
return;
|
|
354
437
|
this.submittingDir = claim.dir;
|
|
355
438
|
try {
|
|
356
|
-
await resolveTicketPage(claim.
|
|
439
|
+
await resolveTicketPage(claim.id, responses);
|
|
357
440
|
}
|
|
358
441
|
catch (error) {
|
|
359
442
|
this.submittingDir = undefined;
|
|
@@ -363,28 +446,28 @@ export class InboxController {
|
|
|
363
446
|
this.markDirty();
|
|
364
447
|
return;
|
|
365
448
|
}
|
|
366
|
-
if (failure === '
|
|
367
|
-
this.status =
|
|
449
|
+
if (failure === 'already_settled')
|
|
450
|
+
this.status = settledStatus(await this.requestOrNull(claim.id));
|
|
368
451
|
this.leaveDetail(false);
|
|
369
|
-
this.rescan();
|
|
452
|
+
await this.rescan();
|
|
370
453
|
this.markDirty();
|
|
371
454
|
return;
|
|
372
455
|
}
|
|
373
456
|
this.submittingDir = undefined;
|
|
374
457
|
this.leaveDetail(false);
|
|
375
|
-
this.rescan();
|
|
458
|
+
await this.rescan();
|
|
376
459
|
// A settled page whose row survives its own post-resolve rescan is the
|
|
377
|
-
// "row won't leave" defect. This records the
|
|
378
|
-
//
|
|
379
|
-
// reproduction:
|
|
380
|
-
// was the claim left behind.
|
|
460
|
+
// "row won't leave" defect. This records the truth at the exact moment the
|
|
461
|
+
// row should have dropped, so a live recurrence is diagnosable without a
|
|
462
|
+
// reproduction: did the request reach a terminal state, does the scan still
|
|
463
|
+
// list it, and was the claim left behind.
|
|
381
464
|
const stillListed = this.items.some((item) => item.dir === claim.dir);
|
|
382
465
|
emitEvent({
|
|
383
466
|
level: stillListed ? 'warn' : 'info',
|
|
384
467
|
event: 'inbox.page.resolved',
|
|
385
468
|
fields: {
|
|
386
|
-
ticket_id:
|
|
387
|
-
|
|
469
|
+
ticket_id: claim.id,
|
|
470
|
+
request_settled: isSettled(await this.requestOrNull(claim.id)),
|
|
388
471
|
still_listed: stillListed,
|
|
389
472
|
claim_left_behind: existsSync(claimPath(claim.dir)),
|
|
390
473
|
},
|
|
@@ -417,6 +500,7 @@ export class InboxController {
|
|
|
417
500
|
if (release && this.claim !== undefined)
|
|
418
501
|
releaseClaim(this.claim.dir, this.claim.token);
|
|
419
502
|
this.claim = undefined;
|
|
503
|
+
this.openRevision = undefined;
|
|
420
504
|
this.screen = 'list';
|
|
421
505
|
}
|
|
422
506
|
select(index) {
|
|
@@ -453,14 +537,21 @@ export class InboxController {
|
|
|
453
537
|
focusAvailable(_dir) {
|
|
454
538
|
return this.host.capabilities.canFocusNode;
|
|
455
539
|
}
|
|
456
|
-
/** Ask the host to bring the
|
|
540
|
+
/** Ask the host to bring the requesting node's viewer into view — the
|
|
541
|
+
* conversation that raised this ask. */
|
|
457
542
|
async focusSelectedSource() {
|
|
458
543
|
const item = this.items[this.selectedIndex];
|
|
459
544
|
if (item === undefined || this.focusingSource)
|
|
460
545
|
return;
|
|
546
|
+
const requesterNodeId = item.source.nodeId;
|
|
547
|
+
if (requesterNodeId === undefined) {
|
|
548
|
+
this.status = 'This request was not raised by a canvas node';
|
|
549
|
+
this.markDirty();
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
461
552
|
this.focusingSource = true;
|
|
462
553
|
try {
|
|
463
|
-
const focused = await this.host.focusNode(
|
|
554
|
+
const focused = await this.host.focusNode(requesterNodeId);
|
|
464
555
|
if (focused)
|
|
465
556
|
this.close();
|
|
466
557
|
else {
|
|
@@ -472,31 +563,65 @@ export class InboxController {
|
|
|
472
563
|
this.focusingSource = false;
|
|
473
564
|
}
|
|
474
565
|
}
|
|
475
|
-
/** What the selected page actually says
|
|
476
|
-
*
|
|
477
|
-
*
|
|
566
|
+
/** What the selected page actually says. Rendering is synchronous and the
|
|
567
|
+
* page is a round trip, so the projection is held and a miss schedules the
|
|
568
|
+
* fetch, marking the frame dirty when it lands. A width change re-wraps the
|
|
569
|
+
* held projection without another read. */
|
|
478
570
|
pagePreviewBody(item, width) {
|
|
479
|
-
|
|
571
|
+
const cached = this.preview;
|
|
572
|
+
if (cached !== undefined && cached.dir === item.dir) {
|
|
573
|
+
if (this.previewStale)
|
|
574
|
+
this.schedulePreview(item);
|
|
575
|
+
if (cached.width === width)
|
|
576
|
+
return cached.lines;
|
|
577
|
+
const lines = previewLines(cached.view, width);
|
|
578
|
+
this.preview = { ...cached, width, lines };
|
|
579
|
+
return lines;
|
|
580
|
+
}
|
|
581
|
+
this.schedulePreview(item);
|
|
582
|
+
// A failed read says so; an unfetched one is simply not there yet.
|
|
583
|
+
return this.previewFailed === item.dir ? [`${DIM}page could not be read${RESET}`] : [];
|
|
584
|
+
}
|
|
585
|
+
/** One in-flight preview read at a time. A revision that did not move keeps
|
|
586
|
+
* the held projection, so activity on an unrelated ticket costs no re-wrap. */
|
|
587
|
+
schedulePreview(item) {
|
|
588
|
+
if (this.previewFetching === item.dir)
|
|
589
|
+
return;
|
|
590
|
+
this.previewFetching = item.dir;
|
|
591
|
+
this.previewStale = false;
|
|
592
|
+
void cliClient().getHumanInboxPage(item.inboxTicketId).then((page) => {
|
|
593
|
+
if (this.closed || this.previewFetching !== item.dir)
|
|
594
|
+
return;
|
|
595
|
+
this.previewFetching = undefined;
|
|
596
|
+
this.previewFailed = undefined;
|
|
597
|
+
if (this.preview?.dir === item.dir && this.preview.revision === page.revision)
|
|
598
|
+
return;
|
|
599
|
+
const view = pageViewFromDTO(page);
|
|
600
|
+
const width = this.preview?.width ?? inboxLayout(this.cols, this.rows, this.screen).detailWidth;
|
|
601
|
+
this.preview = { dir: item.dir, revision: page.revision, view, width, lines: previewLines(view, width) };
|
|
602
|
+
this.markDirty();
|
|
603
|
+
}, () => {
|
|
604
|
+
if (this.closed || this.previewFetching !== item.dir)
|
|
605
|
+
return;
|
|
606
|
+
this.previewFetching = undefined;
|
|
607
|
+
this.previewFailed = item.dir;
|
|
608
|
+
// Never leave the prior page's body standing under this row's title.
|
|
609
|
+
if (this.preview?.dir === item.dir)
|
|
610
|
+
this.preview = undefined;
|
|
611
|
+
this.markDirty();
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
/** The request record is the settlement authority: a settled page publishes
|
|
615
|
+
* no file, so a claim would still succeed on its directory. An unreachable
|
|
616
|
+
* daemon reads as "not known to be settled" — the settle attempt that
|
|
617
|
+
* follows is the one that fails loudly. */
|
|
618
|
+
async requestOrNull(id) {
|
|
480
619
|
try {
|
|
481
|
-
|
|
620
|
+
return await cliClient().getHumanRequest(id);
|
|
482
621
|
}
|
|
483
622
|
catch {
|
|
484
|
-
|
|
623
|
+
return undefined;
|
|
485
624
|
}
|
|
486
|
-
const cached = this.preview;
|
|
487
|
-
if (cached !== undefined && cached.dir === item.dir && cached.width === width && cached.stamp === stamp)
|
|
488
|
-
return cached.lines;
|
|
489
|
-
let lines = [];
|
|
490
|
-
try {
|
|
491
|
-
const ticket = readPageTicket(item.dir);
|
|
492
|
-
const display = ticket.manifest.dialect === 'html'
|
|
493
|
-
? projectHtmlDocumentMarkdown(ticket.document)
|
|
494
|
-
: projectPageDisplayMarkdown(ticket.document, ticket.manifest);
|
|
495
|
-
lines = pageBodyLines(ticket.manifest, display, Math.min(Math.max(20, width - 4), 100), Math.max(20, width - 4));
|
|
496
|
-
}
|
|
497
|
-
catch { /* a half-written or removed ticket previews as its title alone */ }
|
|
498
|
-
this.preview = { dir: item.dir, width, stamp, lines };
|
|
499
|
-
return lines;
|
|
500
625
|
}
|
|
501
626
|
/** The read-only preview beside the list. It shows the page's own content,
|
|
502
627
|
* because `s` settles the selected ticket from here without ever opening
|
|
@@ -523,7 +648,7 @@ export class InboxController {
|
|
|
523
648
|
withStatus(lines) {
|
|
524
649
|
const status = this.cancelConfirmation === undefined
|
|
525
650
|
? this.status
|
|
526
|
-
: `cancel “${this.cancelConfirmation.title}”? y yes · n/Esc no`;
|
|
651
|
+
: `cancel “${this.cancelConfirmation.item.title}”? y yes · n/Esc no`;
|
|
527
652
|
if (status === undefined || this.rows < 1)
|
|
528
653
|
return lines;
|
|
529
654
|
const next = [...lines];
|
|
@@ -536,50 +661,41 @@ export class InboxController {
|
|
|
536
661
|
this.options.onDirty();
|
|
537
662
|
}
|
|
538
663
|
watchRoots() {
|
|
539
|
-
const unsubscribe = watchInboxActivity(this.options.onInboxActivity ?? (() => this.invalidate()));
|
|
664
|
+
const unsubscribe = watchInboxActivity(this.options.onInboxActivity ?? (() => { void this.invalidate(); }));
|
|
540
665
|
this.watchers.push({ close: unsubscribe });
|
|
541
666
|
}
|
|
667
|
+
/** The request directory still carries the claim and progress files other
|
|
668
|
+
* inboxes write. Its page content lives in the daemon-selected revision,
|
|
669
|
+
* which `invalidate` re-reads over the API. */
|
|
542
670
|
watchSelected(dir) {
|
|
543
671
|
this.selectedWatcher?.close();
|
|
544
672
|
try {
|
|
545
|
-
this.selectedWatcher = watch(dir, (
|
|
546
|
-
if (file === 'page.json') {
|
|
547
|
-
this.reloadSelectedPage();
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
this.invalidate();
|
|
551
|
-
});
|
|
673
|
+
this.selectedWatcher = watch(dir, () => { void this.invalidate(); });
|
|
552
674
|
}
|
|
553
675
|
catch {
|
|
554
676
|
this.selectedWatcher = undefined;
|
|
555
677
|
}
|
|
556
678
|
}
|
|
557
679
|
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
if (result.kind === 'page')
|
|
564
|
-
return 'ticket was already resolved: page submitted';
|
|
565
|
-
return 'ticket was already canceled';
|
|
680
|
+
/** The inbox the daemon lists IS the inbox: visibility, ordering and row
|
|
681
|
+
* content all come from the one projection. */
|
|
682
|
+
async function defaultScan() {
|
|
683
|
+
const { tickets } = await cliClient().listHumanInbox();
|
|
684
|
+
return tickets.map(inboxRowFromDTO).sort(byNewestFirst);
|
|
566
685
|
}
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
return readTicketResult(dir);
|
|
573
|
-
}
|
|
574
|
-
catch {
|
|
575
|
-
return null;
|
|
576
|
-
}
|
|
686
|
+
function previewLines(view, width) {
|
|
687
|
+
const display = view.manifest.dialect === 'html'
|
|
688
|
+
? projectHtmlDocumentMarkdown(view.document)
|
|
689
|
+
: projectPageDisplayMarkdown(view.document, view.manifest);
|
|
690
|
+
return pageBodyLines(view.manifest, display, Math.min(Math.max(20, width - 4), 100), Math.max(20, width - 4));
|
|
577
691
|
}
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
692
|
+
/** A request the daemon no longer reports on is not known to be settled. */
|
|
693
|
+
function isSettled(request) {
|
|
694
|
+
return request !== undefined && request.state !== 'pending';
|
|
695
|
+
}
|
|
696
|
+
/** Why a second settlement was refused, in the status line's own wording. */
|
|
697
|
+
function settledStatus(request) {
|
|
698
|
+
if (request?.page === undefined)
|
|
699
|
+
return 'ticket was already resolved';
|
|
700
|
+
return settledStatusOf(request.page);
|
|
585
701
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { InboxPageDTO, InboxTicketSummaryDTO } from '../../api/dto/inbox.js';
|
|
2
|
+
import type { PageManifest, PageResponses } from '../../core/human/page-schema.js';
|
|
3
|
+
import type { PageTicketSummary, ReviewTicketSummary } from '../../core/human/types.js';
|
|
4
|
+
/** A review row as the inbox actually uses it. The review's file and output
|
|
5
|
+
* path belong to the review document surface, which reads them from the review
|
|
6
|
+
* client — an inbox row never needs either. */
|
|
7
|
+
export type InboxReviewRow = Omit<ReviewTicketSummary, 'file' | 'output'>;
|
|
8
|
+
export type InboxRow = PageTicketSummary | InboxReviewRow;
|
|
9
|
+
/** Everything the page renderer needs, plus the revision token that decides
|
|
10
|
+
* whether an already-open page has to reload. */
|
|
11
|
+
export interface InboxPageView {
|
|
12
|
+
manifest: PageManifest;
|
|
13
|
+
/** The authored JSX/HTML source the renderer projects — never the compiled host module. */
|
|
14
|
+
document: string;
|
|
15
|
+
progress: PageResponses | null;
|
|
16
|
+
state: 'pending' | 'resolved' | 'canceled' | 'passive';
|
|
17
|
+
/** Opaque equality token for the SQL-selected revision. Compare, never parse. */
|
|
18
|
+
revision: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function inboxRowFromDTO(dto: InboxTicketSummaryDTO): InboxRow;
|
|
21
|
+
export declare function pageViewFromDTO(dto: InboxPageDTO): InboxPageView;
|
|
22
|
+
/** The stored one-line answer digest, or undefined when the page was not
|
|
23
|
+
* answered. A canceled page carries no digest by construction. */
|
|
24
|
+
export declare function answerDigestOf(dto: InboxPageDTO): string | undefined;
|
|
25
|
+
/** What a surface says when a settled request refuses a second settlement. */
|
|
26
|
+
export declare function settledStatusOf(dto: InboxPageDTO): string;
|
|
27
|
+
/** The row sort every inbox surface shares: newest first, request id breaking ties. */
|
|
28
|
+
export declare function byNewestFirst(a: InboxRow, b: InboxRow): number;
|