@north-light/crouter-api 0.3.198 → 0.3.200

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.
@@ -9,14 +9,14 @@ import type { FocusDTO, RegisterFocusRequest, SetFocusPaneRequest } from './dto/
9
9
  import { type ArmCronRequest, type CancelCronQuery, type CronDTO, type CronRunDTO, type CronScopeQuery, type CronShowDTO, type ListCronsQuery, type PokeCronsResult } from './dto/crons.js';
10
10
  import type { NodeConfigPatch } from './dto/config.js';
11
11
  import type { AttachEnsureRequest, AttachEnsureResultDTO } from './dto/attach.js';
12
- import type { EnsureProfileRequest, ProfileDTO } from './dto/profiles.js';
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
15
  import type { CredentialRemovalResultDTO, CredentialResultDTO, InstallCredentialRequest, ModelAuthListDTO } from './dto/modelauth.js';
16
16
  import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanCancelRequest, HumanCancelResultDTO, HumanResolveRequest, HumanResolveResultDTO } from './dto/human.js';
17
17
  import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, ReviewCancelResultDTO, ReviewDocumentBaseDTO, ReviewDTO, ReviewListDTO, ReviewSubmitResultDTO } from './dto/reviews.js';
18
18
  import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
19
- import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageRenderDTO, PagesBundleAssetDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
19
+ import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageFeedbackResolutionDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
20
20
  import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
21
21
  import type { CloseWorktreeResultDTO } from './dto/worktree.js';
22
22
  import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
@@ -158,9 +158,8 @@ export declare class CrtrClient {
158
158
  ensureProfile(name: string, req?: EnsureProfileRequest): Promise<ProfileDTO>;
159
159
  listProfiles(): Promise<ProfileDTO[]>;
160
160
  getProfile(name: string): Promise<ProfileDTO>;
161
- /** Delete one profile by exact id or unique name (`DELETE /v1/profiles/:name`,
162
- * idempotent a miss is success). */
163
- deleteProfile(name: string): Promise<void>;
161
+ /** Force-delete or detach one profile by exact id or unique name. */
162
+ deleteProfile(name: string, req: DeleteProfileRequest): Promise<DeleteProfileResultDTO>;
164
163
  listModelAuth(): Promise<ModelAuthListDTO>;
165
164
  installCredential(provider: string, req: InstallCredentialRequest): Promise<CredentialResultDTO>;
166
165
  removeCredential(provider: string): Promise<CredentialRemovalResultDTO>;
@@ -169,12 +168,11 @@ export declare class CrtrClient {
169
168
  * broker) precisely because a human bridge must never have one. */
170
169
  createHumanBridge(req: CreateHumanBridgeRequest): Promise<HumanBridgeResultDTO>;
171
170
  /** Resolve a page ticket answer. crtrd claims the ticket (taking over a live
172
- * inbox claim where one exists), publishes the canonical result, delivers
173
- * to the asking node, and retires the bridge before this resolves. */
174
- resolveHumanTicket(nodeId: string, body: HumanResolveRequest): Promise<HumanResolveResultDTO>;
175
- /** Cancel a pending ticket: a terminal canceled result, the bridge retired,
176
- * every subscriber but the caller notified. */
177
- cancelHumanTicket(nodeId: string, body: HumanCancelRequest): Promise<HumanCancelResultDTO>;
171
+ * inbox claim where one exists), publishes the canonical result, and follows
172
+ * its optional reply route before this resolves. */
173
+ resolveHumanTicket(ticketId: string, body: HumanResolveRequest): Promise<HumanResolveResultDTO>;
174
+ /** Cancel a pending ticket and retire its optional reply bridge. */
175
+ cancelHumanTicket(ticketId: string, body: HumanCancelRequest): Promise<HumanCancelResultDTO>;
178
176
  createReview(req: CreateReviewRequest): Promise<ReviewDTO>;
179
177
  listReviews(query?: ListReviewsQuery): Promise<ReviewListDTO>;
180
178
  getReview(reviewId: string): Promise<ReviewDTO>;
