@north-light/crouter 0.3.220 → 0.3.222

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 (271) hide show
  1. package/dist/api/client.d.ts +29 -0
  2. package/dist/api/client.js +44 -0
  3. package/dist/api/dto/chat-inventory.d.ts +56 -0
  4. package/dist/api/dto/chat-inventory.js +11 -0
  5. package/dist/api/dto/human-requests.d.ts +88 -0
  6. package/dist/api/dto/human-requests.js +4 -0
  7. package/dist/api/dto/human.d.ts +3 -0
  8. package/dist/api/dto/profiles.d.ts +19 -5
  9. package/dist/api/dto/profiles.js +2 -1
  10. package/dist/api/dto/reviews.d.ts +2 -0
  11. package/dist/api/index.d.ts +2 -0
  12. package/dist/api/index.js +2 -0
  13. package/dist/api/routes.d.ts +8 -0
  14. package/dist/api/routes.js +11 -0
  15. package/dist/build-root.d.ts +2 -6
  16. package/dist/build-root.js +51 -4
  17. package/dist/builtin-memory/00-runtime-base/00-authoring.md +31 -0
  18. package/dist/builtin-memory/00-runtime-base/01-escalation.md +14 -0
  19. package/dist/builtin-memory/{insights/listen.md → 00-runtime-base/02-insight-capture.md} +1 -0
  20. package/dist/builtin-memory/02-turn-lifecycle/00-ending-a-turn.md +27 -0
  21. package/dist/builtin-memory/{02-lifecycle/01-resident.md → 02-turn-lifecycle/02-resident.md} +5 -0
  22. package/dist/builtin-memory/04-base-worker.md +4 -8
  23. package/dist/builtin-memory/04-orchestration-kernel.md +1 -1
  24. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +1 -0
  25. package/dist/builtin-memory/05-kinds/advisor/advice-contract.md +1 -0
  26. package/dist/builtin-memory/05-kinds/design/00-base.md +2 -1
  27. package/dist/builtin-memory/05-kinds/design/01-orchestrator.md +2 -1
  28. package/dist/builtin-memory/05-kinds/design/design-contract.md +19 -0
  29. package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -0
  30. package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +1 -0
  31. package/dist/builtin-memory/05-kinds/explore/00-base.md +1 -0
  32. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +1 -0
  33. package/dist/builtin-memory/05-kinds/general/00-base.md +1 -0
  34. package/dist/builtin-memory/05-kinds/plan/00-base.md +2 -1
  35. package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +2 -1
  36. package/dist/builtin-memory/05-kinds/plan/plan-contract.md +28 -0
  37. package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +1 -0
  38. package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +1 -0
  39. package/dist/builtin-memory/05-kinds/plan/reviewers/lens-contract.md +1 -0
  40. package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +1 -0
  41. package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -0
  42. package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +1 -0
  43. package/dist/builtin-memory/05-kinds/review/00-base.md +1 -0
  44. package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -0
  45. package/dist/builtin-memory/05-kinds/review/companion/00-base.md +1 -0
  46. package/dist/builtin-memory/05-kinds/review/security-findings.md +1 -0
  47. package/dist/builtin-memory/05-kinds/spec/00-base.md +4 -3
  48. package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +1 -0
  49. package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -0
  50. package/dist/builtin-memory/design/guide.md +35 -0
  51. package/dist/builtin-memory/design/roadmap.md +21 -0
  52. package/dist/builtin-memory/insights/capture.md +1 -1
  53. package/dist/builtin-memory/internal/agent-shaping.md +3 -1
  54. package/dist/builtin-memory/internal/memory-loading.md +4 -0
  55. package/dist/builtin-memory/internal/plugins.md +10 -1
  56. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  57. package/dist/builtin-memory/plan/roadmap.md +6 -22
  58. package/dist/builtin-memory/spec/guide.md +23 -6
  59. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +1 -1
  60. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/crtr-commands/index.ts +7 -1
  61. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +34 -16
  62. package/dist/clients/attach/__tests__/ref-autocomplete.test.js +1 -1
  63. package/dist/clients/attach/__tests__/titled-editor-preview.test.js +1 -1
  64. package/dist/clients/attach/overlays/file-review.js +2 -2
  65. package/dist/clients/attach/render/markdown-source.js +106 -1
  66. package/dist/clients/attach/session/file-links.d.ts +13 -4
  67. package/dist/clients/attach/session/file-links.js +54 -58
  68. package/dist/clients/attach/session/keys.d.ts +1 -1
  69. package/dist/clients/attach/session/profile-files.js +1 -1
  70. package/dist/clients/attach/viewer.js +698 -696
  71. package/dist/clients/inbox/controller.js +1 -1
  72. package/dist/clients/inbox/resolve.d.ts +1 -0
  73. package/dist/clients/inbox/review/launch.d.ts +8 -4
  74. package/dist/clients/inbox/review/launch.js +55 -5
  75. package/dist/clients/inbox/review/review-client.d.ts +1 -0
  76. package/dist/clients/inbox/review/review-client.js +7 -1
  77. package/dist/clients/inbox/review-adapter.d.ts +1 -8
  78. package/dist/clients/inbox/review-adapter.js +4 -52
  79. package/dist/commands/__tests__/human.test.js +2 -2
  80. package/dist/commands/human/request.d.ts +2 -0
  81. package/dist/commands/human/request.js +281 -0
  82. package/dist/commands/human.js +5 -2
  83. package/dist/commands/memory/lint.js +2 -1
  84. package/dist/commands/memory/read.js +1 -0
  85. package/dist/commands/memory.js +1 -1
  86. package/dist/commands/pkg/market-manage.js +165 -75
  87. package/dist/commands/pkg/plugin-inspect.js +19 -2
  88. package/dist/commands/pkg/plugin-manage.d.ts +8 -3
  89. package/dist/commands/pkg/plugin-manage.js +72 -24
  90. package/dist/commands/profile/default.js +6 -10
  91. package/dist/commands/profile/list.js +5 -3
  92. package/dist/commands/profile/new.js +21 -8
  93. package/dist/commands/profile/project.js +25 -19
  94. package/dist/commands/profile/show.js +3 -3
  95. package/dist/commands/surface-inbox.js +1 -0
  96. package/dist/commands/sys/__tests__/migrate.test.js +16 -5
  97. package/dist/commands/sys/config.js +2 -2
  98. package/dist/commands/sys/doctor.js +87 -5
  99. package/dist/commands/sys/migrate.js +38 -19
  100. package/dist/commands/sys/setup-core.js +1 -1
  101. package/dist/commands/sys/sync-project-guidance.js +1 -1
  102. package/dist/core/__tests__/broker-extension-canvas-db-boundary.test.js +7 -4
  103. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +1 -1
  104. package/dist/core/__tests__/fixtures/c5-command-boundary-ext.js +24 -0
  105. package/dist/core/__tests__/fixtures/fake-engine.d.ts +24 -18
  106. package/dist/core/__tests__/fixtures/fake-engine.js +8 -1
  107. package/dist/core/__tests__/fixtures/memory-slash-live-probe.js +71 -0
  108. package/dist/core/__tests__/human-action-delivery.test.d.ts +1 -0
  109. package/dist/core/__tests__/human-action-delivery.test.js +140 -0
  110. package/dist/core/__tests__/human-actions.test.d.ts +1 -0
  111. package/dist/core/__tests__/human-actions.test.js +116 -0
  112. package/dist/core/__tests__/inline-memory-refs.test.js +36 -2
  113. package/dist/core/__tests__/profile-project-memory-delivery.test.d.ts +1 -0
  114. package/dist/core/__tests__/profile-project-memory-delivery.test.js +217 -0
  115. package/dist/core/__tests__/prospective-inventory-capability-parity.test.d.ts +1 -0
  116. package/dist/core/__tests__/prospective-inventory-capability-parity.test.js +91 -0
  117. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.d.ts +1 -0
  118. package/dist/core/__tests__/seam/memory-slash-node-relative-inventory.test.js +127 -0
  119. package/dist/core/__tests__/seam/prospective-inventory-stdout.test.d.ts +1 -0
  120. package/dist/core/__tests__/seam/prospective-inventory-stdout.test.js +31 -0
  121. package/dist/core/__tests__/serial/broker-sdk-wiring.test.js +102 -2
  122. package/dist/core/bootstrap.js +6 -0
  123. package/dist/core/canvas/browse/app.js +5 -2
  124. package/dist/core/canvas/browse/model.d.ts +25 -15
  125. package/dist/core/canvas/browse/model.js +86 -65
  126. package/dist/core/canvas/db.js +23 -0
  127. package/dist/core/canvas/human-deliveries.d.ts +53 -0
  128. package/dist/core/canvas/human-deliveries.js +75 -0
  129. package/dist/core/canvas/render-source.d.ts +6 -0
  130. package/dist/core/canvas/render-source.js +7 -1
  131. package/dist/core/canvas/render.js +10 -2
  132. package/dist/core/command-hooks/artifact.d.ts +10 -0
  133. package/dist/core/command-hooks/artifact.js +129 -0
  134. package/dist/core/command-hooks/catalog.d.ts +14 -0
  135. package/dist/core/command-hooks/catalog.js +38 -0
  136. package/dist/core/command-hooks/compose.d.ts +15 -0
  137. package/dist/core/command-hooks/compose.js +99 -0
  138. package/dist/core/command-hooks/discovery.d.ts +87 -0
  139. package/dist/core/command-hooks/discovery.js +174 -0
  140. package/dist/core/command-hooks/help.d.ts +5 -0
  141. package/dist/core/command-hooks/help.js +18 -0
  142. package/dist/core/command-hooks/index.d.ts +6 -0
  143. package/dist/core/command-hooks/index.js +6 -0
  144. package/dist/core/command-hooks/report.d.ts +23 -0
  145. package/dist/core/command-hooks/report.js +19 -0
  146. package/dist/core/command-hooks/schema.d.ts +27 -0
  147. package/dist/core/command-hooks/schema.js +68 -0
  148. package/dist/core/command-hooks/transport/exec-invoke.d.ts +22 -0
  149. package/dist/core/command-hooks/transport/exec-invoke.js +274 -0
  150. package/dist/core/command-plugins/presence.d.ts +2 -0
  151. package/dist/core/command-plugins/presence.js +17 -0
  152. package/dist/core/command-plugins/transport/exec-invoke.d.ts +5 -0
  153. package/dist/core/command-plugins/transport/exec-invoke.js +58 -5
  154. package/dist/core/command.d.ts +8 -1
  155. package/dist/core/command.js +12 -10
  156. package/dist/core/config.d.ts +13 -1
  157. package/dist/core/config.js +51 -1
  158. package/dist/core/feed/inbox.d.ts +6 -0
  159. package/dist/core/feed/inbox.js +9 -1
  160. package/dist/core/help.d.ts +7 -1
  161. package/dist/core/human/action-binding.d.ts +21 -0
  162. package/dist/core/human/action-binding.js +40 -0
  163. package/dist/core/human/completion.d.ts +38 -0
  164. package/dist/core/human/completion.js +27 -0
  165. package/dist/core/human/convention.d.ts +2 -0
  166. package/dist/core/human/convention.js +2 -0
  167. package/dist/core/human/tickets.d.ts +25 -6
  168. package/dist/core/human/tickets.js +19 -13
  169. package/dist/core/human/types.d.ts +5 -0
  170. package/dist/core/human-actions.d.ts +25 -0
  171. package/dist/core/human-actions.js +101 -0
  172. package/dist/core/io.d.ts +9 -1
  173. package/dist/core/io.js +44 -2
  174. package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
  175. package/dist/core/memory/inline-ref-inventory.js +15 -8
  176. package/dist/core/memory-resolver.d.ts +13 -1
  177. package/dist/core/memory-resolver.js +26 -20
  178. package/dist/core/profiles/manifest.d.ts +13 -2
  179. package/dist/core/profiles/manifest.js +84 -18
  180. package/dist/core/profiles/select.d.ts +2 -0
  181. package/dist/core/profiles/select.js +29 -12
  182. package/dist/core/render.js +11 -0
  183. package/dist/core/runtime/advertised-command-invocation.d.ts +20 -0
  184. package/dist/core/runtime/advertised-command-invocation.js +233 -0
  185. package/dist/core/runtime/bearings.js +1 -1
  186. package/dist/core/runtime/broker/event-projection.js +7 -0
  187. package/dist/core/runtime/broker/frame-dispatch.d.ts +1 -1
  188. package/dist/core/runtime/broker/frame-dispatch.js +13 -11
  189. package/dist/core/runtime/broker/read-ops.d.ts +4 -0
  190. package/dist/core/runtime/broker/read-ops.js +6 -2
  191. package/dist/core/runtime/broker-extension-render.js +1 -1
  192. package/dist/core/runtime/broker-inventory.d.ts +4 -0
  193. package/dist/core/runtime/broker-inventory.js +116 -0
  194. package/dist/core/runtime/broker-persona-guidance.js +1 -1
  195. package/dist/core/runtime/broker-protocol.d.ts +9 -2
  196. package/dist/core/runtime/broker.js +10 -1
  197. package/dist/core/runtime/chat-inventory-rows.d.ts +8 -0
  198. package/dist/core/runtime/chat-inventory-rows.js +105 -0
  199. package/dist/core/runtime/command-surface.d.ts +38 -0
  200. package/dist/core/runtime/command-surface.js +117 -0
  201. package/dist/core/runtime/launch-target.d.ts +25 -0
  202. package/dist/core/runtime/launch-target.js +54 -0
  203. package/dist/core/runtime/node-read.js +5 -0
  204. package/dist/core/runtime/persona.js +3 -3
  205. package/dist/core/runtime/prospective-inventory-cli.d.ts +1 -0
  206. package/dist/core/runtime/prospective-inventory-cli.js +61 -0
  207. package/dist/core/runtime/prospective-inventory.d.ts +10 -0
  208. package/dist/core/runtime/prospective-inventory.js +88 -0
  209. package/dist/core/runtime/spawn.d.ts +3 -1
  210. package/dist/core/runtime/spawn.js +5 -3
  211. package/dist/core/scope.d.ts +26 -1
  212. package/dist/core/scope.js +52 -12
  213. package/dist/core/substrate/on-read.d.ts +7 -1
  214. package/dist/core/substrate/on-read.js +30 -32
  215. package/dist/core/substrate/render-node.d.ts +3 -2
  216. package/dist/core/substrate/render-node.js +3 -2
  217. package/dist/core/substrate/render.js +65 -24
  218. package/dist/core/substrate/schema.d.ts +16 -2
  219. package/dist/core/substrate/schema.js +14 -5
  220. package/dist/core/user-settings.d.ts +4 -0
  221. package/dist/core/user-settings.js +1 -0
  222. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +56 -7
  223. package/dist/daemon/api/handlers/chat-inventory.d.ts +2 -0
  224. package/dist/daemon/api/handlers/chat-inventory.js +25 -0
  225. package/dist/daemon/api/handlers/human-requests.d.ts +2 -0
  226. package/dist/daemon/api/handlers/human-requests.js +409 -0
  227. package/dist/daemon/api/handlers/human.js +3 -0
  228. package/dist/daemon/api/handlers/inbox.js +3 -0
  229. package/dist/daemon/api/handlers/nodes.d.ts +1 -3
  230. package/dist/daemon/api/handlers/nodes.js +11 -46
  231. package/dist/daemon/api/handlers/profiles.js +7 -1
  232. package/dist/daemon/api/handlers/prospective-chat-inventory.d.ts +2 -0
  233. package/dist/daemon/api/handlers/prospective-chat-inventory.js +59 -0
  234. package/dist/daemon/api/handlers/reviews.js +10 -2
  235. package/dist/daemon/api/map.d.ts +2 -1
  236. package/dist/daemon/api/map.js +3 -2
  237. package/dist/daemon/api/server.js +6 -0
  238. package/dist/daemon/crtrd.js +6 -0
  239. package/dist/daemon/human/deliver-action.d.ts +16 -0
  240. package/dist/daemon/human/deliver-action.js +168 -0
  241. package/dist/daemon/human/finish.d.ts +8 -5
  242. package/dist/daemon/human/finish.js +45 -6
  243. package/dist/daemon/human/sweep.js +4 -1
  244. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +10 -0
  245. package/dist/daemon/reconcilers/human-delivery-lane.js +41 -0
  246. package/dist/daemon/review/finish.d.ts +8 -3
  247. package/dist/daemon/review/finish.js +19 -1
  248. package/dist/hook-authoring.d.ts +75 -0
  249. package/dist/hook-authoring.js +358 -0
  250. package/dist/hook-process.d.ts +7 -0
  251. package/dist/hook-process.js +34 -0
  252. package/dist/index.d.ts +2 -0
  253. package/dist/index.js +2 -0
  254. package/dist/migrations/002-profile-project-memory.d.ts +2 -0
  255. package/dist/migrations/002-profile-project-memory.js +71 -0
  256. package/dist/migrations/profile-manifests.d.ts +30 -0
  257. package/dist/migrations/profile-manifests.js +70 -0
  258. package/dist/migrations/registry.js +10 -5
  259. package/dist/migrations/types.d.ts +28 -1
  260. package/dist/migrations/types.js +15 -9
  261. package/dist/pi-extensions/__tests__/canvas-structured-output.test.js +21 -4
  262. package/dist/pi-extensions/canvas-structured-output.js +85 -2
  263. package/dist/types.d.ts +23 -6
  264. package/dist/types.js +1 -0
  265. package/package.json +1 -1
  266. package/runtime.lock.json +2 -2
  267. package/dist/builtin-memory/00-runtime-base.md +0 -55
  268. package/dist/builtin-memory/design.md +0 -55
  269. package/dist/clients/attach/__tests__/file-review-focus.test.js +0 -49
  270. /package/dist/builtin-memory/{02-lifecycle/00-terminal.md → 02-turn-lifecycle/01-terminal.md} +0 -0
  271. /package/dist/{clients/attach/__tests__/file-review-focus.test.d.ts → core/__tests__/fixtures/memory-slash-live-probe.d.ts} +0 -0
