@north-light/crouter 0.3.179 → 0.3.181

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 (137) hide show
  1. package/dist/api/client.d.ts +27 -2
  2. package/dist/api/client.js +41 -1
  3. package/dist/api/dto/broker.d.ts +32 -0
  4. package/dist/api/dto/crons.d.ts +17 -0
  5. package/dist/api/dto/human.d.ts +1 -7
  6. package/dist/api/dto/inbox.d.ts +71 -1
  7. package/dist/api/dto/inbox.js +9 -1
  8. package/dist/api/dto/memory.d.ts +17 -0
  9. package/dist/api/dto/memory.js +6 -0
  10. package/dist/api/dto/messages.d.ts +5 -0
  11. package/dist/api/dto/reviews.d.ts +8 -4
  12. package/dist/api/index.d.ts +1 -0
  13. package/dist/api/index.js +1 -0
  14. package/dist/api/routes.d.ts +5 -0
  15. package/dist/api/routes.js +8 -1
  16. package/dist/build-root.d.ts +7 -0
  17. package/dist/build-root.js +21 -0
  18. package/dist/builtin-memory/insights/init.md +48 -3
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/__tests__/insights-active-init.test.ts +98 -0
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +7 -50
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +16 -1
  22. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/pi-shell-runner.ts +34 -0
  23. package/dist/cli.js +1 -2
  24. package/dist/clients/attach/__tests__/context-message.test.js +5 -2
  25. package/dist/clients/attach/assets/README.md +7 -0
  26. package/dist/clients/attach/assets/whip-06.mp3 +0 -0
  27. package/dist/clients/attach/assets/whip-crack.mp3 +0 -0
  28. package/dist/clients/attach/assets/whip-snap.mp3 +0 -0
  29. package/dist/clients/attach/chrome/canvas-panels.d.ts +7 -1
  30. package/dist/clients/attach/chrome/canvas-panels.js +20 -3
  31. package/dist/clients/attach/chrome/review-wait.d.ts +6 -0
  32. package/dist/clients/attach/chrome/review-wait.js +22 -0
  33. package/dist/clients/attach/chrome/roster.js +23 -2
  34. package/dist/clients/attach/chrome/widgets.js +1 -1
  35. package/dist/clients/attach/input/controller.js +4 -3
  36. package/dist/clients/attach/overlays/mcp.js +3 -1
  37. package/dist/clients/attach/render/chat-view.js +1 -1
  38. package/dist/clients/attach/session/whip.d.ts +1 -0
  39. package/dist/clients/attach/session/whip.js +26 -0
  40. package/dist/clients/attach/slash/dispatch.js +2 -0
  41. package/dist/clients/attach/viewer.js +578 -573
  42. package/dist/clients/inbox/review/document-surface.d.ts +1 -1
  43. package/dist/clients/inbox/review/document-surface.js +4 -4
  44. package/dist/clients/inbox/review/launch.js +16 -4
  45. package/dist/clients/inbox/review/review-client.d.ts +9 -4
  46. package/dist/clients/inbox/review/review-client.js +3 -0
  47. package/dist/commands/cron.js +30 -8
  48. package/dist/commands/human/prompts.d.ts +7 -2
  49. package/dist/commands/human/prompts.js +15 -10
  50. package/dist/commands/human.js +1 -2
  51. package/dist/commands/memory/find.js +11 -8
  52. package/dist/commands/memory/read.js +111 -11
  53. package/dist/commands/memory/write.js +1 -1
  54. package/dist/commands/memory.js +1 -1
  55. package/dist/commands/pkg/market-manage.d.ts +13 -0
  56. package/dist/commands/pkg/market-manage.js +39 -33
  57. package/dist/commands/pkg/plugin-inspect.js +4 -3
  58. package/dist/commands/pkg/plugin-manage.js +12 -11
  59. package/dist/commands/surface/node/focus.js +1 -2
  60. package/dist/commands/sys/doctor.js +4 -4
  61. package/dist/commands/sys/setup-core.d.ts +14 -7
  62. package/dist/commands/sys/setup-core.js +66 -11
  63. package/dist/commands/sys/setup-wizard.js +2 -2
  64. package/dist/commands/sys/setup.js +1 -1
  65. package/dist/core/__tests__/cron-held-settlement.test.d.ts +1 -0
  66. package/dist/core/__tests__/cron-held-settlement.test.js +222 -0
  67. package/dist/core/__tests__/helpers/harness.js +1 -2
  68. package/dist/core/__tests__/phase4-review-store.test.js +1 -0
  69. package/dist/core/__tests__/serial/command-plugins.test.js +88 -1
  70. package/dist/core/__tests__/session-model.test.js +5 -3
  71. package/dist/core/bootstrap.d.ts +0 -4
  72. package/dist/core/bootstrap.js +1 -55
  73. package/dist/core/canvas/crons.d.ts +54 -2
  74. package/dist/core/canvas/crons.js +48 -4
  75. package/dist/core/canvas/db.js +23 -0
  76. package/dist/core/command-manifests/manifest.d.ts +11 -0
  77. package/dist/core/command-manifests/manifest.js +45 -4
  78. package/dist/core/command-manifests/schema.d.ts +1 -1
  79. package/dist/core/command-plugins/bundle.d.ts +1 -0
  80. package/dist/core/command-plugins/bundle.js +3 -3
  81. package/dist/core/command-plugins/discovery.d.ts +5 -2
  82. package/dist/core/command-plugins/discovery.js +5 -5
  83. package/dist/core/command-plugins/help-addenda.d.ts +12 -0
  84. package/dist/core/command-plugins/help-addenda.js +30 -0
  85. package/dist/core/command.js +25 -2
  86. package/dist/core/config.js +0 -1
  87. package/dist/core/human/convention.d.ts +0 -1
  88. package/dist/core/human/convention.js +0 -6
  89. package/dist/core/keybindings/inbox.d.ts +6 -8
  90. package/dist/core/keybindings/inbox.js +6 -15
  91. package/dist/core/keybindings/index.d.ts +1 -1
  92. package/dist/core/keybindings/index.js +1 -1
  93. package/dist/core/memory/doc-link-grammar.js +4 -1
  94. package/dist/core/memory-resolver.d.ts +28 -4
  95. package/dist/core/memory-resolver.js +51 -39
  96. package/dist/core/review/stage.js +1 -0
  97. package/dist/core/review/store.d.ts +5 -0
  98. package/dist/core/review/store.js +10 -0
  99. package/dist/core/review/types.d.ts +4 -0
  100. package/dist/core/runtime/broker/event-projection.d.ts +8 -1
  101. package/dist/core/runtime/broker/event-projection.js +25 -1
  102. package/dist/core/runtime/broker/frame-dispatch.d.ts +2 -0
  103. package/dist/core/runtime/broker/frame-dispatch.js +50 -8
  104. package/dist/core/runtime/broker/message-ledger.d.ts +53 -0
  105. package/dist/core/runtime/broker/message-ledger.js +143 -0
  106. package/dist/core/runtime/broker/rebind.js +14 -0
  107. package/dist/core/runtime/broker-protocol.d.ts +46 -1
  108. package/dist/core/runtime/broker.js +11 -2
  109. package/dist/core/runtime/interactive-deliver.d.ts +5 -2
  110. package/dist/core/runtime/interactive-deliver.js +6 -3
  111. package/dist/core/runtime/shell-expansion.d.ts +32 -0
  112. package/dist/core/runtime/shell-expansion.js +102 -0
  113. package/dist/core/session-model/session-state.d.ts +9 -4
  114. package/dist/core/session-model/session-state.js +5 -1
  115. package/dist/daemon/api/handlers/broker-ops.js +8 -0
  116. package/dist/daemon/api/handlers/crons.js +14 -1
  117. package/dist/daemon/api/handlers/inbox.js +346 -2
  118. package/dist/daemon/api/handlers/memory.d.ts +2 -0
  119. package/dist/daemon/api/handlers/memory.js +48 -0
  120. package/dist/daemon/api/handlers/messages.js +7 -1
  121. package/dist/daemon/api/handlers/reviews.js +7 -5
  122. package/dist/daemon/api/map.js +3 -0
  123. package/dist/daemon/api/server.js +2 -0
  124. package/dist/daemon/cron-run.js +71 -3
  125. package/dist/daemon/crtrd.js +3 -0
  126. package/dist/daemon/reconcilers/pending-review-submit.d.ts +7 -0
  127. package/dist/daemon/reconcilers/pending-review-submit.js +35 -0
  128. package/dist/daemon/review/companion.d.ts +8 -0
  129. package/dist/daemon/review/companion.js +35 -0
  130. package/dist/daemon/review/deliver.js +2 -1
  131. package/dist/daemon/review/finish.d.ts +29 -2
  132. package/dist/daemon/review/finish.js +75 -2
  133. package/dist/shared/generated-context.d.ts +3 -4
  134. package/dist/shared/generated-context.js +24 -6
  135. package/dist/types.d.ts +0 -1
  136. package/package.json +1 -1
  137. package/runtime.lock.json +2 -2