@@ -205,15 +203,13 @@ export declare class CrtrClient {
205
203
  postInboxProgress(ticketId: InboxTicketIdDTO, responses: PageResponsesDTO): Promise<void>;
206
204
  /** Get the published response for a resolved page ticket. 404 if pending or canceled. */
207
205
  getInboxResponse(ticketId: InboxTicketIdDTO): Promise<InboxPageResponseDTO>;
208
- /** The page's body-level HTML payload, for pending, resolved, and canceled
209
- * tickets alike. The host wraps it and injects the page runtime bundle. */
210
- renderHumanInboxPage(ticketId: InboxTicketIdDTO): Promise<InboxPageRenderDTO>;
211
- /** One built page runtime asset. Pass the previously returned `etag` as
212
- * `ifNoneMatch` to get a 304 (and no bytes) while the cached copy is
213
- * current. The one non-JSON route on this surface. */
214
- getPagesBundleAsset(asset: 'js' | 'css', ifNoneMatch?: string): Promise<PagesBundleAssetDTO>;
215
206
  /** Cancel a ticket (terminal response, never deletion). */
216
207
  cancelHumanInboxTicket(ticketId: InboxTicketIdDTO, request?: CancelInboxTicketRequest): Promise<CanceledTicketResultDTO>;
208
+ /** Resolve one page feedback comment — the bound companion's report that it
209
+ * has been dealt with. `nodeId` names the caller; the daemon refuses any
210
+ * node but the ticket's companion. Terminal for the comment; appends no
211
+ * chat turn. */
212
+ resolvePageFeedbackComment(ticketId: InboxTicketIdDTO, commentId: string, nodeId: string): Promise<PageFeedbackResolutionDTO>;
217
213
  /** Composed client-side from `GET /v1/nodes` + `GET /v1/status` (spec §6.3 —
218
214
  * the dashboard is absorbed into those two reads; there is no single route).
219
215
  * `generated_at` is the client-side capture instant of the composition. */
@@ -250,6 +246,10 @@ export declare class CrtrClient {
250
246
  * wrapper goes through here; only the non-JSON routes call it directly. */
251
247
  private send;
252
248
  private nodePath;
249
+ /** Validate a human interaction id before route construction. Reply-bearing
250
+ * tickets use bridge ids and standalone pages use page ids; both obey the
251
+ * safe node-id segment contract. */
252
+ private interactionPath;
253
253
  /** Validate a background job id before route construction. Job ids arrive
254
254
  * from the daemon's file-backed roster and must remain one path segment. */
255
255
  private jobPath;
@@ -287,10 +287,9 @@ export class CrtrClient {
287
287
  getProfile(name) {
288
288
  return this.request('GET', routes.profile(name));
289
289
  }
290
- /** Delete one profile by exact id or unique name (`DELETE /v1/profiles/:name`,
291
- * idempotent — a miss is success). */
292
- async deleteProfile(name) {
293
- await this.request('DELETE', routes.profile(name));
290
+ /** Force-delete or detach one profile by exact id or unique name. */
291
+ deleteProfile(name, req) {
292
+ return this.request('DELETE', routes.profile(name), req);
294
293
  }
295
294
  // ---- Model auth --------------------------------------------------------
296
295
  listModelAuth() {
@@ -310,15 +309,14 @@ export class CrtrClient {
310
309
  return this.request('POST', routes.humanBridge(), req);
311
310
  }
312
311
  /** Resolve a page ticket answer. crtrd claims the ticket (taking over a live
313
- * inbox claim where one exists), publishes the canonical result, delivers
314
- * to the asking node, and retires the bridge before this resolves. */
315
- resolveHumanTicket(nodeId, body) {
316
- return this.request('POST', routes.humanTicketResolve(this.nodePath(nodeId)), body);
312
+ * inbox claim where one exists), publishes the canonical result, and follows
313
+ * its optional reply route before this resolves. */
314
+ resolveHumanTicket(ticketId, body) {
315
+ return this.request('POST', routes.humanTicketResolve(this.interactionPath(ticketId)), body);
317
316
  }
318
- /** Cancel a pending ticket: a terminal canceled result, the bridge retired,
319
- * every subscriber but the caller notified. */
320
- cancelHumanTicket(nodeId, body) {
321
- return this.request('POST', routes.humanTicketCancel(this.nodePath(nodeId)), body);
317
+ /** Cancel a pending ticket and retire its optional reply bridge. */
318
+ cancelHumanTicket(ticketId, body) {
319
+ return this.request('POST', routes.humanTicketCancel(this.interactionPath(ticketId)), body);
322
320
  }
323
321
  // ---- Daemon-owned document reviews and comments -----------------------
324
322
  createReview(req) {
@@ -401,35 +399,20 @@ export class CrtrClient {
401
399
  getInboxResponse(ticketId) {
402
400
  return this.request('GET', routes.humanInboxResponse(this.ticketId(ticketId)));
403
401
  }
404
- /** The page's body-level HTML payload, for pending, resolved, and canceled
405
- * tickets alike. The host wraps it and injects the page runtime bundle. */
406
- renderHumanInboxPage(ticketId) {
407
- return this.request('GET', routes.humanInboxRender(this.ticketId(ticketId)));
408
- }
409
- /** One built page runtime asset. Pass the previously returned `etag` as
410
- * `ifNoneMatch` to get a 304 (and no bytes) while the cached copy is
411
- * current. The one non-JSON route on this surface. */
412
- async getPagesBundleAsset(asset, ifNoneMatch) {
413
- if (asset !== 'js' && asset !== 'css') {
414
- throw new TypeError(`invalid page bundle asset: ${JSON.stringify(asset)}`);
415
- }
416
- const res = await this.send('GET', routes.humanPagesBundle(asset), undefined, ifNoneMatch === undefined ? undefined : { 'if-none-match': ifNoneMatch });
417
- if (res.status === 304) {
418
- return { status: 304, etag: res.headers['etag'] ?? '', content_type: res.headers['content-type'] ?? '', content: null };
419
- }
420
- if (res.status < 200 || res.status >= 300)
421
- parse(res); // throws the mapped ApiError
422
- return {
423
- status: 200,
424
- etag: res.headers['etag'] ?? '',
425
- content_type: res.headers['content-type'] ?? '',
426
- content: res.text,
427
- };
428
- }
429
402
  /** Cancel a ticket (terminal response, never deletion). */
430
403
  cancelHumanInboxTicket(ticketId, request) {
431
404
  return this.request('POST', routes.humanInboxCancel(this.ticketId(ticketId)), request ?? {});
432
405
  }
406
+ /** Resolve one page feedback comment — the bound companion's report that it
407
+ * has been dealt with. `nodeId` names the caller; the daemon refuses any
408
+ * node but the ticket's companion. Terminal for the comment; appends no
409
+ * chat turn. */
410
+ resolvePageFeedbackComment(ticketId, commentId, nodeId) {
411
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(commentId)) {
412
+ throw new TypeError(`invalid feedback comment id: ${JSON.stringify(commentId)}`);
413
+ }
414
+ return this.request('POST', routes.humanInboxFeedbackResolve(this.ticketId(ticketId), commentId), { node_id: nodeId });
415
+ }
433
416
  // ---- Canvas reads / maintenance ---------------------------------------
434
417
  /** Composed client-side from `GET /v1/nodes` + `GET /v1/status` (spec §6.3 —
435
418
  * the dashboard is absorbed into those two reads; there is no single route).
@@ -512,6 +495,15 @@ export class CrtrClient {
512
495
  }
513
496
  return id;
514
497
  }
498
+ /** Validate a human interaction id before route construction. Reply-bearing
499
+ * tickets use bridge ids and standalone pages use page ids; both obey the
500
+ * safe node-id segment contract. */
501
+ interactionPath(id) {
502
+ if (!isSafeNodeId(id)) {
503
+ throw new ApiError(400, 'invalid_ticket_id', `invalid interaction ticket id: ${JSON.stringify(id)}`);
504
+ }
505
+ return id;
506
+ }
515
507
  /** Validate a background job id before route construction. Job ids arrive
516
508
  * from the daemon's file-backed roster and must remain one path segment. */
517
509
  jobPath(id) {
@@ -23,7 +23,7 @@ export interface BrokerSettleRequest {
23
23
  stopReason: string;
24
24
  backgroundJobsRunning: boolean;
25
25
  pushedFinal: boolean;
26
- askedHuman: boolean;
26
+ requestedHumanReply: boolean;
27
27
  }
28
28
  /** The only consequence a settle caller may enact. crtrd has already committed
29
29
  * every canvas and placement effect before returning this directive. */
@@ -75,12 +75,14 @@ export interface BrokerExtensionNodeDTO {
75
75
  profile_id: string | null;
76
76
  managed_worktree?: {
77
77
  state: 'open' | 'closed';
78
+ cleanup?: 'pending' | 'complete';
78
79
  path: string;
79
80
  branch: string;
80
81
  base_ref: string;
81
82
  base_sha: string;
82
83
  } | null;
83
84
  review_binding?: {
85
+ kind?: 'review' | 'page_feedback';
84
86
  review_id: string;
85
87
  origin_node_id: string;
86
88
  branch_file: string;
@@ -12,14 +12,25 @@ export interface BrokerErrorFrame {
12
12
  }
13
13
  /**
14
14
  * The `welcome` frame's history/state snapshot, narrowed to what a relay consumer
15
- * replays: the message history and the streaming flag. `M` is the message shape
16
- * (pi's `AgentMessage` in a pi consumer; `unknown` by default).
15
+ * replays: the message history, the streaming flag, and the unrun queue. `M` is
16
+ * the message shape (pi's `AgentMessage` in a pi consumer; `unknown` by default).
17
+ *
18
+ * `queued` carries the same two arrays a live `queue_update` frame carries — the
19
+ * steer/follow-up texts accepted by the engine but not started yet. A relay that
20
+ * renders queued rows needs it to survive (re)attach: a message enqueued mid-turn
21
+ * is in NEITHER `messages` (it never ran) nor any later frame the consumer has
22
+ * already seen. Optional: a broker on an older runtime generation omits it, which
23
+ * a consumer reads as an empty queue.
17
24
  */
18
25
  export interface BrokerWelcomeSnapshot<M = unknown> {
19
26
  messages: M[];
20
27
  state?: {
21
28
  isStreaming?: boolean;
22
29
  };
30
+ queued?: {
31
+ steering?: string[];
32
+ followUp?: string[];
33
+ };
23
34
  }
24
35
  /**
25
36
  * The crtrd broker `welcome` control frame — the history/resume catch-up snapshot
@@ -13,8 +13,8 @@
13
13
  // `unknown` defaults.
14
14
  //
15
15
  // NARROWING NOTE: `BrokerWelcomeSnapshot` is deliberately the fields a live/history
16
- // relay mapper reads — `messages` plus `state.isStreaming` not the broker's full
17
- // authoritative `BrokerSnapshot` (stats + the complete `get_state` mirror). The
18
- // broker sends the richer object on the wire; consumers that only replay history
19
- // read this narrowing of it.
16
+ // relay mapper reads — `messages`, `state.isStreaming`, and the unrun `queued`
17
+ // texts — not the broker's full authoritative `BrokerSnapshot` (stats + the
18
+ // complete `get_state` mirror). The broker sends the richer object on the wire;
19
+ // consumers that only replay history read this narrowing of it.
20
20
  export {};
@@ -36,21 +36,22 @@ export interface FeedbackResultDTO {
36
36
  commentsTotal: number;
37
37
  commentsUnresolved: number;
38
38
  }
39
- /** `POST /v1/human/tickets/{node_id}/resolve` body — a page answer keyed by slot id. */
39
+ /** `POST /v1/human/tickets/{ticket_id}/resolve` body — a page answer keyed by slot id. */
40
40
  export interface HumanResolveRequest {
41
41
  responses: Record<string, Record<string, unknown>>;
42
42
  }
43
- /** `POST /v1/human/tickets/{node_id}/cancel` body. */
43
+ /** `POST /v1/human/tickets/{ticket_id}/cancel` body. */
44
44
  export interface HumanCancelRequest {
45
45
  reason?: string;
46
46
  actor?: string;
47
47
  }
48
- /** `POST /v1/human/tickets/{node_id}/resolve` result. */
48
+ /** `POST /v1/human/tickets/{ticket_id}/resolve` result. */
49
49
  export interface HumanResolveResultDTO {
50
- delivered: true;
50
+ completed: true;
51
+ reply_delivered: boolean;
51
52
  kind: 'page';
52
53
  }
53
- /** `POST /v1/human/tickets/{node_id}/cancel` result. */
54
+ /** `POST /v1/human/tickets/{ticket_id}/cancel` result. */
54
55
  export interface HumanCancelResultDTO {
55
56
  canceled: true;
56
57
  }
@@ -5,6 +5,7 @@ export interface TicketSourceDTO {
5
5
  sessionName?: string;
6
6
  askedBy?: string;
7
7
  blockedSince?: IsoTime;
8
+ emittedAt?: IsoTime;
8
9
  profileName?: string;
9
10
  nodeId?: string;
10
11
  }
@@ -22,13 +23,14 @@ export interface PageTicketSummaryDTO {
22
23
  title: string;
23
24
  subtitle?: string;
24
25
  placement: 'inline' | 'panel';
25
- dialect: 'md' | 'html';
26
+ dialect: 'jsx' | 'html';
27
+ inbox: boolean;
26
28
  steps: number;
27
- blocked_since: IsoTime;
29
+ emitted_at: IsoTime;
28
30
  source: TicketSourceDTO;
29
31
  slot_kinds: string[];
30
32
  awaits_response: boolean;
31
- state?: 'pending' | 'resolved' | 'canceled';
33
+ state?: 'pending' | 'resolved' | 'canceled' | 'passive';
32
34
  /** Present only on resolved history entries; the stored one-line answer digest. */
33
35
  answer_digest?: string;
34
36
  }
@@ -46,25 +48,27 @@ export interface PageSlotDTO {
46
48
  }
47
49
  /** The nested protocol object is deliberately camelCase on the wire. */
48
50
  export interface PageManifestDTO {
49
- schema: 'crtr.page/v1';
50
- dialect: 'md' | 'html';
51
+ schema: 'crtr.page/v2';
52
+ dialect: 'jsx' | 'html';
51
53
  title: string;
52
54
  subtitle?: string;
53
- placement: 'inline' | 'panel';
54
- document: 'page.md' | 'page.html';
55
+ delivery: {
56
+ placement: 'inline' | 'panel';
57
+ inbox: boolean;
58
+ reply: boolean;
59
+ };
60
+ document: 'page.tsx' | 'page.html';
55
61
  steps: number;
56
62
  slots: PageSlotDTO[];
57
63
  source?: TicketSourceDTO;
58
64
  }
65
+ /** Answer-annotation anchors: option on UserQuestion, row on UserTable.
66
+ * Feedback on other page content — including the question text — is a
67
+ * ticket-level feedback comment, never a response anchor. */
59
68
  export interface PageCommentAnchorDTO {
60
- kind: 'whole' | 'option' | 'row' | 'column' | 'card' | 'range';
69
+ kind: 'option' | 'row';
61
70
  optionId?: string;
62
71
  rowId?: string;
63
- columnId?: string;
64
- cardId?: string;
65
- start?: number;
66
- end?: number;
67
- quote?: string;
68
72
  }
69
73
  export interface PageCommentDTO {
70
74
  id: string;
@@ -79,7 +83,6 @@ export interface PageOptionsResponseDTO {
79
83
  export interface PageTextResponseDTO {
80
84
  text: string;
81
85
  edited: boolean;
82
- comments: PageCommentDTO[];
83
86
  }
84
87
  export interface PageTableResponseDTO {
85
88
  selectedRowIds: string[];
@@ -88,40 +91,81 @@ export interface PageTableResponseDTO {
88
91
  }
89
92
  export interface PageCardsResponseDTO {
90
93
  selectedCardIds: string[];
91
- comments: PageCommentDTO[];
92
94
  }
93
95
  export type SlotResponseDTO = PageOptionsResponseDTO | PageTextResponseDTO | PageTableResponseDTO | PageCardsResponseDTO | Record<string, unknown>;
94
96
  export type PageResponsesDTO = Record<string, SlotResponseDTO>;
95
97
  export interface InboxPageDTO {
96
98
  ticket_id: InboxTicketIdDTO;
97
99
  kind: 'page';
98
- state: 'pending' | 'resolved' | 'canceled';
100
+ state: 'pending' | 'resolved' | 'canceled' | 'passive';
99
101
  page: PageManifestDTO;
102
+ /** JSX is compiled for the host; HTML is the authored document verbatim. */
100
103
  document: string;
101
- document_media_type: 'text/markdown' | 'text/html';
104
+ document_media_type: 'text/jsx' | 'text/html';
102
105
  progress: {
103
106
  responses: PageResponsesDTO;
104
107
  } | null;
108
+ /** Ticket-attached feedback comments and the companion conversation they
109
+ * deliver to. Comments are immutable once sent — open until the companion
110
+ * resolves them. */
111
+ feedback: PageFeedbackDTO;
112
+ }
113
+ export interface PageFeedbackCommentDTO {
114
+ id: string;
115
+ /** The highlighted text the note is about; for a chart, its title. */
116
+ quote: string;
117
+ /** Surrounding text that locates the quote on the page. */
118
+ context?: string;
119
+ note: string;
120
+ /** Open until the companion has dealt with it; resolution is terminal. */
121
+ status: 'open' | 'resolved';
122
+ created_at: IsoTime;
123
+ resolved_at?: IsoTime;
124
+ }
125
+ export interface PageFeedbackDTO {
126
+ /** The ticket-bound companion conversation comments deliver to; null until
127
+ * the first comment realizes it. */
128
+ companion_node_id: string | null;
129
+ /** How many comments remain open. Zero once feedback exists is the ticket's
130
+ * authoritative signal that the companion has dealt with all of it. */
131
+ open_count: number;
132
+ comments: PageFeedbackCommentDTO[];
133
+ }
134
+ /** `POST /v1/human/inbox/:ticket_id/feedback-comments` body. */
135
+ export interface CreatePageFeedbackCommentRequest {
136
+ quote: string;
137
+ context?: string;
138
+ note: string;
139
+ }
140
+ export interface PageFeedbackDeliveryDTO {
141
+ target_node_id: string;
142
+ status: 'delivered' | 'failed';
143
+ via?: 'engine' | 'inbox';
144
+ woke: boolean;
145
+ error?: string;
146
+ }
147
+ /** Create result: the new comment, the ticket's full feedback state after it,
148
+ * and the delivery outcome in the companion conversation. */
149
+ export interface PageFeedbackMutationDTO {
150
+ comment: PageFeedbackCommentDTO;
151
+ feedback: PageFeedbackDTO;
152
+ delivery: PageFeedbackDeliveryDTO;
153
+ }
154
+ /** `POST .../feedback-comments/:comment_id/resolve` request. Resolution is
155
+ * companion-only: `node_id` names the calling node and must equal the
156
+ * ticket's bound companion. */
157
+ export interface ResolvePageFeedbackCommentRequest {
158
+ node_id: string;
159
+ }
160
+ /** `POST .../feedback-comments/:comment_id/resolve` result. Resolution appends
161
+ * no chat turn; the companion's own conversational report covers it. */
162
+ export interface PageFeedbackResolutionDTO {
163
+ comment: PageFeedbackCommentDTO;
164
+ feedback: PageFeedbackDTO;
105
165
  }
106
166
  export interface InboxPageHistoryDTO {
107
167
  tickets: PageTicketSummaryDTO[];
108
168
  }
109
- /** `GET /v1/human/inbox/:ticket_id/render` — the page's body-level HTML
110
- * payload. It carries the page's own prose and `crtr-*` slot elements only;
111
- * the host supplies the surrounding document and injects the page runtime
112
- * bundle it chooses to serve. */
113
- export interface InboxPageRenderDTO {
114
- html: string;
115
- }
116
- /** A client-side projection of `GET /v1/human/pages/bundle.{js,css}` — the one
117
- * non-JSON route on this surface. `content` is null on a 304, where the
118
- * caller's cached copy is still current. */
119
- export interface PagesBundleAssetDTO {
120
- status: 200 | 304;
121
- etag: string;
122
- content_type: string;
123
- content: string | null;
124
- }
125
169
  export interface RespondInboxPageRequest {
126
170
  responses: PageResponsesDTO;
127
171
  }
@@ -145,7 +189,10 @@ export interface PageAnswerGroupDTO {
145
189
  }[];
146
190
  }
147
191
  export interface PageAnswerCommentDTO {
148
- anchor: PageCommentAnchorDTO;
192
+ /** Legacy stored responses may still carry the retired `whole` anchor. */
193
+ anchor: PageCommentAnchorDTO | {
194
+ kind: 'whole';
195
+ };
149
196
  anchorLabel: string;
150
197
  text: string;
151
198
  }
@@ -90,6 +90,8 @@ export interface NodePathsDTO {
90
90
  /** A node's managed git worktree, if any. */
91
91
  export interface NodeWorktreeDTO {
92
92
  state: 'open' | 'closed';
93
+ /** Pending cleanup must be run manually after the owner exits. */
94
+ cleanup?: 'pending' | 'complete';
93
95
  path: string;
94
96
  branch: string;
95
97
  repo_root: string;
@@ -98,9 +100,13 @@ export interface NodeWorktreeDTO {
98
100
  created: IsoTime;
99
101
  closed?: IsoTime;
100
102
  }
101
- /** Immutable review-companion provenance and fork coordinates. Present only on
102
- * a `review/companion` node spawned by the daemon for a human review. */
103
+ /** Immutable companion provenance and fork coordinates. Present only on a
104
+ * daemon-spawned companion node: a `review/companion` node for a human review
105
+ * (`kind` absent or `review`), or — for a page ticket's feedback conversation
106
+ * (`kind: 'page_feedback'`, review_id = ticket id, target_file = the page
107
+ * source) — a fork of the sending node itself, spawned with its kind. */
103
108
  export interface NodeReviewBindingDTO {
109
+ kind?: 'review' | 'page_feedback';
104
110
  review_id: string;
105
111
  origin_node_id: string;
106
112
  branch_file: string;
@@ -3,6 +3,29 @@ export interface EnsureProfileRequest {
3
3
  /** Absolute project directories in the profile's purview. */
4
4
  projects?: string[];
5
5
  }
6
+ /** `DELETE /v1/profiles/{name}` body. Destructive deletion is never implicit. */
7
+ export interface DeleteProfileRequest {
8
+ force: boolean;
9
+ /** Preserve nodes and human history while removing their profile identity. */
10
+ detach?: boolean;
11
+ /** The invoking broker, when the request came from a node-owned CLI process. */
12
+ caller_node_id?: string | null;
13
+ }
14
+ export type DeleteProfileMode = 'deleted' | 'detached';
15
+ /** The completed deletion, or the accepted plan when the invoking node is part of it. */
16
+ export interface DeleteProfileResultDTO {
17
+ profile_id: string;
18
+ name: string;
19
+ mode: DeleteProfileMode;
20
+ nodes: number;
21
+ crons: number;
22
+ tickets: number;
23
+ reviews: number;
24
+ default_pins: number;
25
+ /** True only when crtrd acknowledged the response before tearing down its caller. */
26
+ accepted?: true;
27
+ grace_ms?: number;
28
+ }
6
29
  /** A profile projection. */
7
30
  export interface ProfileDTO {
8
31
  /** Stable profile-directory id (`<slug>-<id>`). */
@@ -1,3 +1,3 @@
1
- // Profile DTOs (spec §6.6). Server-side for remote/Core (P2) consumers; local
2
- // `crtr profile *` verbs stay fs-local.
1
+ // Profile DTOs (spec §6.6). Profile deletion crosses profile, canvas, cron,
2
+ // inbox, and review state, so every consumer routes it through crtrd.
3
3
  export {};
@@ -7,13 +7,11 @@ export interface CloseWorktreeResultDTO {
7
7
  worktree_path: string;
8
8
  /** The commit SHA the recorded local base branch was fast-forwarded onto. */
9
9
  landed_sha: string;
10
- /** False when the landing happened but the checkout could not be removed
11
- * automatically the close still counts as done (state is closed);
12
- * `worktree_remove_error` carries the manual-cleanup note. */
10
+ /** False while the caller's checkout remains registered for deferred cleanup.
11
+ * `worktree_remove_error` names that state and the safe follow-up. */
13
12
  worktree_removed: boolean;
14
13
  worktree_remove_error?: string;
15
- /** False when the landing happened but the local branch could not be deleted
16
- * automatically — same non-fatal treatment as `worktree_removed`. */
14
+ /** False while the local branch remains checked out by the deferred cleanup. */
17
15
  branch_deleted: boolean;
18
16
  branch_delete_error?: string;
19
17
  }
@@ -59,8 +59,8 @@ export declare const routes: {
59
59
  readonly canvasPrune: () => string;
60
60
  readonly canvasRebuildIndex: () => string;
61
61
  readonly humanBridge: () => string;
62
- readonly humanTicketResolve: (nodeId: string) => string;
63
- readonly humanTicketCancel: (nodeId: string) => string;
62
+ readonly humanTicketResolve: (ticketId: string) => string;
63
+ readonly humanTicketCancel: (ticketId: string) => string;
64
64
  readonly humanReviews: () => string;
65
65
  readonly humanReview: (reviewId: string) => string;
66
66
  readonly humanReviewByBridge: (bridgeNodeId: string) => string;
@@ -81,9 +81,7 @@ export declare const routes: {
81
81
  readonly humanInboxProgress: (ticketId: string) => string;
82
82
  readonly humanInboxResponse: (ticketId: string) => string;
83
83
  readonly humanInboxCancel: (ticketId: string) => string;
84
- readonly humanInboxRender: (ticketId: string) => string;
85
- /** The built page runtime assets, served for whatever host renders a page. */
86
- readonly humanPagesBundle: (asset: "js" | "css") => string;
84
+ readonly humanInboxFeedbackResolve: (ticketId: string, commentId: string) => string;
87
85
  readonly profiles: () => string;
88
86
  readonly profile: (name: string) => string;
89
87
  readonly modelAuths: () => string;
@@ -83,8 +83,8 @@ export const routes = {
83
83
  // Human bridge creation + the pinned ticket route table (design §"The `/v1`
84
84
  // surface") — every ticket route is addressed by node id only.
85
85
  humanBridge: () => `${V}/human/bridge`,
86
- humanTicketResolve: (nodeId) => `${V}/human/tickets/${nodeId}/resolve`,
87
- humanTicketCancel: (nodeId) => `${V}/human/tickets/${nodeId}/cancel`,
86
+ humanTicketResolve: (ticketId) => `${V}/human/tickets/${ticketId}/resolve`,
87
+ humanTicketCancel: (ticketId) => `${V}/human/tickets/${ticketId}/cancel`,
88
88
  // Daemon-owned document reviews and comments. All interpolated ids are
89
89
  // guarded by `CrtrClient` before they reach these pure builders.
90
90
  humanReviews: () => `${V}/human/reviews`,
@@ -108,10 +108,8 @@ export const routes = {
108
108
  humanInboxProgress: (ticketId) => `${V}/human/inbox/${ticketId}/progress`,
109
109
  humanInboxResponse: (ticketId) => `${V}/human/inbox/${ticketId}/response`,
110
110
  humanInboxCancel: (ticketId) => `${V}/human/inbox/${ticketId}/cancel`,
111
- humanInboxRender: (ticketId) => `${V}/human/inbox/${ticketId}/render`,
112
- /** The built page runtime assets, served for whatever host renders a page. */
113
- humanPagesBundle: (asset) => `${V}/human/pages/bundle.${asset}`,
114
- // Profiles (server-side for P2 Core; CLI profile verbs stay fs-local)
111
+ humanInboxFeedbackResolve: (ticketId, commentId) => `${V}/human/inbox/${ticketId}/feedback-comments/${commentId}/resolve`,
112
+ // Profiles (deletion is daemon-owned because it crosses canvas state)
115
113
  profiles: () => `${V}/profiles`,
116
114
  profile: (name) => `${V}/profiles/${name}`,
117
115
  // Model auth
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter-api",
3
- "version": "0.3.198",
3
+ "version": "0.3.200",
4
4
  "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, and the CrtrClient. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/api/index.js",