@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.
Files changed (495) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +746 -735
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +13 -1
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  121. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
  122. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  123. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  124. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  125. package/dist/core/__tests__/integration/revive.test.js +67 -21
  126. package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
  127. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  128. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  129. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  130. package/dist/core/__tests__/kickoff.test.js +36 -39
  131. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  132. package/dist/core/__tests__/lifecycle.test.js +2 -1
  133. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  134. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  135. package/dist/core/__tests__/migration.test.js +145 -31
  136. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  137. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  138. package/dist/core/__tests__/node-outcome.test.js +93 -26
  139. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  140. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
  141. package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
  142. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  143. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  144. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  145. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  146. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  147. package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
  148. package/dist/core/__tests__/prune.test.js +11 -5
  149. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  150. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  151. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  152. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  153. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  154. package/dist/core/__tests__/revive-all.test.js +13 -3
  155. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  156. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  157. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  158. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  159. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  160. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  161. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  162. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  163. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  164. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  165. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
  166. package/dist/core/__tests__/stop-guard.test.js +2 -1
  167. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  168. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
  169. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  170. package/dist/core/bootstrap.js +2 -0
  171. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  172. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  173. package/dist/core/broker-client/transport-socket.js +13 -5
  174. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  175. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  176. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  177. package/dist/core/canvas/attention.d.ts +2 -5
  178. package/dist/core/canvas/attention.js +15 -64
  179. package/dist/core/canvas/boot.d.ts +6 -7
  180. package/dist/core/canvas/boot.js +5 -9
  181. package/dist/core/canvas/canvas.d.ts +13 -109
  182. package/dist/core/canvas/canvas.js +140 -401
  183. package/dist/core/canvas/crons.d.ts +2 -0
  184. package/dist/core/canvas/crons.js +16 -15
  185. package/dist/core/canvas/daemon-owner.js +10 -0
  186. package/dist/core/canvas/db.d.ts +2 -2
  187. package/dist/core/canvas/db.js +2 -18
  188. package/dist/core/canvas/deliveries.d.ts +104 -0
  189. package/dist/core/canvas/deliveries.js +354 -0
  190. package/dist/core/canvas/executions.d.ts +29 -0
  191. package/dist/core/canvas/executions.js +68 -0
  192. package/dist/core/canvas/history.js +35 -35
  193. package/dist/core/canvas/index.d.ts +3 -1
  194. package/dist/core/canvas/index.js +3 -1
  195. package/dist/core/canvas/migrations.js +20 -12
  196. package/dist/core/canvas/nav-model.js +1 -3
  197. package/dist/core/canvas/nav-render.d.ts +4 -4
  198. package/dist/core/canvas/nav-render.js +11 -21
  199. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  200. package/dist/core/canvas/node-sql-migration.js +261 -0
  201. package/dist/core/canvas/paths.d.ts +2 -16
  202. package/dist/core/canvas/paths.js +2 -31
  203. package/dist/core/canvas/recovery.d.ts +76 -0
  204. package/dist/core/canvas/recovery.js +588 -0
  205. package/dist/core/canvas/remote-canvas-source.js +4 -0
  206. package/dist/core/canvas/render-source.d.ts +16 -27
  207. package/dist/core/canvas/render-source.js +16 -45
  208. package/dist/core/canvas/sessions.d.ts +33 -0
  209. package/dist/core/canvas/sessions.js +78 -0
  210. package/dist/core/canvas/types.d.ts +33 -33
  211. package/dist/core/canvas/types.js +2 -5
  212. package/dist/core/canvas/waits.d.ts +18 -0
  213. package/dist/core/canvas/waits.js +70 -0
  214. package/dist/core/canvas/worktrees.d.ts +40 -0
  215. package/dist/core/canvas/worktrees.js +93 -0
  216. package/dist/core/config.d.ts +17 -12
  217. package/dist/core/config.js +106 -155
  218. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  219. package/dist/core/feed/feed.d.ts +0 -6
  220. package/dist/core/feed/feed.js +68 -56
  221. package/dist/core/feed/inbox.d.ts +7 -81
  222. package/dist/core/feed/inbox.js +46 -378
  223. package/dist/core/feed/messages.d.ts +58 -0
  224. package/dist/core/feed/messages.js +217 -0
  225. package/dist/core/fs-utils.d.ts +4 -0
  226. package/dist/core/fs-utils.js +21 -1
  227. package/dist/core/human/answer.d.ts +1 -1
  228. package/dist/core/human/answer.js +1 -1
  229. package/dist/core/human/claim.d.ts +1 -1
  230. package/dist/core/human/claim.js +2 -4
  231. package/dist/core/human/component-docs.js +1 -1
  232. package/dist/core/human/feedback-companion.js +3 -2
  233. package/dist/core/human/feedback.d.ts +5 -8
  234. package/dist/core/human/feedback.js +57 -85
  235. package/dist/core/human/page-authoring.d.ts +30 -0
  236. package/dist/core/human/page-authoring.js +19 -0
  237. package/dist/core/human/requests.d.ts +136 -0
  238. package/dist/core/human/requests.js +515 -0
  239. package/dist/core/human/root.d.ts +0 -7
  240. package/dist/core/human/root.js +0 -17
  241. package/dist/core/human/scan.d.ts +2 -7
  242. package/dist/core/human/scan.js +48 -132
  243. package/dist/core/human/summary.d.ts +1 -1
  244. package/dist/core/human/summary.js +1 -1
  245. package/dist/core/human/tickets.d.ts +23 -83
  246. package/dist/core/human/tickets.js +92 -243
  247. package/dist/core/human/types.d.ts +5 -1
  248. package/dist/core/installed-plugins.js +8 -3
  249. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  250. package/dist/core/locked-file.d.ts +6 -3
  251. package/dist/core/locked-file.js +36 -9
  252. package/dist/core/memory/extensions.js +2 -0
  253. package/dist/core/preview-registry.js +0 -1
  254. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  255. package/dist/core/profiles/default-binding.d.ts +0 -4
  256. package/dist/core/profiles/default-binding.js +12 -58
  257. package/dist/core/profiles/env-store.js +8 -3
  258. package/dist/core/profiles/manifest.d.ts +2 -37
  259. package/dist/core/profiles/manifest.js +35 -161
  260. package/dist/core/profiles/select.js +3 -0
  261. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  262. package/dist/core/review/__tests__/comments.test.js +28 -10
  263. package/dist/core/review/__tests__/remap.test.js +28 -10
  264. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  265. package/dist/core/review/birth.d.ts +1 -1
  266. package/dist/core/review/birth.js +34 -5
  267. package/dist/core/review/comments.js +1 -1
  268. package/dist/core/review/document.js +1 -1
  269. package/dist/core/review/project.d.ts +5 -1
  270. package/dist/core/review/project.js +14 -36
  271. package/dist/core/review/realize.d.ts +3 -6
  272. package/dist/core/review/realize.js +51 -168
  273. package/dist/core/review/remap.js +1 -1
  274. package/dist/core/review/stage.d.ts +3 -2
  275. package/dist/core/review/stage.js +2 -3
  276. package/dist/core/review/store.d.ts +3 -21
  277. package/dist/core/review/store.js +140 -186
  278. package/dist/core/review/types.d.ts +0 -1
  279. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  280. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  281. package/dist/core/runtime/broker/auth-reload.js +9 -10
  282. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  283. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  284. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  285. package/dist/core/runtime/broker/extension-abort.js +11 -0
  286. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  287. package/dist/core/runtime/broker/fault-retry.js +142 -95
  288. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  289. package/dist/core/runtime/broker/inbox.js +4 -92
  290. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  291. package/dist/core/runtime/broker/rebind.js +21 -12
  292. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  293. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  294. package/dist/core/runtime/broker.js +28 -22
  295. package/dist/core/runtime/close.d.ts +3 -9
  296. package/dist/core/runtime/close.js +16 -27
  297. package/dist/core/runtime/fault.d.ts +3 -93
  298. package/dist/core/runtime/fault.js +9 -419
  299. package/dist/core/runtime/kickoff.d.ts +3 -6
  300. package/dist/core/runtime/kickoff.js +12 -18
  301. package/dist/core/runtime/launch.js +1 -1
  302. package/dist/core/runtime/lifecycle.js +40 -7
  303. package/dist/core/runtime/placement.js +2 -2
  304. package/dist/core/runtime/recycle.js +8 -2
  305. package/dist/core/runtime/reset.js +22 -6
  306. package/dist/core/runtime/revive.js +226 -218
  307. package/dist/core/runtime/spawn.js +14 -3
  308. package/dist/core/scoped-state/db.d.ts +7 -0
  309. package/dist/core/scoped-state/db.js +92 -0
  310. package/dist/core/scoped-state/migrate.d.ts +11 -0
  311. package/dist/core/scoped-state/migrate.js +198 -0
  312. package/dist/core/scoped-state/paths.d.ts +9 -0
  313. package/dist/core/scoped-state/paths.js +27 -0
  314. package/dist/core/scoped-state/profiles.d.ts +12 -0
  315. package/dist/core/scoped-state/profiles.js +62 -0
  316. package/dist/core/scoped-state/providers.d.ts +16 -0
  317. package/dist/core/scoped-state/providers.js +8 -0
  318. package/dist/core/scoped-state/schema.d.ts +3 -0
  319. package/dist/core/scoped-state/schema.js +26 -0
  320. package/dist/core/scoped-state/settings.d.ts +28 -0
  321. package/dist/core/scoped-state/settings.js +82 -0
  322. package/dist/core/subscription-state.d.ts +29 -48
  323. package/dist/core/subscription-state.js +176 -712
  324. package/dist/core/worktree-close.js +4 -4
  325. package/dist/core/worktree-mutation-async.js +2 -2
  326. package/dist/core/worktree-sweep.js +11 -16
  327. package/dist/core/worktree.js +6 -12
  328. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  329. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  330. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  331. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  332. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  333. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
  334. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  335. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  336. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  337. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  338. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  339. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  340. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  341. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  342. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  343. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
  344. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  345. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  346. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  347. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  348. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  349. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
  350. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  351. package/dist/daemon/api/bridge.js +1 -1
  352. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  353. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  354. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  355. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  356. package/dist/daemon/api/handlers/canvas.js +2 -44
  357. package/dist/daemon/api/handlers/daemon.js +41 -0
  358. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  359. package/dist/daemon/api/handlers/health.js +10 -5
  360. package/dist/daemon/api/handlers/human-requests.js +168 -188
  361. package/dist/daemon/api/handlers/human.js +3 -151
  362. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  363. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  364. package/dist/daemon/api/handlers/inbox.js +21 -120
  365. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  366. package/dist/daemon/api/handlers/messages.js +73 -15
  367. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  368. package/dist/daemon/api/handlers/nodes.js +7 -13
  369. package/dist/daemon/api/handlers/reviews.js +4 -29
  370. package/dist/daemon/api/map.d.ts +25 -3
  371. package/dist/daemon/api/map.js +84 -14
  372. package/dist/daemon/api/server.js +68 -9
  373. package/dist/daemon/control.d.ts +18 -0
  374. package/dist/daemon/cron/disposition.d.ts +2 -0
  375. package/dist/daemon/cron/disposition.js +8 -5
  376. package/dist/daemon/cron/settle.js +37 -13
  377. package/dist/daemon/cron/sinks.d.ts +18 -1
  378. package/dist/daemon/cron/sinks.js +47 -93
  379. package/dist/daemon/crtrd-cli.js +4 -19
  380. package/dist/daemon/crtrd.d.ts +2 -0
  381. package/dist/daemon/crtrd.js +206 -81
  382. package/dist/daemon/fleet.js +5 -6
  383. package/dist/daemon/human/finish.d.ts +12 -24
  384. package/dist/daemon/human/finish.js +88 -285
  385. package/dist/daemon/human/settle.d.ts +40 -0
  386. package/dist/daemon/human/settle.js +89 -0
  387. package/dist/daemon/human/sweep.d.ts +20 -5
  388. package/dist/daemon/human/sweep.js +56 -60
  389. package/dist/daemon/manage.d.ts +21 -16
  390. package/dist/daemon/manage.js +85 -51
  391. package/dist/daemon/messaging/node-message.d.ts +1 -1
  392. package/dist/daemon/messaging/node-message.js +9 -12
  393. package/dist/daemon/park-activity.js +3 -3
  394. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  395. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  396. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  397. package/dist/daemon/reconcilers/controller-death.js +6 -18
  398. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  399. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  400. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  401. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  402. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  403. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  404. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  405. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  406. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  407. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  408. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  409. package/dist/daemon/review/companion.js +5 -11
  410. package/dist/daemon/review/deliver.d.ts +1 -5
  411. package/dist/daemon/review/deliver.js +3 -52
  412. package/dist/daemon/review/finish.d.ts +2 -27
  413. package/dist/daemon/review/finish.js +79 -263
  414. package/dist/daemon/review/sweep.d.ts +3 -10
  415. package/dist/daemon/review/sweep.js +13 -131
  416. package/dist/daemon/startup-policy.d.ts +0 -5
  417. package/dist/daemon/startup-policy.js +0 -5
  418. package/dist/index.d.ts +2 -1
  419. package/dist/index.js +1 -1
  420. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  421. package/dist/migrations/__tests__/activation.test.js +9 -6
  422. package/dist/migrations/activation.d.ts +3 -2
  423. package/dist/migrations/activation.js +2 -4
  424. package/dist/migrations/corpus.d.ts +2 -5
  425. package/dist/migrations/corpus.js +9 -20
  426. package/dist/migrations/runner.d.ts +3 -1
  427. package/dist/migrations/runner.js +6 -2
  428. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  429. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  430. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  431. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  432. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  433. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  434. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  435. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  436. package/dist/pi-extensions/canvas-stophook.js +47 -31
  437. package/dist/shared/env.d.ts +1 -0
  438. package/dist/shared/env.js +3 -0
  439. package/package.json +1 -1
  440. package/runtime.lock.json +5 -5
  441. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  442. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  443. package/dist/clients/inbox/review-visibility.js +0 -19
  444. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  445. package/dist/commands/canvas-rebuild-index.js +0 -46
  446. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  447. package/dist/core/__tests__/human-deliver.test.d.ts +0 -1
  448. package/dist/core/__tests__/human-deliver.test.js +0 -256
  449. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  450. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  451. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  452. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  453. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  454. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  455. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  456. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  457. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  458. package/dist/core/canvas/human-deliveries.js +0 -75
  459. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  460. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  461. package/dist/core/feed/passive.d.ts +0 -3
  462. package/dist/core/feed/passive.js +0 -53
  463. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  464. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  465. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  466. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  467. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  468. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  469. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  470. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  471. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  472. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  473. package/dist/core/review/ticket-filter.d.ts +0 -17
  474. package/dist/core/review/ticket-filter.js +0 -21
  475. package/dist/core/runtime/broker/passive.d.ts +0 -17
  476. package/dist/core/runtime/broker/passive.js +0 -44
  477. package/dist/core/runtime/busy.d.ts +0 -46
  478. package/dist/core/runtime/busy.js +0 -150
  479. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  480. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  481. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  482. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  483. package/dist/daemon/human/deliver-action.d.ts +0 -3
  484. package/dist/daemon/human/deliver-action.js +0 -9
  485. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  486. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  487. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  488. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  489. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  490. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  491. package/dist/daemon/startup-block-marker.d.ts +0 -25
  492. package/dist/daemon/startup-block-marker.js +0 -99
  493. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  494. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  495. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