@@ -5,16 +5,17 @@ import type { PushReportRequest, PushReportResultDTO, ReportDTO, ReportsQuery }
5
5
  import type { CloseRequest, CloseResultDTO, PromoteRequest, RelaunchRootResultDTO, ReviveRequest, ReviveResultDTO, WaitRequest, YieldRequest } from './dto/lifecycle.js';
6
6
  import type { SubscribeRequest, SubscriptionDTO } from './dto/subscriptions.js';
7
7
  import type { FocusDTO, RegisterFocusRequest, SetFocusPaneRequest } from './dto/focus.js';
8
- import { type ArmCronRequest, type CancelCronQuery, type CronDTO, type CronRunDTO, type CronScopeQuery, type CronShowDTO, type ListCronsQuery } from './dto/crons.js';
8
+ import { type ArmCronRequest, type CancelCronQuery, type CronDTO, type CronRunDTO, type CronScopeQuery, type CronShowDTO, type ListCronsQuery, type PokeCronsResult } from './dto/crons.js';
9
9
  import type { NodeConfigPatch } from './dto/config.js';
10
10
  import type { AttachEnsureRequest, AttachEnsureResultDTO } from './dto/attach.js';
11
11
  import type { EnsureProfileRequest, ProfileDTO } from './dto/profiles.js';
12
12
  import type { FilePeekDTO } from './dto/files.js';
13
+ import type { MemoryDocRefDTO } from './dto/memory.js';
13
14
  import type { CredentialRemovalResultDTO, CredentialResultDTO, InstallCredentialRequest, ModelAuthListDTO } from './dto/modelauth.js';