@@ -12,11 +12,13 @@ import type { AttachEnsureRequest, AttachEnsureResultDTO } from './dto/attach.js
12
12
  import type { DeleteProfileRequest, DeleteProfileResultDTO, EnsureProfileRequest, ProfileDTO } from './dto/profiles.js';
13
13
  import type { FilePeekDTO } from './dto/files.js';
14
14
  import type { MemoryDocRefDTO } from './dto/memory.js';
15
+ import type { ChatInventoryDTO, ProspectiveChatInventoryDTO, ProspectiveChatInventoryQuery } from './dto/chat-inventory.js';
15
16
  import type { CredentialRemovalResultDTO, CredentialResultDTO, InstallCredentialRequest, ModelAuthListDTO } from './dto/modelauth.js';
16
17
  import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanCancelRequest, HumanCancelResultDTO, HumanResolveRequest, HumanResolveResultDTO } from './dto/human.js';
17
18
  import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, ReviewCancelResultDTO, ReviewDocumentBaseDTO, ReviewDTO, ReviewListDTO, ReviewSubmitResultDTO } from './dto/reviews.js';
18
19
  import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
19
20
  import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageFeedbackResolutionDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
21
+ import type { CreateHumanRequestDTO, CreateHumanRequestRequest, HumanRequestDTO, HumanRequestIdDTO, ReplaceHumanRequestRequest, RespondHumanRequestRequest, SettleHumanRequestRequest } from './dto/human-requests.js';
20
22
  import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