@@ -10,16 +10,23 @@
10
10
  // roster; Esc at the page top closes back to the editor.
11
11
  //
12
12
  // The claim lifecycle mirrors the inbox surface's detail screen: claim on
13
- // open, heartbeat every 10s, watch the ticket dir (page.json → reload, other
14
- // activity → close if resolved elsewhere), resolve through the daemon on
15
- // complete, release on close. Review tickets and unreadable pages fall back
16
- // to the full-pane inbox seated on the row.
17
- import { watch } from 'node:fs';
13
+ // open, heartbeat every 10s, resolve through the daemon on complete, release
14
+ // on close. Review tickets and unreadable pages fall back to the full-pane
15
+ // inbox seated on the row.
16
+ //
17
+ // The page itself comes from the daemon, addressed by the row's opaque inbox
18
+ // ticket id. Refresh is driven by inbox activity rather than a watch on the
19
+ // request directory: a `--replace` revision is a NEW directory selected in SQL
20
+ // before the activity signal fires, so the directory the panel opened on never
21
+ // sees the replacement. Each signal re-reads the ticket once and compares its
22
+ // revision and state — a moved revision reloads, a terminal state closes.
18
23
  import { claimTicket, heartbeatClaim, releaseClaim } from '../../../core/human/claim.js';