14
15
  import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanCancelRequest, HumanCancelResultDTO, HumanResolveRequest, HumanResolveResultDTO } from './dto/human.js';
15
16
  import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, ReviewCancelResultDTO, ReviewDocumentBaseDTO, ReviewDTO, ReviewListDTO, ReviewSubmitResultDTO } from './dto/reviews.js';
16
17
  import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
17
- import type { InboxListDTO } from './dto/inbox.js';
18
+ import type { CancelInboxTicketRequest, CanceledTicketResultDTO, DeckTicketResultDTO, InboxDeckDTO, InboxListDTO, InboxTicketIdDTO, RespondInboxDeckRequest } from './dto/inbox.js';
18
19
  import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
19
20
  import type { CloseWorktreeResultDTO } from './dto/worktree.js';
20
21
  import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
@@ -131,6 +132,10 @@ export declare class CrtrClient {
131
132
  runCron(cronId: string, q?: CronScopeQuery): Promise<CronRunDTO>;
132
133
  /** Cancel one cron (`DELETE /v1/crons/:cronId`, idempotent). */
133
134
  cancelCron(cronId: string, q?: CancelCronQuery): Promise<void>;
135
+ /** Bare eligibility poke (`POST /v1/crons/poke`): re-dues every held active
136
+ * cron now — "something changed; re-check now". Canvas-wide, label-free,
137
+ * idempotent, and free when nothing is held. */
138
+ pokeCrons(): Promise<PokeCronsResult>;
134
139
  ensureAttach(id: string, req?: AttachEnsureRequest): Promise<AttachEnsureResultDTO>;
135
140
  getReports(id: string, q?: ReportsQuery): Promise<ReportDTO[]>;
136
141
  getTranscript(id: string, q?: TranscriptQuery): Promise<TranscriptDTO>;
@@ -143,6 +148,10 @@ export declare class CrtrClient {
143
148
  /** Read an absolute host path as UTF-8 (capped, `truncated` when clipped) for
144
149
  * the browser file-peek panel. */
145
150
  peekFile(path: string): Promise<FilePeekDTO>;
151
+ /** Resolve a `[[name]]` memory-document link to the absolute path the given
152
+ * node would read — the node's own precedence chain, not this process's.
153
+ * Pair with `peekFile` to render the document. */
154
+ resolveMemoryDoc(name: string, nodeId: string): Promise<MemoryDocRefDTO>;
146
155
  ensureProfile(name: string, req?: EnsureProfileRequest): Promise<ProfileDTO>;
147
156
  listProfiles(): Promise<ProfileDTO[]>;
148
157
  getProfile(name: string): Promise<ProfileDTO>;
@@ -179,7 +188,17 @@ export declare class CrtrClient {
179
188
  resolveReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
180
189
  reopenReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
181
190
  deleteReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
191
+ /** Pending deck/review tickets across every available crouter-owned
192
+ * humanloop root. */
182
193
  listHumanInbox(): Promise<InboxListDTO>;
194
+ /** Read one pending deck by its opaque ticket id, with Markdown bodies
195
+ * resolved inline. */
196
+ getHumanInboxDeck(ticketId: InboxTicketIdDTO): Promise<InboxDeckDTO>;
197
+ /** Submit ordered interaction responses for a pending deck. Single-assignment
198
+ * server-side: a competing resolution races to `ticket_already_resolved`. */
199
+ respondHumanInboxDeck(ticketId: InboxTicketIdDTO, request: RespondInboxDeckRequest): Promise<DeckTicketResultDTO>;
200
+ /** Cancel a pending deck (terminal response, never deletion). */
201
+ cancelHumanInboxTicket(ticketId: InboxTicketIdDTO, request?: CancelInboxTicketRequest): Promise<CanceledTicketResultDTO>;
183
202
  /** Composed client-side from `GET /v1/nodes` + `GET /v1/status` (spec §6.3 —
184
203
  * the dashboard is absorbed into those two reads; there is no single route).
185
204
  * `generated_at` is the client-side capture instant of the composition. */
@@ -217,6 +236,12 @@ export declare class CrtrClient {
217
236
  * it raw, so a value carrying `/`, whitespace or `?` would corrupt the
218
237
  * request line rather than 404 cleanly. Mirrors `nodePath`. */
219
238
  private cronPath;
239
+ /** Validate an opaque inbox ticket id before route construction. A local
240
+ * shape violation is a caller bug, not a server-rejectable request — throws
241
+ * `TypeError` (matching the existing safe-segment discipline of a local
242
+ * precondition, distinct from `nodePath`'s `ApiError` because that one IS a
243
+ * request the server could plausibly receive and reject itself). */
244
+ private ticketId;
220
245
  /** Validate a review id before route construction (D-A6). Reviews are minted
221
246
  * and addressed like node ids, but arrive from agent argv, so a malformed
222
247
  * one is a plausible request the server would also reject — `ApiError`,
@@ -227,6 +227,12 @@ export class CrtrClient {
227
227
  async cancelCron(cronId, q) {
228
228
  await this.request('DELETE', withQuery(routes.cron(this.cronPath(cronId)), q));
229
229
  }
230
+ /** Bare eligibility poke (`POST /v1/crons/poke`): re-dues every held active
231
+ * cron now — "something changed; re-check now". Canvas-wide, label-free,
232
+ * idempotent, and free when nothing is held. */
233
+ pokeCrons() {
234
+ return this.request('POST', routes.cronsPoke(), {});
235
+ }
230
236
  ensureAttach(id, req) {
231
237
  return this.request('POST', routes.nodeAttach(this.nodePath(id)), req ?? {});
232
238
  }
@@ -257,6 +263,13 @@ export class CrtrClient {
257
263
  peekFile(path) {
258
264
  return this.request('GET', withQuery(routes.filePeek(), { path }));
259
265
  }
266
+ // ---- Memory documents --------------------------------------------------
267
+ /** Resolve a `[[name]]` memory-document link to the absolute path the given
268
+ * node would read — the node's own precedence chain, not this process's.
269
+ * Pair with `peekFile` to render the document. */
270
+ resolveMemoryDoc(name, nodeId) {
271
+ return this.request('GET', withQuery(routes.memoryResolve(), { name, node: nodeId }));
272
+ }
260
273
  // ---- Profiles ----------------------------------------------------------
261
274
  ensureProfile(name, req) {
262
275
  return this.request('PUT', routes.profile(name), req ?? {});
@@ -351,10 +364,26 @@ export class CrtrClient {
351
364
  deleteReviewComment(commentId, req = {}) {
352
365
  return this.request('POST', routes.humanCommentDelete(this.commentPath(commentId)), req);
353
366
  }
354
- // ---- Attached terminal viewer inbox -------------------------------------
367
+ // ---- Humanloop inbox (Northlight crouter-inbox v1, inbox-contract.md §A) --
368
+ /** Pending deck/review tickets across every available crouter-owned
369
+ * humanloop root. */
355
370
  listHumanInbox() {
356
371
  return this.request('GET', routes.humanInbox());
357
372
  }
373
+ /** Read one pending deck by its opaque ticket id, with Markdown bodies
374
+ * resolved inline. */
375
+ getHumanInboxDeck(ticketId) {
376
+ return this.request('GET', routes.humanInboxTicket(this.ticketId(ticketId)));
377
+ }
378
+ /** Submit ordered interaction responses for a pending deck. Single-assignment
379
+ * server-side: a competing resolution races to `ticket_already_resolved`. */
380
+ respondHumanInboxDeck(ticketId, request) {
381
+ return this.request('POST', routes.humanInboxRespond(this.ticketId(ticketId)), request);
382
+ }
383
+ /** Cancel a pending deck (terminal response, never deletion). */
384
+ cancelHumanInboxTicket(ticketId, request) {
385
+ return this.request('POST', routes.humanInboxCancel(this.ticketId(ticketId)), request ?? {});
386
+ }
358
387
  // ---- Canvas reads / maintenance ---------------------------------------
359
388
  /** Composed client-side from `GET /v1/nodes` + `GET /v1/status` (spec §6.3 —
360
389
  * the dashboard is absorbed into those two reads; there is no single route).
@@ -446,6 +475,17 @@ export class CrtrClient {
446
475
  }
447
476
  return id;
448
477
  }
478
+ /** Validate an opaque inbox ticket id before route construction. A local
479
+ * shape violation is a caller bug, not a server-rejectable request — throws
480
+ * `TypeError` (matching the existing safe-segment discipline of a local
481
+ * precondition, distinct from `nodePath`'s `ApiError` because that one IS a
482
+ * request the server could plausibly receive and reject itself). */
483
+ ticketId(id) {
484
+ if (!/^[a-f0-9]{64}$/.test(id)) {
485
+ throw new TypeError(`invalid inbox ticket id: ${JSON.stringify(id)}`);
486
+ }
487
+ return id;
488
+ }
449
489
  /** Validate a review id before route construction (D-A6). Reviews are minted
450
490
  * and addressed like node ids, but arrive from agent argv, so a malformed
451
491
  * one is a plausible request the server would also reject — `ApiError`,
@@ -28,6 +28,38 @@ export interface BrokerWelcomeSnapshot<M = unknown> {
28
28
  export interface BrokerWelcomeFrame<M = unknown> {
29
29
  type: 'welcome';
30
30
  snapshot?: BrokerWelcomeSnapshot<M>;
31
+ /** The last few id-bearing user-message dispatches from the broker's message
32
+ * ledger, oldest first — so a reattaching follower can key the snapshot's
33
+ * trailing user wakes by id (the id a sender minted via `message_id` on
34
+ * `POST .../messages`) instead of discarding them heuristically. Live-process
35
+ * memory only: a broker restart loses it. Absent on a broker pinned to an
36
+ * older runtime generation. */
37
+ recentUserMessages?: Array<{
38
+ id: string;
39
+ text: string;
40
+ }>;
41
+ }
42
+ /**
43
+ * The additive identity fields the broker sets on a relayed pi `queue_update`:
44
+ * id arrays PARALLEL to pi's text arrays (`steeringIds[i]` identifies
45
+ * `steering[i]`). Sender-minted when the send carried `message_id`,
46
+ * broker-minted otherwise. Absent on a broker pinned to an older runtime
47
+ * generation — consumers fall back to bare texts. Intersect with the pinned pi
48
+ * `queue_update` event shape to read them typed.
49
+ */
50
+ export interface RelayedQueueUpdateIdentity {
51
+ steeringIds?: string[];
52
+ followUpIds?: string[];
53
+ }
54
+ /**
55
+ * The additive identity field the broker sets on a relayed USER-role
56
+ * `message_start`: the message's crouter id — the `message_id` its sender
57
+ * minted, or a broker-minted one. Absent when the message carries none (an
58
+ * engine-command expansion, a pre-ledger replay, an older broker). Intersect
59
+ * with the pinned pi `message_start` event shape to read it typed.
60
+ */
61
+ export interface RelayedUserMessageStartIdentity {
62
+ crtrMessageId?: string;
31
63
  }
32
64
  /**
33
65
  * The broker-control frames a relay consumer reads: `welcome` (catch-up snapshot)
@@ -53,6 +53,14 @@ export interface CronDTO {
53
53
  sink: string | null;
54
54
  tier: string;
55
55
  state: CronStateDTO;
56
+ /** True while the row is parked by the exit-75 owed-gate disposition: the
57
+ * last scheduled run declared "owed but not currently eligible", so the
58
+ * occurrence was not spent. A daemon poke re-dues it now; otherwise a
59
+ * recurring row re-checks at its natural `fire_at` slot (the backstop) and
60
+ * a held one-shot waits for a poke until `expires_at` deletes it. `state`
61
+ * stays honest (active|paused) — renderers derive; an active held row must
62
+ * never present as paused. */
63
+ held: boolean;
56
64
  run_state: CronRunStateDTO;
57
65
  /** Recent health: the most recent settled run, or null if it never ran. */
58
66
  last_run: CronLastRunDTO | null;
@@ -93,6 +101,15 @@ export interface CronRunDTO {
93
101
  /** What the sink did with this run's output, or why it didn't. */
94
102
  delivered: string | null;
95
103
  }
104
+ /** `POST /v1/crons/poke` — the bare daemon-level eligibility poke. Re-dues
105
+ * every held active cron now; paused rows keep their held state. Idempotent
106
+ * and free when nothing is held. */
107
+ export interface PokeCronsResult {
108
+ /** How many held rows were re-dued — for the caller's log line. */
109
+ unparked: number;
110
+ /** The poke receipt instant (UTC). */
111
+ at: IsoTime;
112
+ }
96
113
  /** `GET /v1/crons/:cronId` — one cron with its run-log ring (most recent first). */
97
114
  export interface CronShowDTO {
98
115
  cron: CronDTO;
@@ -1,4 +1,5 @@
1
1
  import type { NodeIdDTO } from './common.js';
2
+ import type { InteractionResponseDTO } from './inbox.js';
2
3
  /** One anchored review comment, mirroring crouter's ticket-store shape as a
3
4
  * plain structural wire type (no store import). */
4
5
  export interface FeedbackCommentDTO {
@@ -36,13 +37,6 @@ export interface FeedbackResultDTO {
36
37
  commentsTotal: number;
37
38
  commentsUnresolved: number;
38
39
  }
39
- export interface InteractionResponseDTO {
40
- id: string;
41
- selectedOptionId?: string;
42
- selectedOptionIds?: string[];
43
- freetext?: string;
44
- optionComments?: Record<string, string>;
45
- }
46
40
  /** `POST /v1/human/tickets/{node_id}/resolve` body — a deck answer. */
47
41
  export interface HumanResolveRequest {
48
42
  responses: InteractionResponseDTO[];
@@ -1,6 +1,7 @@
1
1
  import type { IsoTime } from './common.js';
2
2
  /** Opaque, stable, URL-safe ticket id: lowercase SHA-256 hex of
3
- * `canonicalRoot + "\0" + ticketBasename`. */
3
+ * `canonicalRoot + "\0" + ticketBasename`. Clients must treat it as opaque —
4
+ * it discloses no home filesystem path. */
4
5
  export type InboxTicketIdDTO = string;
5
6
  export type InteractionKindDTO = 'notify' | 'decision' | 'context' | 'error' | 'review';
6
7
  export interface DeckSourceDTO {
@@ -32,3 +33,72 @@ export type InboxTicketSummaryDTO = DeckTicketSummaryDTO | ReviewTicketSummaryDT
32
33
  export interface InboxListDTO {
33
34
  tickets: InboxTicketSummaryDTO[];
34
35
  }
36
+ export interface InteractionOptionDTO {
37
+ id: string;
38
+ label: string;
39
+ description?: string;
40
+ }
41
+ export interface InteractionPreAnswerDTO {
42
+ selectedOptionId?: string;
43
+ selectedOptionIds?: string[];
44
+ freetext?: string;
45
+ label?: string;
46
+ }
47
+ export interface InteractionDTO {
48
+ id: string;
49
+ title: string;
50
+ subtitle: string;
51
+ /** Resolved source Markdown — `bodyPath` is deliberately impossible here. */
52
+ body?: string;
53
+ options: InteractionOptionDTO[];
54
+ multiSelect?: boolean;
55
+ allowFreetext?: boolean;
56
+ freetextLabel?: string;
57
+ kind?: InteractionKindDTO;
58
+ preAnswered?: InteractionPreAnswerDTO;
59
+ }
60
+ export interface DeckDTO {
61
+ title: string;
62
+ source?: DeckSourceDTO;
63
+ interactions: InteractionDTO[];
64
+ }
65
+ /** `GET /v1/human/inbox/:ticket_id` result for a pending deck. */
66
+ export interface InboxDeckDTO {
67
+ ticket_id: InboxTicketIdDTO;
68
+ kind: 'deck';
69
+ deck: DeckDTO;
70
+ }
71
+ export interface InteractionResponseDTO {
72
+ id: string;
73
+ selectedOptionId?: string;
74
+ selectedOptionIds?: string[];
75
+ freetext?: string;
76
+ optionComments?: Record<string, string>;
77
+ }
78
+ /** `POST /v1/human/inbox/:ticket_id/respond` body. */
79
+ export interface RespondInboxDeckRequest {
80
+ responses: InteractionResponseDTO[];
81
+ }
82
+ /** `POST /v1/human/inbox/:ticket_id/respond` result — the canonical humanloop
83
+ * `humanloop.response/v2` result, unchanged. */
84
+ export interface DeckTicketResultDTO {
85
+ schema: 'humanloop.response/v2';
86
+ kind: 'deck';
87
+ responses: InteractionResponseDTO[];
88
+ summary: string;
89
+ completedAt: IsoTime;
90
+ }
91
+ /** `POST /v1/human/inbox/:ticket_id/cancel` body. `reason`, when present, must
92
+ * be nonempty after trim and at most 1000 characters. */
93
+ export interface CancelInboxTicketRequest {
94
+ reason?: string;
95
+ }
96
+ /** `POST /v1/human/inbox/:ticket_id/cancel` result — the canonical humanloop
97
+ * `humanloop.cancel/v1` result, unchanged. `actor` is always `"human"`. */
98
+ export interface CanceledTicketResultDTO {
99
+ schema: 'humanloop.cancel/v1';
100
+ kind: 'canceled';
101
+ canceledAt: IsoTime;
102
+ reason?: string;
103
+ actor?: string;
104
+ }
@@ -1,2 +1,10 @@
1
- // Ticket summaries rendered by the attached terminal viewer.
1
+ // Humanloop inbox DTOs — crtrd `/v1/human/inbox` (Northlight crouter-inbox v1,
2
+ // inbox-contract.md §A). Crouter API envelope fields use the existing
3
+ // snake_case convention; nested humanloop protocol objects retain their
4
+ // canonical camelCase field names so they cross the wire without translation
5
+ // or loss. Optional fields are omitted when absent, never serialized as
6
+ // `null`. `bodyPath` is deliberately impossible on this wire — crtrd resolves
7
+ // it server-side via humanloop's `parseDeck` and returns inline `body`.
8
+ //
9
+ // PURITY (spec §3.1): Node built-ins + `src/api/*` only.
2
10
  export {};
@@ -0,0 +1,17 @@
1
+ /** `GET /v1/memory/resolve?name=<name>&node=<id>` result — where the named
2
+ * document lives for that node. Resolution runs the node's own precedence
3
+ * chain (its context store, its project stack, its profile, user, builtin), so
4
+ * the same name can answer with different documents for different nodes. */
5
+ export interface MemoryDocRefDTO {
6
+ /** The document's canonical identity (its frontmatter `name`, else its
7
+ * path-derived name) — which may differ from the queried name when the query
8
+ * was a bare leaf or a directory whose INDEX resolved. */
9
+ name: string;
10
+ /** Which store it came from: node | project | profile | user | builtin. */
11
+ scope: string;
12
+ /** Absolute path to the `.md` file. */
13
+ path: string;
14
+ /** The owning plugin's name when the doc is mounted from an installed plugin,
15
+ * absent for a native scope doc. */
16
+ plugin?: string;
17
+ }
@@ -0,0 +1,6 @@
1
+ // Memory-document resolution DTO. Backs `GET /v1/memory/resolve` — a client
2
+ // holding a `[[name]]` link out of a node's transcript turns it into the
3
+ // absolute path of the document that node would read, then peeks that path.
4
+ //
5
+ // PURITY (spec §3.1): Node built-ins + `src/api/*` only.
6
+ export {};
@@ -26,6 +26,11 @@ export interface SendMessageRequest {
26
26
  * body only — rejected with fresh/reopen/situational_context/
27
27
  * output_schema or tier 'deferred'. Absent → durable inbox (unchanged). */
28
28
  delivery?: 'interactive';
29
+ /** Sender-minted message identity for a `delivery:'interactive'` send. The
30
+ * broker mirrors it through pi's queues and echoes it on the relayed user
31
+ * `message_start` (`crtrMessageId`), so an optimistic sender (the gateway)
32
+ * retires its pending entry by exact id. Ignored on the durable-inbox path. */
33
+ message_id?: string;
29
34
  }
30
35
  /** Result of an immediate message send. */
31
36
  export interface MessageResultDTO {
@@ -38,6 +38,9 @@ export interface ReviewDTO {
38
38
  created: IsoTime;
39
39
  /** Daemon open timestamp, after the companion binds. */
40
40
  opened_at?: IsoTime;
41
+ /** When the human submitted a review whose companion was still working. The
42
+ * review remains `open` until the companion goes quiet. */
43
+ submit_requested_at?: IsoTime;
41
44
  /** Daemon source-read status at projection time. */
42
45
  source_missing: boolean;
43
46
  /** Daemon-owned current comment-coordinate source digest. */
@@ -73,12 +76,13 @@ export interface ListReviewsQuery {
73
76
  export interface ReviewListDTO {
74
77
  reviews: ReviewDTO[];
75
78
  }
76
- /** Daemon-derived result of terminal review approval. */
79
+ /** Daemon-derived result of review approval, which may still be waiting on the
80
+ * review's companion. */
77
81
  export interface ReviewSubmitResultDTO {
78
82
  review: ReviewDTO;
79
- /** Immutable approval result. */
80
- result: FeedbackResultDTO;
81
- outcome: 'settled' | 'already_settled';
83
+ /** Immutable approval result; absent while the approval awaits the companion. */
84
+ result?: FeedbackResultDTO;
85
+ outcome: 'settled' | 'already_settled' | 'awaiting_companion';
82
86
  }
83
87
  /** Daemon-derived result of terminal review cancellation. */
84
88
  export interface ReviewCancelResultDTO {
@@ -21,6 +21,7 @@ export * from './dto/canvas.js';
21
21
  export * from './dto/worktree.js';
22
22
  export * from './dto/human.js';
23
23
  export * from './dto/files.js';
24
+ export * from './dto/memory.js';
24
25
  export * from './dto/inbox.js';
25
26
  export * from './dto/reviews.js';
26
27
  export * from './dto/review-comments.js';
package/dist/api/index.js CHANGED
@@ -22,6 +22,7 @@ export * from './dto/canvas.js';
22
22
  export * from './dto/worktree.js';
23
23
  export * from './dto/human.js';
24
24
  export * from './dto/files.js';
25
+ export * from './dto/memory.js';
25
26
  export * from './dto/inbox.js';
26
27
  export * from './dto/reviews.js';
27
28
  export * from './dto/review-comments.js';
@@ -46,6 +46,7 @@ export declare const routes: {
46
46
  readonly cronPause: (cronId: string) => string;
47
47
  readonly cronResume: (cronId: string) => string;
48
48
  readonly cronRun: (cronId: string) => string;
49
+ readonly cronsPoke: () => string;
49
50
  readonly canvasAttention: () => string;
50
51
  readonly canvasAttentionCounts: () => string;
51
52
  readonly canvasHistorySearch: () => string;
@@ -73,9 +74,13 @@ export declare const routes: {
73
74
  readonly humanCommentReopen: (commentId: string) => string;
74
75
  readonly humanCommentDelete: (commentId: string) => string;
75
76
  readonly humanInbox: () => string;
77
+ readonly humanInboxTicket: (ticketId: string) => string;
78
+ readonly humanInboxRespond: (ticketId: string) => string;
79
+ readonly humanInboxCancel: (ticketId: string) => string;
76
80
  readonly profiles: () => string;
77
81
  readonly profile: (name: string) => string;
78
82
  readonly modelAuths: () => string;
79
83
  readonly modelAuth: (provider: string) => string;
80
84
  readonly filePeek: () => string;
85
+ readonly memoryResolve: () => string;
81
86
  };
@@ -67,6 +67,7 @@ export const routes = {
67
67
  cronPause: (cronId) => `${V}/crons/${cronId}/pause`,
68
68
  cronResume: (cronId) => `${V}/crons/${cronId}/resume`,
69
69
  cronRun: (cronId) => `${V}/crons/${cronId}/run`,
70
+ cronsPoke: () => `${V}/crons/poke`,
70
71
  // Canvas maintenance / reads
71
72
  canvasAttention: () => `${V}/canvas/attention`,
72
73
  canvasAttentionCounts: () => `${V}/canvas/attention/counts`,
@@ -98,8 +99,11 @@ export const routes = {
98
99
  humanCommentResolve: (commentId) => `${V}/human/comments/${commentId}/resolve`,
99
100
  humanCommentReopen: (commentId) => `${V}/human/comments/${commentId}/reopen`,
100
101
  humanCommentDelete: (commentId) => `${V}/human/comments/${commentId}/delete`,
101
- // Attached terminal viewer inbox
102
+ // Humanloop inbox (Northlight crouter-inbox v1, inbox-contract.md §A)
102
103
  humanInbox: () => `${V}/human/inbox`,
104
+ humanInboxTicket: (ticketId) => `${V}/human/inbox/${ticketId}`,
105
+ humanInboxRespond: (ticketId) => `${V}/human/inbox/${ticketId}/respond`,
106
+ humanInboxCancel: (ticketId) => `${V}/human/inbox/${ticketId}/cancel`,
103
107
  // Profiles (server-side for P2 Core; CLI profile verbs stay fs-local)
104
108
  profiles: () => `${V}/profiles`,
105
109
  profile: (name) => `${V}/profiles/${name}`,
@@ -109,4 +113,7 @@ export const routes = {
109
113
  // Host file read (browser file-peek panel). The absolute path rides as a
110
114
  // `path` query param, not a path segment — it is not a single safe segment.
111
115
  filePeek: () => `${V}/files/peek`,
116
+ // Memory-document resolution (a `[[name]]` link in a node's transcript). Both
117
+ // the name and the node it is resolved for ride as query params.
118
+ memoryResolve: () => `${V}/memory/resolve`,
112
119
  };
@@ -2,6 +2,13 @@ import type { RootDef } from './core/command.js';
2
2
  /** Every shipped subtree name. Cheap (no module loading) — the front-door
3
3
  * recursion guard and the dispatcher's first-token routing need only names. */
4
4
  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. */
11
+ export declare function coreCommandPaths(): Promise<ReadonlySet<string>>;
5
12
  /** Build a root that contains only the subtree `first` dispatches into.
6
13
  * Returns the FULL root when `first` is not a recognized subtree — bare `crtr`,
7
14
  * `-h`/`--help`, `--version`, and any unknown leading token all need the
@@ -23,6 +23,27 @@ const SUBTREE_LOADERS = {
23
23
  /** Every shipped subtree name. Cheap (no module loading) — the front-door
24
24
  * recursion guard and the dispatcher's first-token routing need only names. */
25
25
  export const SUBTREE_NAMES = Object.freeze(Object.keys(SUBTREE_LOADERS));
26
+ /** Every core command path, space-joined ("cron", "cron add", …) — the set
27
+ * plugin `helpAddenda` keys are validated against at the strict gates
28
+ * (install, bundle parse, doctor/inspect reports). Loads every core subtree,
29
+ * so call it only from those gates, never on a dispatch path. Passthrough
30
+ * branches are excluded: crtr never renders their help, so an addendum
31
+ * targeting one could never appear. */
32
+ export async function coreCommandPaths() {
33
+ const core = await Promise.all(SUBTREE_NAMES.map((n) => SUBTREE_LOADERS[n]()));
34
+ const paths = new Set();
35
+ const visit = (node, prefix) => {
36
+ if (node.kind === 'branch' && node.passthrough !== undefined)
37
+ return;
38
+ paths.add(prefix);
39
+ if (node.kind === 'branch')
40
+ for (const child of node.children)
41
+ visit(child, `${prefix} ${child.name}`);
42
+ };
43
+ for (const subtree of core)
44
+ visit(subtree, subtree.name);
45
+ return paths;
46
+ }
26
47
  /** Build a root that contains only the subtree `first` dispatches into.
27
48
  * Returns the FULL root when `first` is not a recognized subtree — bare `crtr`,
28
49
  * `-h`/`--help`, `--version`, and any unknown leading token all need the
@@ -8,11 +8,15 @@ slash: true
8
8
  rationale: Ordinary conversations, corrections, answers to `crtr human ask`, and review comments carry unique user knowledge that agents inconsistently recognize or save; when agents do infer a deeper principle, they have written it without first letting the user correct the extrapolation.
9
9
  ---
10
10
 
11
- # /insights:init — begin passive domain listening
11
+ # /insights:init — begin domain listening
12
12
 
13
- Initialize an ordinary memory directory that listens for user-derived insight about this domain. This version is passive: do not start research, schedule work, create a standing node, or proactively question the user after initialization.
13
+ Initialize an ordinary memory directory that listens for user-derived insight about this domain.
14
14
 
15
- **Requested domain:** $ARGUMENTS
15
+ **Requested domain and mode:** $ARGUMENTS
16
+
17
+ ## Check for --active flag
18
+
19
+ If `$ARGUMENTS` contains `--active`, follow the **active mode** steps below. Otherwise, follow the **passive mode** steps.
16
20
 
17
21
  ## Establish the topic and scope
18
22
 
@@ -43,3 +47,44 @@ Keep the body short. It contains:
43
47
  Do not copy the capture workflow into the listener. The link keeps that process in one maintained place. Do not create placeholder principle documents.
44
48
 
45
49
  Run `crtr memory lint`, fix every finding, then report the canonical listener name, selected scope, and the domain boundary. Initialization is complete once the routed listener exists; no independent work follows.
50
+
51
+ ## Active mode: research and surface claims
52
+
53
+ When `--active` is present, do not stop after creating the listener. After initialization:
54
+
55
+ ### 1. Create the listener first
56
+
57
+ Follow the passive mode steps above through "Initialization is complete." The listener INDEX must exist before spawning the explorer.
58
+
59
+ ### 2. Spawn the explorer child
60
+
61
+ Run this exact command, replacing `<topic>` with the topic slug you chose above:
62
+
63
+ ```bash
64
+ crtr node new --kind explore --name "explore-<topic>" <<'TASK'
65
+ Investigate the domain "<topic>" thoroughly. Your goal is to surface 3–5 distinct, falsifiable claims or questions about how this domain works, what its gaps are, or what fundamental principles govern it. Each claim should be specific enough that the user can confirm it, refine it, or reject it outright.
66
+
67
+ Gather evidence from code, docs, existing understanding, and project artifacts. Then present your claims clearly:
68
+
69
+ **Claim 1:** [claim text]
70
+ **Evidence:** [why you believe this]
71
+ **Question:** [what would prove or disprove this?]
72
+
73
+ Repeat for each claim. Write findings to $CRTR_CONTEXT_DIR/claims.md and report the absolute path.
74
+ TASK
75
+ ```
76
+
77
+ Do not wait for the explorer to finish—it runs in parallel. Move to the next step while it works.
78
+
79
+ ### 3. Coordinate user responses and capture flow
80
+
81
+ When the explorer reports, share its claims with the user. For each claim, ask:
82
+ - Does this ring true?
83
+ - Is it incomplete or wrong?
84
+ - What's the actual principle?
85
+
86
+ For each user response, use [[insights/capture]] to extract and review the insight. Apply approved insights directly to the listener INDEX's `Approved insights` section.
87
+
88
+ ### 4. Report completion
89
+
90
+ Once claims have been surfaced and user guidance has generated approved insights, report that active initialization is complete. The listener INDEX now passively captures this domain as new user material emerges.