21
23
  import type { CloseWorktreeResultDTO } from './dto/worktree.js';
22
24
  import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
@@ -151,6 +153,12 @@ export declare class CrtrClient {
151
153
  /** The node's conversation exactly as it ran — raw `.jsonl` bytes plus the
152
154
  * assembled system prompt. For exports; `getSnapshot` is for renderers. */
153
155
  getSession(id: string): Promise<NodeSessionDTO>;
156
+ /** What a non-terminal chat surface may offer for this node: the chat-capable
157
+ * slash commands its live engine registered, and the memory documents an
158
+ * inline `/name` token resolves to. Never revives — a node whose broker is
159
+ * not live answers `broker_live: false` with empty arrays. */
160
+ getChatInventory(id: string): Promise<ChatInventoryDTO>;
161
+ getProspectiveChatInventory(q?: ProspectiveChatInventoryQuery): Promise<ProspectiveChatInventoryDTO>;
154
162
  getArtifacts(id: string, q?: ArtifactsQuery): Promise<ArtifactListDTO>;
155
163
  getContext(id: string): Promise<ContextListDTO>;
156
164
  /** Read an absolute host path as UTF-8 (capped, `truncated` when clipped) for
@@ -160,6 +168,9 @@ export declare class CrtrClient {
160
168
  * node would read — the node's own precedence chain, not this process's.
161
169
  * Pair with `peekFile` to render the document. */
162
170
  resolveMemoryDoc(name: string, nodeId: string): Promise<MemoryDocRefDTO>;
171
+ /** Create-or-return by name. Supplied `projects` are shape-checked even when
172
+ * the profile already exists; their directories are only required to exist
173
+ * when this call creates the profile. */
163
174
  ensureProfile(name: string, req?: EnsureProfileRequest): Promise<ProfileDTO>;
164
175
  listProfiles(): Promise<ProfileDTO[]>;
165
176
  getProfile(name: string): Promise<ProfileDTO>;
@@ -211,6 +222,24 @@ export declare class CrtrClient {
211
222
  getInboxResponse(ticketId: InboxTicketIdDTO): Promise<InboxPageResponseDTO>;
212
223
  /** Cancel a ticket (terminal response, never deletion). */
213
224
  cancelHumanInboxTicket(ticketId: InboxTicketIdDTO, request?: CancelInboxTicketRequest): Promise<CanceledTicketResultDTO>;
225
+ /** Create one durable human request. Its `request_id` is the same opaque id
226
+ * the inbox routes address, so the request and the inbox ticket are one
227
+ * record. An unresolvable `action.name` is rejected before the page is
228
+ * published, leaving no inbox row behind. */
229
+ createHumanRequest(request: CreateHumanRequestRequest): Promise<CreateHumanRequestDTO>;
230
+ /** Read one request: its current state, its answer when answered, and the
231
+ * delivery state of its completion action when it bound one. */
232
+ getHumanRequest(requestId: HumanRequestIdDTO): Promise<HumanRequestDTO>;
233
+ /** Revise a pending request's page in place. Identity, provenance, and the
234
+ * frozen action binding are preserved; a settled request refuses. */
235
+ replaceHumanRequest(requestId: HumanRequestIdDTO, request: ReplaceHumanRequestRequest): Promise<HumanRequestDTO>;
236
+ /** Settle a request `answered` programmatically. Races a human answer to the
237
+ * same first-writer-wins result. */
238
+ respondHumanRequest(requestId: HumanRequestIdDTO, request: RespondHumanRequestRequest): Promise<HumanRequestDTO>;
239
+ /** The recipient surface closing a request without answering. */
240
+ dismissHumanRequest(requestId: HumanRequestIdDTO, request?: SettleHumanRequestRequest): Promise<HumanRequestDTO>;
241
+ /** The requester withdrawing its own request. */
242
+ cancelHumanRequest(requestId: HumanRequestIdDTO, request?: SettleHumanRequestRequest): Promise<HumanRequestDTO>;
214
243
  /** Resolve one page feedback comment — the bound companion's report that it
215
244
  * has been dealt with. `nodeId` names the caller; the daemon refuses any
216
245
  * node but the ticket's companion. Terminal for the comment; appends no
@@ -267,6 +267,16 @@ export class CrtrClient {
267
267
  getSession(id) {
268
268
  return this.request('GET', routes.nodeSession(this.nodePath(id)));
269
269
  }
270
+ /** What a non-terminal chat surface may offer for this node: the chat-capable
271
+ * slash commands its live engine registered, and the memory documents an
272
+ * inline `/name` token resolves to. Never revives — a node whose broker is
273
+ * not live answers `broker_live: false` with empty arrays. */
274
+ getChatInventory(id) {
275
+ return this.request('GET', routes.nodeChatInventory(this.nodePath(id)));
276
+ }
277
+ getProspectiveChatInventory(q) {
278
+ return this.request('GET', withQuery(routes.prospectiveChatInventory(), q));
279
+ }
270
280
  getArtifacts(id, q) {
271
281
  return this.request('GET', withQuery(routes.nodeArtifacts(this.nodePath(id)), q));
272
282
  }
@@ -287,6 +297,9 @@ export class CrtrClient {
287
297
  return this.request('GET', withQuery(routes.memoryResolve(), { name, node: nodeId }));
288
298
  }
289
299
  // ---- Profiles ----------------------------------------------------------
300
+ /** Create-or-return by name. Supplied `projects` are shape-checked even when
301
+ * the profile already exists; their directories are only required to exist
302
+ * when this call creates the profile. */
290
303
  ensureProfile(name, req) {
291
304
  return this.request('PUT', routes.profile(name), req ?? {});
292
305
  }
@@ -416,6 +429,37 @@ export class CrtrClient {
416
429
  cancelHumanInboxTicket(ticketId, request) {
417
430
  return this.request('POST', routes.humanInboxCancel(this.ticketId(ticketId)), request ?? {});
418
431
  }
432
+ // ---- Durable programmatic human requests -------------------------------
433
+ /** Create one durable human request. Its `request_id` is the same opaque id
434
+ * the inbox routes address, so the request and the inbox ticket are one
435
+ * record. An unresolvable `action.name` is rejected before the page is
436
+ * published, leaving no inbox row behind. */
437
+ createHumanRequest(request) {
438
+ return this.request('POST', routes.humanRequests(), request);
439
+ }
440
+ /** Read one request: its current state, its answer when answered, and the
441
+ * delivery state of its completion action when it bound one. */
442
+ getHumanRequest(requestId) {
443
+ return this.request('GET', routes.humanRequest(this.ticketId(requestId)));
444
+ }
445
+ /** Revise a pending request's page in place. Identity, provenance, and the
446
+ * frozen action binding are preserved; a settled request refuses. */
447
+ replaceHumanRequest(requestId, request) {
448
+ return this.request('POST', routes.humanRequestReplace(this.ticketId(requestId)), request);
449
+ }
450
+ /** Settle a request `answered` programmatically. Races a human answer to the
451
+ * same first-writer-wins result. */
452
+ respondHumanRequest(requestId, request) {
453
+ return this.request('POST', routes.humanRequestRespond(this.ticketId(requestId)), request);
454
+ }
455
+ /** The recipient surface closing a request without answering. */
456
+ dismissHumanRequest(requestId, request = {}) {
457
+ return this.request('POST', routes.humanRequestDismiss(this.ticketId(requestId)), request);
458
+ }
459
+ /** The requester withdrawing its own request. */
460
+ cancelHumanRequest(requestId, request = {}) {
461
+ return this.request('POST', routes.humanRequestCancel(this.ticketId(requestId)), request);
462
+ }
419
463
  /** Resolve one page feedback comment — the bound companion's report that it
420
464
  * has been dealt with. `nodeId` names the caller; the daemon refuses any
421
465
  * node but the ticket's companion. Terminal for the comment; appends no
@@ -0,0 +1,56 @@
1
+ /** One command a chat surface may advertise. Builtin and non-opted-in rows are
2
+ * dropped before this DTO exists, so `source` never carries `'builtin'`. */
3
+ export interface ChatInventoryCommandDTO {
4
+ /** No leading slash, exactly as the engine dispatches it. */
5
+ name: string;
6
+ description: string;
7
+ source: 'command' | 'template';
8
+ /** Argument shape to display beside the name, when the command supplies one. */
9
+ argument_hint?: string;
10
+ /** Deterministic expansion metadata for a memory-slash command — the same
11
+ * material the terminal preview uses, so a chat preview cannot drift from
12
+ * what submission sends. */
13
+ expansion?: {
14
+ kind: 'memory-slash';
15
+ commandName: string;
16
+ body: string;
17
+ };
18
+ /** Raw prompt-template content (frontmatter stripped), for `source: 'template'`. */
19
+ template?: string;
20
+ }
21
+ /** One resolvable inline memory reference. Metadata only — never the document
22
+ * body or its source path. `shortForm` stays camelCase to mirror the broker's
23
+ * own `RefMeta`, which is where these rows come from. */
24
+ export interface ChatInventoryMemoryRefDTO {
25
+ /** Canonical `/`-joined name, e.g. `taste/writing`. */
26
+ name: string;
27
+ kind: 'knowledge' | 'preference';
28
+ scope: 'node' | 'project' | 'profile' | 'user' | 'builtin';
29
+ shortForm: string;
30
+ }
31
+ /** `GET /v1/nodes/{id}/chat-inventory` result.
32
+ *
33
+ * `broker_live` reports whether the node's engine was reachable at all. There
34
+ * is no per-part error flag: a part that failed and a part that is genuinely
35
+ * empty both arrive as an empty array, and a client's behavior is identical
36
+ * for both. A dormant node answers 200 with `broker_live: false` — this read
37
+ * never revives an engine. */
38
+ export interface ChatInventoryDTO {
39
+ node_id: string;
40
+ broker_live: boolean;
41
+ commands: ChatInventoryCommandDTO[];
42
+ memory_refs: ChatInventoryMemoryRefDTO[];
43
+ }
44
+ /** Session-less inventory for the launch target a create would resolve. */
45
+ export interface ProspectiveChatInventoryDTO {
46
+ profile_id: string | null;
47
+ cwd: string;
48
+ commands: ChatInventoryCommandDTO[];
49
+ memory_refs: ChatInventoryMemoryRefDTO[];
50
+ }
51
+ export interface ProspectiveChatInventoryQuery {
52
+ profile?: string;
53
+ cwd?: string;
54
+ /** Same optional kind operand as POST /v1/nodes. */
55
+ kind?: string;
56
+ }
@@ -0,0 +1,11 @@
1
+ // Chat-inventory DTO. Backs `GET /v1/nodes/{id}/chat-inventory` — the one read
2
+ // a non-terminal chat surface makes to learn what the node's live engine will
3
+ // accept: the slash commands that can complete their outcome from a chat
4
+ // conversation, and the memory documents an inline `/name` token resolves to.
5
+ //
6
+ // Eligibility is decided in crouter and disclosed here. A client never filters
7
+ // by name, infers capability, or invents a row: what is absent from these
8
+ // arrays is not offered.
9
+ //
10
+ // PURITY (spec §3.1): Node built-ins + `src/api/*` only.
11
+ export {};
@@ -0,0 +1,88 @@
1
+ import type { IsoTime } from './common.js';
2
+ import type { InboxTicketIdDTO, PageResponsesDTO, TicketSourceDTO } from './inbox.js';
3
+ /** A request id IS an opaque inbox ticket id: lowercase 64-hex. */
4
+ export type HumanRequestIdDTO = InboxTicketIdDTO;
5
+ /** The complete authored page text, inline — never a path. */
6
+ export interface HumanRequestPageDTO {
7
+ dialect: 'jsx' | 'html';
8
+ source: string;
9
+ }
10
+ export interface HumanRequestDeliveryDTO {
11
+ placement: 'inline' | 'panel';
12
+ inbox: boolean;
13
+ reply: boolean;
14
+ }
15
+ /** Frozen at creation: the action name and its opaque payload. An omitted
16
+ * `payload` is frozen as JSON null, so the completion document always carries it. */
17
+ export interface HumanRequestActionDTO {
18
+ name: string;
19
+ payload?: unknown;
20
+ }
21
+ export interface CreateHumanRequestRequest {
22
+ page: HumanRequestPageDTO;
23
+ delivery?: HumanRequestDeliveryDTO;
24
+ source?: TicketSourceDTO;
25
+ creator_cwd: string;
26
+ action?: HumanRequestActionDTO;
27
+ }
28
+ export type HumanRequestState = 'pending' | 'answered' | 'dismissed' | 'canceled';
29
+ export type HumanRequestDeliveryState = 'none' | 'pending' | 'running' | 'accepted' | 'permanent_failed';
30
+ export interface CreateHumanRequestDTO {
31
+ request_id: HumanRequestIdDTO;
32
+ state: 'pending';
33
+ /** Omitted entirely when the request carries no action binding. */
34
+ action?: {
35
+ name: string;
36
+ };
37
+ delivery_state: HumanRequestDeliveryState;
38
+ }
39
+ export interface HumanRequestDeliveryFailureDTO {
40
+ kind: 'exit' | 'signal' | 'timeout' | 'spawn_error';
41
+ exit_code?: number;
42
+ signal?: string;
43
+ message?: string;
44
+ /** A bounded tail, not full output. */
45
+ stderr?: string;
46
+ }
47
+ export interface HumanRequestDeliveryDetailDTO {
48
+ state: HumanRequestDeliveryState;
49
+ /** Attempts started. */
50
+ attempt: number;
51
+ /** Present only while pending after a retryable failure. */
52
+ next_attempt_at?: IsoTime;
53
+ accepted_at?: IsoTime;
54
+ permanent_failed_at?: IsoTime;
55
+ last_failure?: HumanRequestDeliveryFailureDTO;
56
+ }
57
+ export interface HumanRequestDTO {
58
+ request_id: HumanRequestIdDTO;
59
+ state: HumanRequestState;
60
+ title: string;
61
+ subtitle?: string;
62
+ source: TicketSourceDTO;
63
+ emitted_at: IsoTime;
64
+ /** Present unless pending. */
65
+ settled_at?: IsoTime;
66
+ /** Present only when `state` is `answered`. */
67
+ responses?: PageResponsesDTO;
68
+ reason?: string;
69
+ actor?: string;
70
+ /** `action` and `delivery` are both omitted when no action is bound. */
71
+ action?: {
72
+ name: string;
73
+ payload: unknown;
74
+ };
75
+ delivery?: HumanRequestDeliveryDetailDTO;
76
+ }
77
+ export interface ReplaceHumanRequestRequest {
78
+ page: HumanRequestPageDTO;
79
+ delivery?: HumanRequestDeliveryDTO;
80
+ }
81
+ export interface RespondHumanRequestRequest {
82
+ responses: PageResponsesDTO;
83
+ actor?: string;
84
+ }
85
+ export interface SettleHumanRequestRequest {
86
+ reason?: string;
87
+ actor?: string;
88
+ }
@@ -0,0 +1,4 @@
1
+ // Durable programmatic human-request DTOs — crtrd `/v1/human/requests`. The
2
+ // envelope is snake_case; nested page-protocol objects keep their canonical
3
+ // camelCase names, matching the inbox DTOs.
4
+ export {};
@@ -44,6 +44,9 @@ export interface HumanResolveRequest {
44
44
  export interface HumanCancelRequest {
45
45
  reason?: string;
46
46
  actor?: string;
47
+ /** The recipient surface closing it sends `dismissed`; a requester retracting
48
+ * it sends `canceled` or omits the field. */
49
+ disposition?: 'canceled' | 'dismissed';
47
50
  }
48
51
  /** `POST /v1/human/tickets/{ticket_id}/resolve` result. */
49
52
  export interface HumanResolveResultDTO {
@@ -1,8 +1,22 @@
1
+ /** The disclosure ladder, lowest to highest. Index order is the ordering. */
2
+ export declare const PROFILE_PROJECT_MEMORY_VALUES: readonly ["none", "name", "preview", "content"];
3
+ /** How much of a project's memory stores the profile relationship lets an
4
+ * automatic delivery disclose. */
5
+ export type ProfileProjectMemory = (typeof PROFILE_PROJECT_MEMORY_VALUES)[number];
6
+ /** One project directory in a profile's purview. */
7
+ export interface ProfileProject {
8
+ /** Absolute, real-path-resolved directory. */
9
+ path: string;
10
+ /** Maximum rung automatic boot and workspace-open delivery may reach from
11
+ * this project's memory stores, regardless of the node's working directory.
12
+ * An authored lower rung stays lower; targeted reads are never capped. */
13
+ memory: ProfileProjectMemory;
14
+ }
1
15
  /** `PUT /v1/profiles/{name}` body — idempotent ensure. Every field applies
2
16
  * only at create; an existing same-named profile is returned untouched. */
3
17
  export interface EnsureProfileRequest {
4
- /** Absolute project directories in the profile's purview. */
5
- projects?: string[];
18
+ /** Project directories in the profile's purview, each with its memory cap. */
19
+ projects?: ProfileProject[];
6
20
  /** Persona kind for node creates under the profile that omit kind. */
7
21
  default_kind?: string;
8
22
  /** Profile facts (identity, role); each entry reaches every broker
@@ -37,9 +51,9 @@ export interface ProfileDTO {
37
51
  /** Stable profile-directory id (`<slug>-<id>`). */
38
52
  id: string;
39
53
  name: string;
40
- projects: string[];
41
- /** Where nodes under this profile run — one of `projects` (the first unless
42
- * re-pointed), or null when the profile owns none. */
54
+ projects: ProfileProject[];
55
+ /** Where nodes under this profile run — one of `projects[].path` (the first
56
+ * unless re-pointed), or null when the profile owns none. */
43
57
  home: string | null;
44
58
  /** ISO timestamp when the profile was paused, or null while active. */
45
59
  paused_at: string | null;
@@ -1,3 +1,4 @@
1
1
  // Profile DTOs (spec §6.6). Profile deletion crosses profile, canvas, cron,
2
2
  // inbox, and review state, so every consumer routes it through crtrd.
3
- export {};
3
+ /** The disclosure ladder, lowest to highest. Index order is the ordering. */
4
+ export const PROFILE_PROJECT_MEMORY_VALUES = ['none', 'name', 'preview', 'content'];
@@ -93,6 +93,8 @@ export interface ReviewCancelResultDTO {
93
93
  export interface CancelReviewRequest {
94
94
  reason?: string;
95
95
  actor?: string;
96
+ /** Recipient surfaces send `dismissed`; a requester withdrawal defaults to `canceled`. */
97
+ disposition?: 'canceled' | 'dismissed';
96
98
  }
97
99
  /** Daemon-derived coordinate base for the terminal review surface. */
98
100
  export interface ReviewDocumentBaseDTO {
@@ -25,5 +25,7 @@ export * from './dto/human.js';
25
25
  export * from './dto/files.js';
26
26
  export * from './dto/memory.js';
27
27
  export * from './dto/inbox.js';
28
+ export * from './dto/human-requests.js';
28
29
  export * from './dto/reviews.js';
29
30
  export * from './dto/review-comments.js';
31
+ export * from './dto/chat-inventory.js';
package/dist/api/index.js CHANGED
@@ -26,5 +26,7 @@ export * from './dto/human.js';
26
26
  export * from './dto/files.js';
27
27
  export * from './dto/memory.js';
28
28
  export * from './dto/inbox.js';
29
+ export * from './dto/human-requests.js';
29
30
  export * from './dto/reviews.js';
30
31
  export * from './dto/review-comments.js';
32
+ export * from './dto/chat-inventory.js';
@@ -11,6 +11,8 @@ export declare const routes: {
11
11
  readonly nodeSnapshot: (id: string) => string;
12
12
  readonly nodeSubject: (id: string) => string;
13
13
  readonly nodeSession: (id: string) => string;
14
+ readonly nodeChatInventory: (id: string) => string;
15
+ readonly prospectiveChatInventory: () => string;
14
16
  readonly nodeTranscript: (id: string) => string;
15
17
  readonly nodeContext: (id: string) => string;
16
18
  readonly nodeArtifacts: (id: string) => string;
@@ -83,6 +85,12 @@ export declare const routes: {
83
85
  readonly humanInboxResponse: (ticketId: string) => string;
84
86
  readonly humanInboxCancel: (ticketId: string) => string;
85
87
  readonly humanInboxFeedbackResolve: (ticketId: string, commentId: string) => string;
88
+ readonly humanRequests: () => string;
89
+ readonly humanRequest: (requestId: string) => string;
90
+ readonly humanRequestReplace: (requestId: string) => string;
91
+ readonly humanRequestRespond: (requestId: string) => string;
92
+ readonly humanRequestDismiss: (requestId: string) => string;
93
+ readonly humanRequestCancel: (requestId: string) => string;
86
94
  readonly profiles: () => string;
87
95
  readonly profile: (name: string) => string;
88
96
  readonly modelAuths: () => string;
@@ -27,6 +27,8 @@ export const routes = {
27
27
  nodeSnapshot: (id) => `${V}/nodes/${id}/snapshot`,
28
28
  nodeSubject: (id) => `${V}/nodes/${id}/subject`,
29
29
  nodeSession: (id) => `${V}/nodes/${id}/session`,
30
+ nodeChatInventory: (id) => `${V}/nodes/${id}/chat-inventory`,
31
+ prospectiveChatInventory: () => `${V}/prospective-chat-inventory`,
30
32
  nodeTranscript: (id) => `${V}/nodes/${id}/transcript`,
31
33
  nodeContext: (id) => `${V}/nodes/${id}/context`,
32
34
  nodeArtifacts: (id) => `${V}/nodes/${id}/artifacts`,
@@ -110,6 +112,15 @@ export const routes = {
110
112
  humanInboxResponse: (ticketId) => `${V}/human/inbox/${ticketId}/response`,
111
113
  humanInboxCancel: (ticketId) => `${V}/human/inbox/${ticketId}/cancel`,
112
114
  humanInboxFeedbackResolve: (ticketId, commentId) => `${V}/human/inbox/${ticketId}/feedback-comments/${commentId}/resolve`,
115
+ // Durable programmatic human requests. `request_id` is the same opaque
116
+ // inbox ticket id the `/v1/human/inbox` routes address, so one request is one
117
+ // record across both surfaces.
118
+ humanRequests: () => `${V}/human/requests`,
119
+ humanRequest: (requestId) => `${V}/human/requests/${requestId}`,
120
+ humanRequestReplace: (requestId) => `${V}/human/requests/${requestId}/replace`,
121
+ humanRequestRespond: (requestId) => `${V}/human/requests/${requestId}/respond`,
122
+ humanRequestDismiss: (requestId) => `${V}/human/requests/${requestId}/dismiss`,
123
+ humanRequestCancel: (requestId) => `${V}/human/requests/${requestId}/cancel`,
113
124
  // Profiles (deletion is daemon-owned because it crosses canvas state)
114
125
  profiles: () => `${V}/profiles`,
115
126
  profile: (name) => `${V}/profiles/${name}`,
@@ -1,13 +1,9 @@
1
1
  import type { RootDef } from './core/command.js';
2
+ import { type CoreHookCatalog } from './core/command-hooks/catalog.js';
2
3
  /** Every shipped subtree name. Cheap (no module loading) — the front-door
3
4
  * recursion guard and the dispatcher's first-token routing need only names. */
4
5
  export declare const SUBTREE_NAMES: readonly string[];
5
- /** Every core command path, space-joined ("cron", "cron add", …) — the set
6
- * plugin `helpAddenda` keys are validated against at the strict gates
7
- * (install, bundle parse, doctor/inspect reports). Loads every core subtree,
8
- * so call it only from those gates, never on a dispatch path. Passthrough
9
- * branches are excluded: crtr never renders their help, so an addendum
10
- * targeting one could never appear. */
6
+ export declare function coreHookCatalog(): Promise<CoreHookCatalog>;
11
7
  export declare function coreCommandPaths(): Promise<ReadonlySet<string>>;
12
8
  /** Build a root that contains only the subtree `first` dispatches into.
13
9
  * Returns the FULL root when `first` is not a recognized subtree — bare `crtr`,
@@ -1,4 +1,7 @@
1
1
  import { defineRoot } from './core/command.js';
2
+ import { createCoreHookCatalog } from './core/command-hooks/catalog.js';
3
+ import { composeCoreHooks } from './core/command-hooks/compose.js';
4
+ import { mark } from './core/timing.js';
2
5
  const TAGLINE = 'crtr: agentic runtime.';
3
6
  /** Flags handled before dispatch, so they belong to no leaf schema and are
4
7
  * stated once at root (help.ts renders them as the Globals footer). */
@@ -43,8 +46,51 @@ export const SUBTREE_NAMES = Object.freeze(Object.keys(SUBTREE_LOADERS));
43
46
  * so call it only from those gates, never on a dispatch path. Passthrough
44
47
  * branches are excluded: crtr never renders their help, so an addendum
45
48
  * targeting one could never appear. */
49
+ /** Every core subtree, built once per process. The hook catalog and the full
50
+ * root both need the complete set; a recognized core first token still loads
51
+ * only its own subtree until something actually demands the whole tree. */
52
+ let coreSubtrees;
53
+ function loadCoreSubtrees() {
54
+ coreSubtrees ??= Promise.all(SUBTREE_NAMES.map((n) => SUBTREE_LOADERS[n]()));
55
+ return coreSubtrees;
56
+ }
57
+ /** Complete static catalog of hook-eligible core leaves. Lifecycle and recovery
58
+ * inspection share the same memoized subtree load as root composition. */
59
+ let hookCatalog;
60
+ export function coreHookCatalog() {
61
+ mark('cli.hooks.catalog');
62
+ hookCatalog ??= loadCoreSubtrees().then(createCoreHookCatalog);
63
+ return hookCatalog;
64
+ }
65
+ /** A loader for the effective hook registry, compiled over the COMPLETE core
66
+ * catalog so a hook targeting any other subtree is never mistaken for a stale
67
+ * target. Loading is lazy — only eligible leaf help or dispatch reaches it,
68
+ * and static help discovery never runs a plugin executable. The memoization
69
+ * is per composed root, never process-global: discovery reads
70
+ * stored plugin bytes and the caller's scope stack, so a plugin install,
71
+ * update, or disable (and a cwd change in a long-lived host) must govern the
72
+ * next root instead of being pinned by the first one. */
73
+ function hookRegistryLoader() {
74
+ let registry;
75
+ return () => {
76
+ // Dynamic import keeps hook discovery (manifest/artifact validation, plugin
77
+ // resolution) off the module graph of an invocation that neither renders
78
+ // eligible leaf help nor dispatches one, matching this file's lazy rationale.
79
+ registry ??= (async () => {
80
+ const { compileHookRegistry, effectiveHookPlugins } = await import('./core/command-hooks/discovery.js');
81
+ const plugins = effectiveHookPlugins();
82
+ mark('cli.hooks.effective_plugins', { count: plugins.length });
83
+ if (plugins.length === 0) {
84
+ mark('cli.hooks.empty_registry');
85
+ return compileHookRegistry(createCoreHookCatalog([]), []);
86
+ }
87
+ return compileHookRegistry(await coreHookCatalog(), plugins);
88
+ })();
89
+ return registry;
90
+ };
91
+ }
46
92
  export async function coreCommandPaths() {
47
- const core = await Promise.all(SUBTREE_NAMES.map((n) => SUBTREE_LOADERS[n]()));
93
+ const core = await loadCoreSubtrees();
48
94
  const paths = new Set();
49
95
  const visit = (node, prefix) => {
50
96
  if (node.kind === 'branch' && node.passthrough !== undefined)
@@ -67,7 +113,7 @@ export async function coreCommandPaths() {
67
113
  export async function resolveRoot(first) {
68
114
  const loader = first !== undefined ? SUBTREE_LOADERS[first] : undefined;
69
115
  if (loader !== undefined) {
70
- return defineRoot({ tagline: TAGLINE, globals: GLOBALS, subtrees: [await loader()] });
116
+ return defineRoot({ tagline: TAGLINE, globals: GLOBALS, subtrees: composeCoreHooks([await loader()], hookRegistryLoader()) });
71
117
  }
72
118
  return buildRoot();
73
119
  }
@@ -88,7 +134,7 @@ export async function resolveRoot(first) {
88
134
  * HTTP-transport plugin manifest replacement takes effect on the next invocation
89
135
  * automatically. Composition performs no network I/O. */
90
136
  export async function buildRoot() {
91
- const core = await Promise.all(SUBTREE_NAMES.map((n) => SUBTREE_LOADERS[n]()));
137
+ const core = await loadCoreSubtrees();
92
138
  // Dynamic import keeps external command discovery/compose (plugin +
93
139
  // HTTP-transport plugin, and their resolver/manifest/HTTP deps) OFF the hot leaf
94
140
  // path's module graph — they load only here, on the fallthrough, matching
@@ -102,5 +148,6 @@ export async function buildRoot() {
102
148
  // sys doctor). Reads only stored manifests — zero network.
103
149
  const snapshot = buildExternalCommandSnapshot(new Set(SUBTREE_NAMES));
104
150
  const external = composeExternalSubtrees(snapshot);
105
- return defineRoot({ tagline: TAGLINE, globals: GLOBALS, subtrees: [...core, ...external] });
151
+ // Only core leaves are hookable, so external contributions compose unwrapped.
152
+ return defineRoot({ tagline: TAGLINE, globals: GLOBALS, subtrees: [...composeCoreHooks(core, hookRegistryLoader()), ...external] });
106
153
  }
@@ -0,0 +1,31 @@
1
+ ---
2
+ kind: preference
3
+ when-and-why-to-read: When a node writes an artifact, report, or decision for another reader, this preference should be read because current, concrete records let the next action proceed without reconstructing stale context or invented terminology.
4
+ rationale: >-
5
+ The living-document paragraph ("Living documents") exists because agents default to appending — plans kept old+new versions side by side, answered Q&A sections stayed behind after the answer was folded in, findings docs grew contradicted layers (observed by Silas, 2026-07-08). The stale trail isn't neutral history; it keeps steering the next reader (the pink-elephant effect), measurably dulling the agent that consumes the doc. Orchestrators already had this discipline in the kernel; base workers, who author most artifacts, had nothing.
6
+
7
+ "Say what actually happens" exists because an approval request called a root a person had created an "attended root" — an invented category with no referent in the product, which forced Silas to halt the decision and ask what the term meant (2026-07-28). Agents coin taxonomies to compress a distinction; the reader pays by decoding a word that names nothing real.
8
+
9
+ The Mermaid line exists because the viewer's inline diagram affordance is otherwise invisible to an agent working from ordinary Markdown defaults.
10
+
11
+ An "Identity" section is deliberately absent, and the artifacts section carries no paths. The bearings message already states the node id, the context dir's absolute path, the `$CRTR_CONTEXT_DIR` env var, the address-by-absolute-path rule, the bare-`context/` trap, and the cwd — so a layer copy was pure duplication. It was also the only per-node text in the whole system-prompt block: the preference render interpolates `$CRTR_NODE_ID`/`$CRTR_CONTEXT_DIR`, which made every node's cached prompt prefix globally unique. Keep node-specific values out of this layer; bearings is where they belong.
12
+ lint-ignore: length
13
+ surfaces:
14
+ - on: boot
15
+ at: content
16
+ ---
17
+
18
+ ## Working in the canvas
19
+ You are a **node** in a live agent graph (the crtr canvas). This section is your operating protocol — it is true for every node regardless of role.
20
+
21
+ ## Artifacts
22
+ An artifact you write to your context dir is shared by pointer: whatever carries it — a report, a reply, an ask — names its absolute path, never the full substance pasted in.
23
+
24
+ ## Living documents
25
+ Every doc you keep — artifact, plan, findings, memory — is a living statement of what is true *now*, never a log of how it got that way. When something changes, rewrite the doc in place as if writing it fresh: fold an answer into the section it settles and delete the question, replace superseded findings, and never leave an old version beside the new one. Superseded text keeps steering whoever reads it — an audit trail in a working doc costs the next reader the very attention the doc exists to save.
26
+
27
+ ## Say what actually happens
28
+ Everything you write — replies, reports, approval requests, artifacts, memory docs, comments — describes systems in concrete, existing product terms: the real command, the real event, the actual cause. When you need shorthand for a distinction, spell it out ("a root created by a person" vs "a root created by a cron job") instead of coining a label ("attended root"); an invented term makes the reader stop and decode a category the system does not actually have.
29
+
30
+ ## Mermaid diagrams
31
+ When visual structure would land faster than prose, use a Mermaid fence; the user's terminal viewer renders it inline.
@@ -0,0 +1,14 @@
1
+ ---
2
+ kind: preference
3
+ when-and-why-to-read: When progress depends on a person deciding, reviewing, or responding, or when a crtr command fails unexpectedly, this preference should be read because the runtime can deliver the needed signal to its actual recipient instead of leaving work stranded in conversation prose.
4
+ rationale: The human inbox and system-feedback commands are delivery paths whose effects are otherwise invisible in ordinary conversation.
5
+ surfaces:
6
+ - on: boot
7
+ at: content
8
+ ---
9
+
10
+ ## When blocked, want feedback, or need the user
11
+ Don't guess at a decision a person should make. Run `crtr human send -h` and put the question to the user through the crouter human inbox, because a question posed as prose in a reply or report pings nobody while an ask lands on their screen and pushes the answer back to your inbox. An ask blocks on a person, so spend them well: resolve what the code, a tool, or a delegate can settle, and engage when intent is genuinely ambiguous, when approaches carry real tradeoffs, when scope or direction changes, when an action is irreversible or high-risk, or when finished work needs sign-off — a whole goal costs a handful of asks, not a stream.
12
+
13
+ ## When crtr itself misbehaves
14
+ A `crtr` command that errors unexpectedly, hangs, churns, double-spawns, or contradicts its own `-h` is a harness bug — don't silently work around it. Run `crtr sys feedback` to report it (`-h` for how), then continue.
@@ -7,4 +7,5 @@ surfaces:
7
7
  at: content
8
8
  ---
9
9
 
10
+ ## When user knowledge should persist
10
11
  When directly received user-supplied or user-validated material may contain a coherent reusable principle, follow [[insights/capture]]. Use an active domain listener's boundary when one matches; otherwise use the higher bar: the episode must justify a permanent reusable principle future agents should be routed to, and a new domain needs that principle as its first approved truth. Do not treat approval of an insight review as a fresh candidate, because user knowledge unavailable from model weights should not disappear with the episode.
@@ -0,0 +1,27 @@
1
+ ---
2
+ kind: preference
3
+ when-and-why-to-read: When a node has no immediate action because it awaits an event, a person, or a fresh context window, this preference should be read because ending the turn through the matching runtime path preserves wakeability without wasting a live window or losing an unanswered decision.
4
+ rationale: >-
5
+ "Waiting is a way to end a turn" lived in its own ungated all-node doc until 2026-07-28. Same gate, same audience, never independently readable — so the split bought no routing and cost a stub cross-reference in runtime-base pointing at a section spliced a few hundred tokens later. It now has its own sort position as the turn-lifecycle preamble; split it again only when a section needs its own sort position, incident rationale, or independent deletion/re-gate decision.
6
+
7
+ Yield applies to every node regardless of mode; promotion does not, because only the mode layers own that boundary — 04-base-worker for when a base node should promote, the kernel for how an orchestrator uses promotion — so restating it in the universal layer duplicated the base-worker text for an audience that includes nodes it does not apply to.
8
+ lint-ignore: length
9
+ surfaces:
10
+ - on: boot
11
+ at: content
12
+ ---
13
+
14
+ ## Waiting is a way to end a turn
15
+
16
+ When your goal is sound but your next step is blocked on something that has not happened yet — a child's report, the user, a CI run, tomorrow morning — you are **waiting**. Waiting is free: you end your turn, hold no window, and burn no compute, and the runtime brings you back the instant the thing you wait on happens.
17
+
18
+ - **Never busy-wait.** Do not hold your window open to re-poll a URL or watch a clock. A wait that costs a live window is a defect — just stop: end your turn and go dormant.
19
+ - **For waits the runtime already knows — a child's report or the reply to your own human page — just stop.** Go dormant; the runtime wakes you when it lands. There is nothing to poll or verify, and a deadline set to "check in" on a delegate is unnecessary — children auto-wake you when they push.
20
+ - **Schedule a wake yourself only when nothing can push to you** — recurring or scheduled standing work, or polling an external the spine can't deliver (CI, a deploy, a clock). Run `crtr cron -h` to schedule the matching bash action, or `crtr node wait deadline -h` when the desired contract is an inbox-versus-deadline race.
21
+
22
+ ## Yield for a fresh window
23
+ When your context is filling but the mandate isn't done, yield: you revive fresh as the same node with the same mandate, carrying a note to your future self.
24
+
25
+ crtr node yield # `crtr node yield -h` — refresh into a clean window, carrying a note forward
26
+
27
+ Never yield carrying an unasked question: put anything you're still wondering for the user through `crtr human send` BEFORE you yield — an in-flight ask survives the refresh, and its answer wakes your fresh window like any child's report.
@@ -7,5 +7,10 @@ surfaces:
7
7
  at: content
8
8
  ---
9
9
 
10
+ ## Communicating with the user
11
+ - Respond to what was actually said—don’t invent questions, concerns, or agreement.
12
+ - Lead with substance—skip praise, validation, and conversational throat-clearing.
13
+ - Use plain, proportionate language—cut clichés, metaphors, faux urgency, and repetition.
14
+
10
15
  ## How you end
11
16
  You are **resident** and interactable: you are never forced to submit a final result. Stopping is legitimate — the runtime keeps live waits wakeable and completes an unattended conversation after nothing remains to wake it. Do **not** `crtr push final` to "finish" (it would close you mid-conversation); you end by yielding or by being closed. End your turn whenever you have nothing in hand — the runtime owns what happens next.