19
- import { readPageTicket, readTicketResult } from '../../../core/human/tickets.js';
24
+ import { watchInboxActivity } from '../../../core/human/root.js';
20
25
  import { resolvePageComponents } from '../../../core/config.js';
21
26
  import { fillBar, stripSgr, truncate, REVERSE } from '../../../core/canvas/nav-render.js';
27
+ import { cliClient } from '../../../commands/api-client.js';
22
28
  import { visibleWidth } from '../../inbox/tui/ansi.js';
29
+ import { pageViewFromDTO, settledStatusOf } from '../../inbox/dto-adapt.js';
23
30
  import { PageAdapter } from '../../inbox/page-adapter.js';
24
31
  import { decodeInboxKey } from '../../inbox/tui/keys.js';
25
32
  import { daemonErrorMessage, resolveFailureKind, resolveTicketPage } from '../../inbox/resolve.js';
@@ -40,7 +47,7 @@ export function createTicketPanel(s, hooks) {
40
47
  return;
41
48
  session = undefined;
42
49
  clearInterval(open.heartbeat);
43
- open.watcher?.close();
50
+ open.unwatch();
44
51
  open.adapter.close();
45
52
  if (release)
46
53
  releaseClaim(open.dir, open.token);
@@ -51,7 +58,7 @@ export function createTicketPanel(s, hooks) {
51
58
  const complete = async (open, responses) => {
52
59
  submitting = true;
53
60
  try {
54
- await resolveTicketPage(open.dir, responses);
61
+ await resolveTicketPage(open.id, responses);
55
62
  closeSession(false);
56
63
  hooks.setNotice('Response sent');
57
64
  }
@@ -62,19 +69,45 @@ export function createTicketPanel(s, hooks) {
62
69
  return; // keep the page open — nothing was submitted
63
70
  }
64
71
  closeSession(false);
65
- hooks.setNotice(failure === 'already_resolved' ? resolvedElsewhereNotice(open.dir) : daemonErrorMessage(error));
72
+ hooks.setNotice(failure === 'already_settled' ? await resolvedElsewhereNotice(open.ticketId) : daemonErrorMessage(error));
66
73
  }
67
74
  finally {
68
75
  submitting = false;
69
76
  }
70
77
  };
71
- const reload = (open) => {
78
+ /** One read per activity signal decides everything: a moved revision is a
79
+ * replacement, a terminal state is a settlement somewhere else. */
80
+ const onActivity = async (open) => {
81
+ if (session !== open || submitting)
82
+ return;
83
+ let page;
84
+ try {
85
+ page = await cliClient().getHumanInboxPage(open.ticketId);
86
+ }
87
+ catch (error) {
88
+ if (session !== open)
89
+ return;
90
+ closeSession(true);
91
+ hooks.setNotice(`Ticket could not be read: ${daemonErrorMessage(error)}`);
92
+ return;
93
+ }
94
+ if (session !== open || submitting)
95
+ return;
96
+ if (page.state === 'resolved' || page.state === 'canceled') {
97
+ closeSession(true);
98
+ hooks.setNotice(page.state === 'canceled' ? 'Ticket was canceled by its requester' : 'Ticket was resolved elsewhere');
99
+ return;
100
+ }
101
+ if (page.revision === open.revision)
102
+ return;
103
+ open.revision = page.revision;
72
104
  try {
73
- open.adapter.reload(readPageTicket(open.dir));
105
+ open.adapter.reload(pageViewFromDTO(page));
74
106
  }
75
107
  catch {
76
108
  hooks.setNotice('Page could not be read');
77
109
  }
110
+ tui.requestRender();
78
111
  };
79
112
  const editPageInput = (open) => {
80
113
  const buffer = open.adapter.inputBuffer();
@@ -93,7 +126,7 @@ export function createTicketPanel(s, hooks) {
93
126
  tui.requestRender();
94
127
  }
95
128
  };
96
- const open = (ticket) => {
129
+ const open = async (ticket) => {
97
130
  if (session !== undefined)
98
131
  closeSession(true);
99
132
  if (ticket.kind !== 'page') {
@@ -105,24 +138,44 @@ export function createTicketPanel(s, hooks) {
105
138
  hooks.setNotice('Ticket is being edited by another inbox');
106
139
  return;
107
140
  }
108
- let loaded;
141
+ let view;
142
+ let revision;
109
143
  try {
110
- loaded = readPageTicket(ticket.dir);
144
+ const page = await cliClient().getHumanInboxPage(ticket.inboxTicketId);
145
+ // The claim is a presenter lock, not settlement authority, so a request
146
+ // that settled between the row being listed and this read would still
147
+ // claim. This projection already carries the state that decides it.
148
+ if (page.state === 'resolved' || page.state === 'canceled') {
149
+ releaseClaim(ticket.dir, claim.token);
150
+ hooks.setNotice(settledStatusOf(page));
151
+ return;
152
+ }
153
+ view = pageViewFromDTO(page);
154
+ revision = page.revision;
111
155
  }
112
156
  catch {
113
157
  releaseClaim(ticket.dir, claim.token);
114
158
  hooks.openInbox(ticket.dir);
115
159
  return;
116
160
  }
161
+ // Awaiting the read gave another open (or a close) the chance to land first;
162
+ // that session owns the panel, so this one releases its claim and stops.
163
+ if (session !== undefined) {
164
+ releaseClaim(ticket.dir, claim.token);
165
+ return;
166
+ }
117
167
  lastCols = Math.max(20, tui.terminal.columns - 2);
118
168
  lastRows = capRows();
119
169
  const entry = {
120
170
  dir: ticket.dir,
171
+ id: ticket.id,
172
+ ticketId: ticket.inboxTicketId,
121
173
  title: ticket.title,
122
174
  token: claim.token,
175
+ revision,
123
176
  adapter: new PageAdapter({
124
- dir: ticket.dir,
125
- ticket: loaded,
177
+ ticketId: ticket.inboxTicketId,
178
+ page: view,
126
179
  productKinds: resolvePageComponents(),
127
180
  cols: lastCols,
128
181
  rows: lastRows,
@@ -131,38 +184,13 @@ export function createTicketPanel(s, hooks) {
131
184
  onComplete: (responses) => { void complete(entry, responses); },
132
185
  onEditorRequest: () => editPageInput(entry),
133
186
  }),
134
- watcher: undefined,
187
+ unwatch: () => { },
135
188
  heartbeat: setInterval(() => {
136
189
  if (session === entry)
137
190
  heartbeatClaim(entry.dir, entry.token);
138
191
  }, 10_000),
139
192
  };
140
- try {
141
- entry.watcher = watch(ticket.dir, (_event, file) => {
142
- if (session !== entry || submitting)
143
- return;
144
- if (file === 'page.json') {
145
- reload(entry);
146
- return;
147
- }
148
- let result;
149
- try {
150
- result = readTicketResult(entry.dir);
151
- }
152
- catch (error) {
153
- closeSession(true);
154
- hooks.setNotice(`ticket result is unreadable: ${error instanceof Error ? error.message : String(error)}`);
155
- return;
156
- }
157
- if (result !== null) {
158
- closeSession(true);
159
- hooks.setNotice(result.kind === 'canceled' ? 'Ticket was canceled by its requester' : 'Ticket was resolved elsewhere');
160
- }
161
- });
162
- }
163
- catch {
164
- entry.watcher = undefined;
165
- }
193
+ entry.unwatch = watchInboxActivity(() => { void onActivity(entry); });
166
194
  session = entry;
167
195
  hooks.syncCursor();
168
196
  hooks.refreshStrip();
@@ -210,13 +238,16 @@ export function createTicketPanel(s, hooks) {
210
238
  currentDir: () => session?.dir,
211
239
  };
212
240
  }
213
- function resolvedElsewhereNotice(dir) {
241
+ /** Why a settlement was refused, in the panel's sentence case. */
242
+ async function resolvedElsewhereNotice(ticketId) {
243
+ let status;
214
244
  try {
215
- return readTicketResult(dir)?.kind === 'canceled' ? 'Ticket was already canceled' : 'Ticket was already resolved';
245
+ status = settledStatusOf(await cliClient().getHumanInboxPage(ticketId));
216
246
  }
217
247
  catch (error) {
218
- return `ticket result is unreadable: ${error instanceof Error ? error.message : String(error)}`;
248
+ return `Ticket result is unreadable: ${daemonErrorMessage(error)}`;
219
249
  }
250
+ return status.charAt(0).toUpperCase() + status.slice(1);
220
251
  }
221
252
  /** The SGR opening the theme's `customMessageBg` — the background the crouter
222
253
  * context cards use. pi shares its live theme across module loaders on this
@@ -29,14 +29,12 @@ import { execFile } from 'node:child_process';
29
29
  import { matchesKey, truncateToWidth } from '@earendil-works/pi-tui';
30
30
  import { formatBinding, matchesPiTuiInput, } from '../../../core/keybindings/index.js';
31
31
  // Pure leaf imports (NOT the canvas/index barrel or nav-model, both of which
32
- // reach the canvas-db): fullName from labels.js, activeFaultForDisplay from
33
- // render-source.js, all render/telemetry helpers from nav-render.js. The
32
+ // reach the canvas-db): fullName from labels.js, faultSummary from
33
+ // status-glyph.js, all render/telemetry helpers from nav-render.js. The
34
34
  // tmux-focus set (formerly nav-model's focusedNodeIds → listFocuses db read) is
35
35
  // fetched through the crtrd API (cliClient().listFocuses) so this viewer stays
36
36
  // off the canvas-db.
37
37
  import { fullName } from '../../../core/canvas/labels.js';
38
- import { activeFaultForDisplay } from '../../../core/canvas/render-source.js';
39
- import { readFault } from '../../../core/runtime/fault.js';
40
38
  import { faultSummary } from '../../../core/canvas/status-glyph.js';
41
39
  import { RemoteCanvasSource } from '../../../core/canvas/remote-canvas-source.js';
42
40
  import { cliClient } from '../../../commands/api-client.js';
@@ -349,7 +347,7 @@ export class GraphOverlay {
349
347
  return wrap(line, false);
350
348
  }
351
349
  const node = snapshot.nodes.get(r.id) ?? null;
352
- const dot = nodeGlyph(node, this.remote);
350
+ const dot = nodeGlyph(node);
353
351
  const rawName = navLabel(node, r.id);
354
352
  const name = r.isSelf ? `${BOLD}${rawName}${RESET}` : rawName;
355
353
  const kind = `${DIM}${node?.kind ?? ''}${RESET}`;
@@ -362,10 +360,9 @@ export class GraphOverlay {
362
360
  const below = node !== null && node.status !== 'active' && (snapshot.activeBelow.get(node.node_id) ?? 0) > 0
363
361
  ? ` ${GREEN}⇣${snapshot.activeBelow.get(node.node_id) ?? 0}${RESET}`
364
362
  : '';
365
- // A remote fault is a local disk read (readFault) keyed on a node id that
366
- // may collide with a local one — skip it entirely rather than read-then-
367
- // discard.
368
- const fault = node !== null && !this.remote ? activeFaultForDisplay(node, readFault(r.id)) : null;
363
+ // The fault rides on the row its owning daemon projected, so a remote node
364
+ // shows its own canvas's fault instead of a local-id collision.
365
+ const fault = node?.fault ?? null;
369
366
  const faultSuffix = fault !== null ? ` · ${faultSummary(fault)}` : '';
370
367
  const line = `${r.branch}${caret}${dot} ${name} ${kind} ${tokens}${cycle}${child}${below}${askBadge(r.id, asks)}${activityCell(r.id, node, this.remote)}${faultSuffix}`;
371
368
  return wrap(line, isAttached(r.id, node, snapshot.focused, this.remote));
@@ -298,16 +298,17 @@ export declare class ChatView {
298
298
  * way assistant prose stays. Condensed history is skipped deliberately — old
299
299
  * cycles keep only prose and cycle seams. */
300
300
  private maybeAppendPageBlock;
301
+ private loadPageBlock;
301
302
  /** Re-measure the tool calls still in flight. A silent long-running command
302
303
  * emits no tool-execution update, so nothing else would evict its cached
303
304
  * lines and its backgrounding hint would never appear. Driven by the
304
305
  * viewer's existing low-rate chrome poll, and cheap because it touches only
305
306
  * in-flight tools — usually one, never the transcript. */
306
307
  refreshInFlightTools(): void;
307
- /** Re-read every placed page from disk. Driven by the viewer's ticket-activity
308
- * watcher, so an answer, a cancellation, or a `--replace` revision lands on
309
- * the block already anchored in the transcript. */
310
- refreshPageBlocks(): void;
308
+ /** Re-read every placed page through the daemon. Driven by the viewer's
309
+ * ticket-activity watcher, so an answer, a cancellation, or a `--replace`
310
+ * revision lands on the block already anchored in the transcript. */
311
+ refreshPageBlocks(): Promise<void>;
311
312
  private makeLoader;
312
313
  /** Let a self-updating history child invalidate only its own cached lines. */
313
314
  private componentTui;
@@ -1454,9 +1454,18 @@ export class ChatView {
1454
1454
  const page = detectInlinePageResult(result);
1455
1455
  if (page === undefined || this.pageBlocks.has(page.pageId))
1456
1456
  return;
1457
- const block = new PageBlockComponent(page.pageId, page.dir, this.pageOpenHint);
1457
+ const block = new PageBlockComponent(page.pageId, this.pageOpenHint);
1458
1458
  this.pageBlocks.set(page.pageId, block);
1459
1459
  this.append(block);
1460
+ // The block is placed empty and fills itself from the daemon: reading a
1461
+ // request is a round trip, and the transcript must not block on one.
1462
+ void this.loadPageBlock(block);
1463
+ }
1464
+ async loadPageBlock(block) {
1465
+ if (!(await block.refresh()))
1466
+ return;
1467
+ this.historyContainer.markDirty(block);
1468
+ this.tui.requestRender();
1460
1469
  }
1461
1470
  /** Re-measure the tool calls still in flight. A silent long-running command
1462
1471
  * emits no tool-execution update, so nothing else would evict its cached
@@ -1470,18 +1479,18 @@ export class ChatView {
1470
1479
  this.historyContainer.markDirty(component);
1471
1480
  this.tui.requestRender();
1472
1481
  }
1473
- /** Re-read every placed page from disk. Driven by the viewer's ticket-activity
1474
- * watcher, so an answer, a cancellation, or a `--replace` revision lands on
1475
- * the block already anchored in the transcript. */
1476
- refreshPageBlocks() {
1477
- let changed = false;
1478
- for (const block of this.pageBlocks.values()) {
1479
- if (!block.refresh())
1480
- continue;
1481
- changed = true;
1482
- this.historyContainer.markDirty(block);
1483
- }
1484
- if (changed)
1482
+ /** Re-read every placed page through the daemon. Driven by the viewer's
1483
+ * ticket-activity watcher, so an answer, a cancellation, or a `--replace`
1484
+ * revision lands on the block already anchored in the transcript. */
1485
+ async refreshPageBlocks() {
1486
+ const blocks = [...this.pageBlocks.values()];
1487
+ const changed = await Promise.all(blocks.map(async (block) => {
1488
+ const moved = await block.refresh();
1489
+ if (moved)
1490
+ this.historyContainer.markDirty(block);
1491
+ return moved;
1492
+ }));
1493
+ if (changed.some(Boolean))
1485
1494
  this.tui.requestRender();
1486
1495
  }
1487
1496
  makeLoader(message) {
@@ -1,7 +1,6 @@
1
1
  import type { Component } from '@earendil-works/pi-tui';
2
2
  export interface InlinePageRef {
3
3
  pageId: string;
4
- dir: string;
5
4
  }
6
5
  /**
7
6
  * The inline page a `human send` tool result announces, or undefined for every
@@ -12,22 +11,27 @@ export interface InlinePageRef {
12
11
  export declare function detectInlinePageResult(result: unknown): InlinePageRef | undefined;
13
12
  export declare class PageBlockComponent implements Component {
14
13
  readonly pageId: string;
15
- private readonly dir;
16
14
  private readonly openHint;
17
15
  private expanded;
18
16
  private generation;
17
+ /** `revision|state` from the last successful read. A replacement selects a
18
+ * new revision and a settlement moves the state, so nothing here depends on
19
+ * a file timestamp or on the directory the page was first projected into. */
19
20
  private stamp;
20
21
  private snapshot;
22
+ /** `loading` until the first read returns; a failed read is never presented
23
+ * as the previous content still being current. */
24
+ private status;
21
25
  private cache;
22
- constructor(pageId: string, dir: string, openHint: () => string);
23
- /** Re-read the ticket when its request or its result changed on disk. */
24
- refresh(): boolean;
26
+ constructor(pageId: string, openHint: () => string);
27
+ /** Re-read the request. Resolves true when the rendered content changed, so
28
+ * the caller knows whether to mark the transcript dirty. */
29
+ refresh(): Promise<boolean>;
25
30
  /** Ctrl+O global expansion (ChatView.isExpandable duck-type). */
26
31
  setExpanded(expanded: boolean): void;
27
32
  render(width: number): string[];
28
33
  invalidate(): void;
29
- private diskStamp;
30
- private reload;
34
+ private settle;
31
35
  private compose;
32
36
  private footerLine;
33
37
  }
@@ -7,17 +7,18 @@
7
7
  // queue entry at all and would otherwise be invisible here), while this block is
8
8
  // what the person actually reads.
9
9
  //
10
- // The block renders from the ticket directory on disk, never from the tool
11
- // result text, so `--replace` revisions and the answer that settles a page both
12
- // land on the already-placed block when `refresh()` is driven by the viewer's
13
- // inbox-activity watcher.
14
- import { readFileSync, statSync } from 'node:fs';
10
+ // The block is identified by the request id the tool result carries, and reads
11
+ // the request through the daemon. The directory in that tool result is a
12
+ // historical record of where the page was projected when it was sent: a
13
+ // `--replace` revision selects a new directory, and a page migrated from the
14
+ // legacy layout never matched the new one at all. So identity is the request id
15
+ // and nothing else, and the page content is whatever revision the daemon
16
+ // currently selects for it.
15
17
  import { pageAwaitsResponse } from '../../../core/human/page-schema.js';
16
18
  import { projectPageDisplayMarkdown } from '../../../core/human/page-markdown.js';
17
19
  import { projectHtmlDocumentMarkdown } from '../../../core/human/page-html-markdown.js';
18
- import { parsePage } from '../../../core/human/page.js';
19
- import { pageManifestPath, pagePath, responsePath } from '../../../core/human/convention.js';
20
- import { pageTicketState, readTicketResult } from '../../../core/human/tickets.js';
20
+ import { cliClient } from '../../../commands/api-client.js';
21
+ import { answerDigestOf } from '../../inbox/dto-adapt.js';
21
22
  import { pageBodyLines } from '../../inbox/tui/page-body.js';
22
23
  import { BOLD, CYAN, DIM, GREEN, RESET, YELLOW, sanitize, singleLine, truncate, wrap } from '../../inbox/tui/ansi.js';
23
24
  /** Rows of page body shown while the block is folded; Ctrl+O expands it. */
@@ -45,42 +46,63 @@ export function detectInlinePageResult(result) {
45
46
  return undefined;
46
47
  const fields = payload;
47
48
  const pageId = fields['page_id'];
48
- const dir = fields['dir'];
49
- if (typeof pageId !== 'string' || typeof dir !== 'string')
49
+ if (typeof pageId !== 'string')
50
50
  return undefined;
51
51
  if (fields['placement'] !== 'inline')
52
52
  return undefined;
53
- return { pageId, dir };
53
+ return { pageId };
54
54
  }
55
- function mtimeOf(path) {
56
- try {
57
- return String(statSync(path).mtimeMs);
58
- }
59
- catch {
60
- return '-';
61
- }
55
+ function projectDisplay(page) {
56
+ return page.document_media_type === 'text/html'
57
+ ? projectHtmlDocumentMarkdown(page.source_document)
58
+ : projectPageDisplayMarkdown(page.source_document, page.page);
62
59
  }
63
60
  export class PageBlockComponent {
64
61
  pageId;
65
- dir;
66
62
  openHint;
67
63
  expanded = false;
68
64
  generation = 0;
69
- stamp = '';
65
+ /** `revision|state` from the last successful read. A replacement selects a
66
+ * new revision and a settlement moves the state, so nothing here depends on
67
+ * a file timestamp or on the directory the page was first projected into. */
68
+ stamp;
70
69
  snapshot;
70
+ /** `loading` until the first read returns; a failed read is never presented
71
+ * as the previous content still being current. */
72
+ status = 'loading';
71
73
  cache;
72
- constructor(pageId, dir, openHint) {
74
+ constructor(pageId, openHint) {
73
75
  this.pageId = pageId;
74
- this.dir = dir;
75
76
  this.openHint = openHint;
76
- this.reload();
77
77
  }
78
- /** Re-read the ticket when its request or its result changed on disk. */
79
- refresh() {
80
- if (this.diskStamp() === this.stamp)
78
+ /** Re-read the request. Resolves true when the rendered content changed, so
79
+ * the caller knows whether to mark the transcript dirty. */
80
+ async refresh() {
81
+ let page;
82
+ try {
83
+ page = (await cliClient().getHumanRequest(this.pageId)).page;
84
+ }
85
+ catch {
86
+ page = undefined;
87
+ }
88
+ if (page === undefined)
89
+ return this.settle('unavailable', undefined, undefined);
90
+ const stamp = `${page.revision}|${page.state}`;
91
+ if (this.status === 'ready' && stamp === this.stamp)
81
92
  return false;
82
- this.reload();
83
- return true;
93
+ let snapshot;
94
+ try {
95
+ snapshot = {
96
+ manifest: page.page,
97
+ displayMarkdown: projectDisplay(page),
98
+ state: page.state,
99
+ ...(page.state === 'resolved' ? withDigest(answerDigestOf(page)) : {}),
100
+ };
101
+ }
102
+ catch {
103
+ return this.settle('unavailable', undefined, stamp);
104
+ }
105
+ return this.settle('ready', snapshot, stamp);
84
106
  }
85
107
  /** Ctrl+O global expansion (ChatView.isExpandable duck-type). */
86
108
  setExpanded(expanded) {
@@ -102,38 +124,22 @@ export class PageBlockComponent {
102
124
  invalidate() {
103
125
  this.cache = undefined;
104
126
  }
105
- diskStamp() {
106
- return `${mtimeOf(pageManifestPath(this.dir))}|${mtimeOf(pagePath(this.dir, 'jsx'))}|${mtimeOf(pagePath(this.dir, 'html'))}|${mtimeOf(responsePath(this.dir))}`;
107
- }
108
- reload() {
109
- this.stamp = this.diskStamp();
127
+ settle(status, snapshot, stamp) {
128
+ if (status === this.status && status === 'unavailable')
129
+ return false;
130
+ this.status = status;
131
+ this.snapshot = snapshot;
132
+ this.stamp = stamp;
110
133
  this.generation++;
111
134
  this.cache = undefined;
112
- try {
113
- const manifest = parsePage(this.dir);
114
- const displayMarkdown = manifest.dialect === 'jsx'
115
- ? projectPageDisplayMarkdown(readFileSync(pagePath(this.dir, 'jsx'), 'utf8'), manifest)
116
- : projectHtmlDocumentMarkdown(readFileSync(pagePath(this.dir, 'html'), 'utf8'));
117
- const state = pageTicketState(this.dir);
118
- const digest = state === 'resolved' ? readTicketResult(this.dir) : null;
119
- this.snapshot = {
120
- manifest,
121
- displayMarkdown,
122
- state,
123
- ...(digest?.kind === 'page' ? { answerDigest: digest.summary.replace(/\s+/g, ' ').trim() } : {}),
124
- };
125
- }
126
- catch {
127
- // A removed or half-written ticket keeps whatever was last read; a block
128
- // that never read one renders its unavailable line instead.
129
- if (this.snapshot === undefined)
130
- this.snapshot = undefined;
131
- }
135
+ return true;
132
136
  }
133
137
  compose(width) {
134
138
  const snapshot = this.snapshot;
135
- if (snapshot === undefined)
136
- return ['', ` ${DIM}[page] no longer available${RESET}`, ''];
139
+ if (snapshot === undefined) {
140
+ const line = this.status === 'loading' ? '[page] loading…' : '[page] no longer available';
141
+ return ['', ` ${DIM}${line}${RESET}`, ''];
142
+ }
137
143
  const maxW = Math.min(Math.max(20, width - 4), 100);
138
144
  const out = ['', ` ${BOLD}${CYAN}${truncate(sanitize(singleLine(snapshot.manifest.title)), maxW)}${RESET}`];
139
145
  if (snapshot.manifest.subtitle) {
@@ -172,3 +178,6 @@ export class PageBlockComponent {
172
178
  }
173
179
  }
174
180
  }
181
+ function withDigest(digest) {
182
+ return digest === undefined ? {} : { answerDigest: digest };
183
+ }