@north-light/crouter-api 0.3.171 → 0.3.173

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -11,7 +11,9 @@ 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
13
  import type { CredentialRemovalResultDTO, CredentialResultDTO, InstallCredentialRequest, ModelAuthListDTO } from './dto/modelauth.js';
14
- import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanConsultResultDTO, HumanDeliverResultDTO, HumanVisualResultDTO } from './dto/human.js';
14
+ import type { CreateHumanBridgeRequest, HumanBridgeResultDTO, HumanCancelRequest, HumanCancelResultDTO, HumanResolveRequest, HumanResolveResultDTO } from './dto/human.js';
15
+ import type { CancelReviewRequest, CreateReviewRequest, ListReviewsQuery, ReviewCancelResultDTO, ReviewDocumentBaseDTO, ReviewDTO, ReviewListDTO, ReviewOpenResultDTO, ReviewSubmitResultDTO } from './dto/reviews.js';
16
+ import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCommentsQuery, ReadReviewCommentEventsQuery, ReviewCommentActionRequest, ReviewCommentDetailDTO, ReviewCommentEventsDTO, ReviewCommentListDTO, ReviewCommentMutationDTO, ReviewCommentRangeBatchRequest, ReviewCommentRangeBatchResultDTO } from './dto/review-comments.js';
15
17
  import type { CancelInboxTicketRequest, CanceledTicketResultDTO, DeckTicketResultDTO, InboxDeckDTO, InboxListDTO, InboxTicketIdDTO, RespondInboxDeckRequest } from './dto/inbox.js';
16
18
  import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
17
19
  import type { CloseWorktreeResultDTO } from './dto/worktree.js';
@@ -146,16 +148,30 @@ export declare class CrtrClient {
146
148
  * (`spawnNode` server-side). Distinct from `createNode` (which launches a
147
149
  * broker) precisely because a human bridge must never have one. */
148
150
  createHumanBridge(req: CreateHumanBridgeRequest): Promise<HumanBridgeResultDTO>;
149
- /** Run the registered humanloop completion handler server-side for one
150
- * `humanloop.completion/v1` event. crtrd re-verifies the full trust binding
151
- * before performing any canvas mutation. */
152
- deliverHuman(event: unknown): Promise<HumanDeliverResultDTO>;
153
- /** Run the registered follow-up handler server-side for one
154
- * `humanloop.followup-request/v1` event. */
155
- consultHuman(event: unknown): Promise<HumanConsultResultDTO>;
156
- /** Run the registered visual handler server-side for one
157
- * `humanloop.visual-request-event/v1` event. */
158
- visualHuman(event: unknown): Promise<HumanVisualResultDTO>;
151
+ /** Resolve a deck ticket answer. crtrd claims the ticket (taking over a live
152
+ * inbox claim where one exists), publishes the canonical result, delivers
153
+ * to the asking node, and retires the bridge before this resolves. */
154
+ resolveHumanTicket(nodeId: string, body: HumanResolveRequest): Promise<HumanResolveResultDTO>;
155
+ /** Cancel a pending ticket: a terminal canceled result, the bridge retired,
156
+ * every subscriber but the caller notified. */
157
+ cancelHumanTicket(nodeId: string, body: HumanCancelRequest): Promise<HumanCancelResultDTO>;
158
+ createReview(req: CreateReviewRequest): Promise<ReviewDTO>;
159
+ listReviews(query?: ListReviewsQuery): Promise<ReviewListDTO>;
160
+ getReview(reviewId: string): Promise<ReviewDTO>;
161
+ getReviewByBridge(bridgeNodeId: string): Promise<ReviewDTO>;
162
+ openReview(reviewId: string): Promise<ReviewOpenResultDTO>;
163
+ submitReview(reviewId: string): Promise<ReviewSubmitResultDTO>;
164
+ cancelReview(reviewId: string, req?: CancelReviewRequest): Promise<ReviewCancelResultDTO>;
165
+ getReviewDocumentBase(reviewId: string): Promise<ReviewDocumentBaseDTO>;
166
+ createReviewComment(reviewId: string | undefined, req: CreateReviewCommentRequest): Promise<ReviewCommentMutationDTO>;
167
+ listReviewComments(reviewId?: string, query?: ListReviewCommentsQuery): Promise<ReviewCommentListDTO>;
168
+ readReviewCommentEvents(reviewId: string, query?: ReadReviewCommentEventsQuery): Promise<ReviewCommentEventsDTO>;
169
+ updateReviewCommentRanges(reviewId: string, req: ReviewCommentRangeBatchRequest): Promise<ReviewCommentRangeBatchResultDTO>;
170
+ getReviewComment(commentId: string): Promise<ReviewCommentDetailDTO>;
171
+ editReviewComment(commentId: string, req: EditReviewCommentRequest): Promise<ReviewCommentMutationDTO>;
172
+ resolveReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
173
+ reopenReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
174
+ deleteReviewComment(commentId: string, req?: ReviewCommentActionRequest): Promise<ReviewCommentMutationDTO>;
159
175
  /** Pending deck/review tickets across every available crouter-owned
160
176
  * humanloop root. */
161
177
  listHumanInbox(): Promise<InboxListDTO>;
@@ -210,6 +226,16 @@ export declare class CrtrClient {
210
226
  * precondition, distinct from `nodePath`'s `ApiError` because that one IS a
211
227
  * request the server could plausibly receive and reject itself). */
212
228
  private ticketId;
229
+ /** Validate a review id before route construction (D-A6). Reviews are minted
230
+ * and addressed like node ids, but arrive from agent argv, so a malformed
231
+ * one is a plausible request the server would also reject — `ApiError`,
232
+ * not `TypeError`, matching `nodePath`. */
233
+ private reviewPath;
234
+ /** Validate a comment id before route construction (D-A6). Comment ids are
235
+ * daemon-minted 32-char lowercase hex, but — like `reviewPath` — arrive from
236
+ * agent argv, so a bad one is a plausible request the server would also
237
+ * reject, not a caller-bug `TypeError` like `ticketId`. */
238
+ private commentPath;
213
239
  private transport;
214
240
  private isColdSocketError;
215
241
  /** A connection torn down MID-request (Node's "socket hang up" / a broken
package/dist/client.js CHANGED
@@ -268,21 +268,70 @@ export class CrtrClient {
268
268
  createHumanBridge(req) {
269
269
  return this.request('POST', routes.humanBridge(), req);
270
270
  }
271
- /** Run the registered humanloop completion handler server-side for one
272
- * `humanloop.completion/v1` event. crtrd re-verifies the full trust binding
273
- * before performing any canvas mutation. */
274
- deliverHuman(event) {
275
- return this.request('POST', routes.humanDeliver(), event);
276
- }
277
- /** Run the registered follow-up handler server-side for one
278
- * `humanloop.followup-request/v1` event. */
279
- consultHuman(event) {
280
- return this.request('POST', routes.humanConsult(), event);
281
- }
282
- /** Run the registered visual handler server-side for one
283
- * `humanloop.visual-request-event/v1` event. */
284
- visualHuman(event) {
285
- return this.request('POST', routes.humanVisual(), event);
271
+ /** Resolve a deck ticket answer. crtrd claims the ticket (taking over a live
272
+ * inbox claim where one exists), publishes the canonical result, delivers
273
+ * to the asking node, and retires the bridge before this resolves. */
274
+ resolveHumanTicket(nodeId, body) {
275
+ return this.request('POST', routes.humanTicketResolve(this.nodePath(nodeId)), body);
276
+ }
277
+ /** Cancel a pending ticket: a terminal canceled result, the bridge retired,
278
+ * every subscriber but the caller notified. */
279
+ cancelHumanTicket(nodeId, body) {
280
+ return this.request('POST', routes.humanTicketCancel(this.nodePath(nodeId)), body);
281
+ }
282
+ // ---- Daemon-owned document reviews and comments -----------------------
283
+ createReview(req) {
284
+ return this.request('POST', routes.humanReviews(), req);
285
+ }
286
+ listReviews(query) {
287
+ return this.request('GET', withQuery(routes.humanReviews(), query));
288
+ }
289
+ getReview(reviewId) {
290
+ return this.request('GET', routes.humanReview(this.reviewPath(reviewId)));
291
+ }
292
+ getReviewByBridge(bridgeNodeId) {
293
+ return this.request('GET', routes.humanReviewByBridge(this.nodePath(bridgeNodeId)));
294
+ }
295
+ openReview(reviewId) {
296
+ return this.request('POST', routes.humanReviewOpen(this.reviewPath(reviewId)), {});
297
+ }
298
+ submitReview(reviewId) {
299
+ return this.request('POST', routes.humanReviewSubmit(this.reviewPath(reviewId)), {});
300
+ }
301
+ cancelReview(reviewId, req = {}) {
302
+ return this.request('POST', routes.humanReviewCancel(this.reviewPath(reviewId)), req);
303
+ }
304
+ getReviewDocumentBase(reviewId) {
305
+ return this.request('GET', routes.humanReviewDocument(this.reviewPath(reviewId)));
306
+ }
307
+ createReviewComment(reviewId, req) {
308
+ const path = reviewId === undefined ? 'self' : this.reviewPath(reviewId);
309
+ return this.request('POST', routes.humanReviewComments(path), req);
310
+ }
311
+ listReviewComments(reviewId, query) {
312
+ const path = reviewId === undefined ? 'self' : this.reviewPath(reviewId);
313
+ return this.request('GET', withQuery(routes.humanReviewComments(path), query));
314
+ }
315
+ readReviewCommentEvents(reviewId, query) {
316
+ return this.request('GET', withQuery(routes.humanReviewCommentEvents(this.reviewPath(reviewId)), query));
317
+ }
318
+ updateReviewCommentRanges(reviewId, req) {
319
+ return this.request('POST', routes.humanReviewCommentRanges(this.reviewPath(reviewId)), req);
320
+ }
321
+ getReviewComment(commentId) {
322
+ return this.request('GET', routes.humanComment(this.commentPath(commentId)));
323
+ }
324
+ editReviewComment(commentId, req) {
325
+ return this.request('POST', routes.humanCommentEdit(this.commentPath(commentId)), req);
326
+ }
327
+ resolveReviewComment(commentId, req = {}) {
328
+ return this.request('POST', routes.humanCommentResolve(this.commentPath(commentId)), req);
329
+ }
330
+ reopenReviewComment(commentId, req = {}) {
331
+ return this.request('POST', routes.humanCommentReopen(this.commentPath(commentId)), req);
332
+ }
333
+ deleteReviewComment(commentId, req = {}) {
334
+ return this.request('POST', routes.humanCommentDelete(this.commentPath(commentId)), req);
286
335
  }
287
336
  // ---- Humanloop inbox (Northlight crouter-inbox v1, inbox-contract.md §A) --
288
337
  /** Pending deck/review tickets across every available crouter-owned
@@ -406,6 +455,26 @@ export class CrtrClient {
406
455
  }
407
456
  return id;
408
457
  }
458
+ /** Validate a review id before route construction (D-A6). Reviews are minted
459
+ * and addressed like node ids, but arrive from agent argv, so a malformed
460
+ * one is a plausible request the server would also reject — `ApiError`,
461
+ * not `TypeError`, matching `nodePath`. */
462
+ reviewPath(id) {
463
+ if (!isSafeNodeId(id)) {
464
+ throw new ApiError(400, 'invalid_review_id', `invalid review id: ${JSON.stringify(id)}`);
465
+ }
466
+ return id;
467
+ }
468
+ /** Validate a comment id before route construction (D-A6). Comment ids are
469
+ * daemon-minted 32-char lowercase hex, but — like `reviewPath` — arrive from
470
+ * agent argv, so a bad one is a plausible request the server would also
471
+ * reject, not a caller-bug `TypeError` like `ticketId`. */
472
+ commentPath(id) {
473
+ if (!/^[a-f0-9]{32}$/.test(id)) {
474
+ throw new ApiError(400, 'invalid_comment_id', `invalid comment id: ${JSON.stringify(id)}`);
475
+ }
476
+ return id;
477
+ }
409
478
  transport(method, path, body) {
410
479
  const usingHttps = this.baseUrl?.protocol === 'https:';
411
480
  const doRequest = usingHttps ? httpsRequest : httpRequest;
@@ -1,29 +1,59 @@
1
- import type { IsoTime, NodeIdDTO } from './common.js';
2
- export type ConsultKindDTO = 'follow_up' | 'visual';
3
- /** A consult-outbox entry (the canvas half of a human consult/visual request). */
4
- export interface ConsultOutboxEntryDTO {
5
- request_id: string;
6
- node_id: NodeIdDTO;
7
- kind: ConsultKindDTO;
8
- dir: string;
9
- created: IsoTime;
1
+ import type { NodeIdDTO } from './common.js';
2
+ import type { InteractionResponseDTO } from './inbox.js';
3
+ /** One anchored review comment, mirroring crouter's ticket-store shape as a
4
+ * plain structural wire type (no store import). */
5
+ export interface FeedbackCommentDTO {
6
+ id: string;
7
+ /** 1-based source line where the comment is anchored (start). */
8
+ line: number;
9
+ /** 1-based source line where the anchored range ends (== line for one line). */
10
+ endLine: number;
11
+ /** Exact selected substring when the human made a visual selection. */
12
+ quote?: string;
13
+ /** 0-based byte column where a partial (charwise) selection starts on `line`. */
14
+ colStart?: number;
15
+ /** 0-based exclusive byte column where the selection ends on `endLine`. */
16
+ colEnd?: number;
17
+ /** Full source text of the anchored line(s) — context for the agent. */
18
+ lineText: string;
19
+ comment: string;
20
+ createdAt: string;
10
21
  }
11
- /** `GET /v1/canvas/consults` result. */
12
- export interface ConsultOutboxDTO {
13
- entries: ConsultOutboxEntryDTO[];
22
+ /** Immutable daemon-projected approval result, mirroring crouter's canonical
23
+ * review result as a plain structural wire type — `src/api/**` never imports
24
+ * the store's own type. */
25
+ export interface FeedbackResultDTO {
26
+ file: string;
27
+ submitted: true;
28
+ approved: true;
29
+ comments: FeedbackCommentDTO[];
30
+ submittedAt: string;
31
+ savedAt: string;
32
+ reviewId: string;
33
+ changed: boolean;
34
+ baselineSha256: string;
35
+ approvedSha256: string;
36
+ companionNodeId: string;
37
+ commentsTotal: number;
38
+ commentsUnresolved: number;
14
39
  }
15
- /** `POST /v1/canvas/consults` body. */
16
- export interface CreateConsultRequest {
17
- node_id: NodeIdDTO;
18
- kind: ConsultKindDTO;
19
- request_id: string;
20
- dir: string;
21
- root: string;
40
+ /** `POST /v1/human/tickets/{node_id}/resolve` body — a deck answer. */
41
+ export interface HumanResolveRequest {
42
+ responses: InteractionResponseDTO[];
43
+ }
44
+ /** `POST /v1/human/tickets/{node_id}/cancel` body. */
45
+ export interface HumanCancelRequest {
46
+ reason?: string;
47
+ actor?: string;
22
48
  }
23
- /** Result of enqueuing a consult. */
24
- export interface ConsultResultDTO {
25
- request_id: string;
26
- created: boolean;
49
+ /** `POST /v1/human/tickets/{node_id}/resolve` result. */
50
+ export interface HumanResolveResultDTO {
51
+ delivered: true;
52
+ kind: 'deck';
53
+ }
54
+ /** `POST /v1/human/tickets/{node_id}/cancel` result. */
55
+ export interface HumanCancelResultDTO {
56
+ canceled: true;
27
57
  }
28
58
  /** `POST /v1/human/bridge` body — create a terminal `kind:'human'` bridge node
29
59
  * via `spawnNode` (NO broker engine). Distinct from `POST /v1/nodes`, whose
@@ -39,19 +69,3 @@ export interface HumanBridgeResultDTO {
39
69
  node_id: NodeIdDTO;
40
70
  name: string;
41
71
  }
42
- /** `POST /v1/human/deliver` result — the registered humanloop completion
43
- * handler run server-side. */
44
- export interface HumanDeliverResultDTO {
45
- delivered: boolean;
46
- }
47
- /** `POST /v1/human/consult` result — the registered follow-up handler run
48
- * server-side. `handled` communicates whether an action was taken (never a
49
- * throw for a stale/superseded event). */
50
- export interface HumanConsultResultDTO {
51
- handled: boolean;
52
- }
53
- /** `POST /v1/human/visual` result — the registered visual handler run
54
- * server-side. */
55
- export interface HumanVisualResultDTO {
56
- handled: boolean;
57
- }
package/dist/dto/human.js CHANGED
@@ -1,4 +1,3 @@
1
- // Human-bridge DTOs — the CANVAS HALF ONLY (spec §6.5). The humanloop
2
- // ticket/deck store is an external package and stays local; these cover the
3
- // `consult_outbox` rows that route through crtrd.
1
+ // Human-bridge and crouter ticket-store DTOs — the canvas-facing wire shapes
2
+ // for bridge work and ticket resolution through crtrd.
4
3
  export {};
@@ -9,7 +9,6 @@ export interface DeckSourceDTO {
9
9
  askedBy?: string;
10
10
  blockedSince?: IsoTime;
11
11
  nodeId?: string;
12
- visual?: 'humanloop.visual/v1';
13
12
  }
14
13
  export interface DeckTicketSummaryDTO {
15
14
  ticket_id: InboxTicketIdDTO;
@@ -82,6 +82,14 @@ export interface NodeWorktreeDTO {
82
82
  created: IsoTime;
83
83
  closed?: IsoTime;
84
84
  }
85
+ /** Immutable review-companion provenance and fork coordinates. Present only on
86
+ * a `review/companion` node spawned by the daemon for a human review. */
87
+ export interface NodeReviewBindingDTO {
88
+ review_id: string;
89
+ origin_node_id: string;
90
+ branch_file: string;
91
+ target_file: string;
92
+ }
85
93
  /** The full node view — summary ∪ identity extras ∪ edges ∪ paths. Returned by
86
94
  * `GET /v1/nodes/{id}` and by the create/lifecycle actions that yield a node. */
87
95
  export interface NodeDetailDTO extends NodeSummaryDTO {
@@ -111,6 +119,10 @@ export interface NodeDetailDTO extends NodeSummaryDTO {
111
119
  * crtr-owned transcript mirror). Consumed by `memory origin` to deref a doc
112
120
  * back to the conversation that authored it. */
113
121
  pi_session_file?: string | null;
122
+ /** Immutable review-companion provenance — present only on nodes of kind
123
+ * `review/companion`. Four fields capture the invocation-time fork
124
+ * coordinates without duplicating the full review record. */
125
+ review_binding?: NodeReviewBindingDTO | null;
114
126
  edges: NodeEdgesDTO;
115
127
  paths: NodePathsDTO;
116
128
  worktree?: NodeWorktreeDTO | null;
@@ -0,0 +1,137 @@
1
+ import type { IsoTime, NodeIdDTO } from './common.js';
2
+ export type ReviewCommentStatusDTO = 'open' | 'resolved' | 'deleted';
3
+ export type ReviewCommentDeliverDTO = 'wake' | 'quiet';
4
+ export type ReviewCommentAnchorStateDTO = 'live' | 'detached';
5
+ /** Caller-supplied source location for a comment or range remap. */
6
+ export interface ReviewCommentAnchorDTO {
7
+ line: number;
8
+ end_line: number;
9
+ col_start?: number;
10
+ col_end?: number;
11
+ quote?: string;
12
+ }
13
+ /** Daemon-derived current comment projection. */
14
+ export interface ReviewCommentDTO {
15
+ comment_id: string;
16
+ review_id: string;
17
+ status: ReviewCommentStatusDTO;
18
+ revision: number;
19
+ text: string;
20
+ anchor: ReviewCommentAnchorDTO;
21
+ anchor_state: ReviewCommentAnchorStateDTO;
22
+ anchor_line_text: string;
23
+ anchor_doc_hash: string;
24
+ author: {
25
+ kind: 'human' | 'node';
26
+ node_id?: NodeIdDTO;
27
+ };
28
+ updated_by: {
29
+ kind: 'human' | 'node';
30
+ node_id?: NodeIdDTO;
31
+ };
32
+ created_at: IsoTime;
33
+ updated_at: IsoTime;
34
+ resolved_at?: IsoTime;
35
+ deleted_at?: IsoTime;
36
+ created_seq: number;
37
+ }
38
+ /** Caller-supplied body for comment creation. `doc_hash` is supplied by a rendered terminal surface; agent CLI creation omits it and the daemon verifies its current coordinate base instead. */
39
+ export interface CreateReviewCommentRequest {
40
+ text: string;
41
+ anchor: ReviewCommentAnchorDTO;
42
+ doc_hash?: string;
43
+ actor_node_id?: NodeIdDTO | null;
44
+ deliver?: ReviewCommentDeliverDTO;
45
+ }
46
+ /** Caller-supplied body for comment text changes. */
47
+ export interface EditReviewCommentRequest {
48
+ text: string;
49
+ actor_node_id?: NodeIdDTO | null;
50
+ deliver?: ReviewCommentDeliverDTO;
51
+ if_revision?: number;
52
+ }
53
+ /** Caller-supplied body for comment state changes. */
54
+ export interface ReviewCommentActionRequest {
55
+ actor_node_id?: NodeIdDTO | null;
56
+ deliver?: ReviewCommentDeliverDTO;
57
+ if_revision?: number;
58
+ }
59
+ /** Daemon-derived best-effort companion-notification result. */
60
+ export interface ReviewCommentDeliveryDTO {
61
+ attempted: boolean;
62
+ target_node_id?: NodeIdDTO;
63
+ status: 'delivered' | 'skipped' | 'failed';
64
+ via?: 'engine' | 'inbox';
65
+ woke: boolean;
66
+ error?: string;
67
+ }
68
+ /** Daemon-derived result of one comment mutation. */
69
+ export interface ReviewCommentMutationDTO {
70
+ comment: ReviewCommentDTO;
71
+ changed: boolean;
72
+ delivery?: ReviewCommentDeliveryDTO;
73
+ }
74
+ /** Caller-supplied filter for a review's comment projection. */
75
+ export interface ListReviewCommentsQuery {
76
+ status?: ReviewCommentStatusDTO | 'all';
77
+ actor_node_id?: NodeIdDTO | null;
78
+ }
79
+ /** Daemon-derived comment list. */
80
+ export interface ReviewCommentListDTO {
81
+ review_id: string;
82
+ comments: ReviewCommentDTO[];
83
+ }
84
+ /** Daemon-derived one-comment projection and audit history. */
85
+ export interface ReviewCommentDetailDTO {
86
+ comment: ReviewCommentDTO;
87
+ events: ReviewCommentEventDTO[];
88
+ }
89
+ /** Caller-supplied cursor/limit for the append-only review audit. */
90
+ export interface ReadReviewCommentEventsQuery {
91
+ since_seq?: number;
92
+ limit?: number;
93
+ }
94
+ /** Daemon-derived page of append-only review comment events. */
95
+ export interface ReviewCommentEventsDTO {
96
+ review_id: string;
97
+ events: ReviewCommentEventDTO[];
98
+ next_since_seq: number | null;
99
+ }
100
+ /** Daemon-derived append-only comment audit event. */
101
+ export interface ReviewCommentEventDTO {
102
+ seq: number;
103
+ review_id: string;
104
+ comment_id: string;
105
+ kind: 'created' | 'edited' | 'resolved' | 'reopened' | 'deleted' | 'reanchored' | 'notified' | 'notify_failed';
106
+ state_change: boolean;
107
+ revision_after: number | null;
108
+ actor: {
109
+ kind: 'human' | 'node' | 'system';
110
+ node_id?: NodeIdDTO;
111
+ };
112
+ at: IsoTime;
113
+ operation_id: string;
114
+ payload?: unknown;
115
+ }
116
+ /** Caller-supplied replacement location for one nondeleted comment. */
117
+ export type ReviewCommentRangeEntryDTO = {
118
+ comment_id: string;
119
+ anchor: ReviewCommentAnchorDTO;
120
+ } | {
121
+ comment_id: string;
122
+ detached: true;
123
+ };
124
+ /** Caller-supplied atomic full-set range remap body. */
125
+ export interface ReviewCommentRangeBatchRequest {
126
+ from_doc_hash: string;
127
+ to_doc_hash: string;
128
+ entries: ReviewCommentRangeEntryDTO[];
129
+ }
130
+ /** Daemon-derived result of an atomic full-set range remap. */
131
+ export interface ReviewCommentRangeBatchResultDTO {
132
+ review_id: string;
133
+ anchor_base_sha256: string;
134
+ updated: number;
135
+ detached: number;
136
+ unchanged: number;
137
+ }
@@ -0,0 +1,5 @@
1
+ // Daemon-owned review comment DTOs. These are HTTP wire contracts only.
2
+ //
3
+ // PURITY: imports remain within `src/api/*`; daemon/store types do not cross
4
+ // this boundary.
5
+ export {};
@@ -0,0 +1,109 @@
1
+ import type { IsoTime, NodeIdDTO, NodeStatusDTO } from './common.js';
2
+ import type { FeedbackResultDTO } from './human.js';
3
+ export type ReviewOriginKindDTO = 'ticket' | 'inline';
4
+ /** `binding` is intentionally never exposed over the API. */
5
+ export type ReviewStateDTO = 'open' | 'approved' | 'canceled';
6
+ /** Caller-supplied body for `POST /v1/human/reviews`. */
7
+ export interface CreateReviewRequest {
8
+ /** Caller-selected review origin. */
9
+ origin_kind: ReviewOriginKindDTO;
10
+ /** Caller-selected node whose persisted session is forked. */
11
+ origin_node_id: NodeIdDTO;
12
+ /** Caller-selected absolute file path; the daemon canonicalizes and validates it. */
13
+ file: string;
14
+ /** Caller-minted invocation key; the daemon enforces its uniqueness. */
15
+ idempotency_key: string;
16
+ /** Caller-supplied ticket subtitle; required for ticket origins. */
17
+ subtitle?: string;
18
+ /** Caller-supplied ticket-only projection destination. */
19
+ output_path?: string;
20
+ }
21
+ /** Daemon-derived canonical review projection. */
22
+ export interface ReviewDTO {
23
+ /** Daemon-minted opaque review identity. */
24
+ review_id: string;
25
+ /** Daemon-recorded origin kind. */
26
+ origin_kind: ReviewOriginKindDTO;
27
+ /** Daemon-recorded originating node. */
28
+ origin_node_id: NodeIdDTO;
29
+ /** Daemon-recorded ticket bridge, when this review came from a ticket. */
30
+ bridge_node_id: NodeIdDTO | null;
31
+ /** Daemon-preallocated companion node. */
32
+ companion_node_id: NodeIdDTO;
33
+ /** Daemon-canonicalized reviewed file path. */
34
+ file: string;
35
+ /** Daemon lifecycle state; never `binding`. */
36
+ state: ReviewStateDTO;
37
+ /** Daemon capture timestamp. */
38
+ created: IsoTime;
39
+ /** Daemon open timestamp, after the companion binds. */
40
+ opened_at?: IsoTime;
41
+ /** Daemon source-read status at projection time. */
42
+ source_missing: boolean;
43
+ /** Daemon-owned current comment-coordinate source digest. */
44
+ anchor_base_sha256: string;
45
+ /** Daemon approval timestamp. */
46
+ approved_at?: IsoTime;
47
+ /** Daemon comparison of approval bytes to the invocation baseline. */
48
+ changed?: boolean;
49
+ /** Daemon snapshot count at approval. */
50
+ comments_total?: number;
51
+ /** Daemon unresolved-comment count at approval. */
52
+ comments_unresolved?: number;
53
+ /** Daemon cancellation timestamp. */
54
+ canceled_at?: IsoTime;
55
+ /** Daemon-recorded caller cancellation reason. */
56
+ cancel_reason?: string;
57
+ /** Daemon-recorded cancellation actor. */
58
+ cancel_actor?: string;
59
+ /** Daemon-owned immutable result projection path. */
60
+ result_path?: string;
61
+ /** Daemon-recorded approval delivery error, when delivery failed after commit. */
62
+ delivery_error?: string;
63
+ /** Daemon-recorded result projection error, when publication failed after commit. */
64
+ projection_error?: string;
65
+ }
66
+ /** Caller-supplied optional filters for `GET /v1/human/reviews`. */
67
+ export interface ListReviewsQuery {
68
+ state?: ReviewStateDTO;
69
+ origin_node_id?: NodeIdDTO;
70
+ file?: string;
71
+ }
72
+ /** Daemon-derived review list. */
73
+ export interface ReviewListDTO {
74
+ reviews: ReviewDTO[];
75
+ }
76
+ /** Daemon-derived result of opening an active review or acknowledging a terminal one. */
77
+ export type ReviewOpenResultDTO = {
78
+ review: ReviewDTO;
79
+ companion_node_id: NodeIdDTO;
80
+ companion_status: NodeStatusDTO;
81
+ disposition: 'open';
82
+ } | {
83
+ review: ReviewDTO;
84
+ disposition: 'terminal';
85
+ };
86
+ /** Daemon-derived result of terminal review approval. */
87
+ export interface ReviewSubmitResultDTO {
88
+ review: ReviewDTO;
89
+ /** Immutable approval result. */
90
+ result: FeedbackResultDTO;
91
+ outcome: 'settled' | 'already_settled';
92
+ }
93
+ /** Daemon-derived result of terminal review cancellation. */
94
+ export interface ReviewCancelResultDTO {
95
+ review: ReviewDTO;
96
+ outcome: 'settled' | 'already_settled';
97
+ }
98
+ /** Caller-supplied optional cancellation context. */
99
+ export interface CancelReviewRequest {
100
+ reason?: string;
101
+ actor?: string;
102
+ }
103
+ /** Daemon-derived coordinate base for the terminal review surface. */
104
+ export interface ReviewDocumentBaseDTO {
105
+ review_id: string;
106
+ anchor_base_sha256: string;
107
+ anchor_base_text: string;
108
+ file: string;
109
+ }
@@ -0,0 +1,5 @@
1
+ // Canonical daemon-owned review DTOs. These are HTTP wire contracts only.
2
+ //
3
+ // PURITY: imports remain within `src/api/*`; daemon/store types do not cross
4
+ // this boundary.
5
+ export {};
package/dist/index.d.ts CHANGED
@@ -22,3 +22,5 @@ export * from './dto/worktree.js';
22
22
  export * from './dto/human.js';
23
23
  export * from './dto/files.js';
24
24
  export * from './dto/inbox.js';
25
+ export * from './dto/reviews.js';
26
+ export * from './dto/review-comments.js';
package/dist/index.js CHANGED
@@ -23,3 +23,5 @@ export * from './dto/worktree.js';
23
23
  export * from './dto/human.js';
24
24
  export * from './dto/files.js';
25
25
  export * from './dto/inbox.js';
26
+ export * from './dto/reviews.js';
27
+ export * from './dto/review-comments.js';
package/dist/routes.d.ts CHANGED
@@ -48,11 +48,24 @@ export declare const routes: {
48
48
  readonly canvasRoster: () => string;
49
49
  readonly canvasPrune: () => string;
50
50
  readonly canvasRebuildIndex: () => string;
51
- readonly canvasConsults: () => string;
52
51
  readonly humanBridge: () => string;
53
- readonly humanDeliver: () => string;
54
- readonly humanConsult: () => string;
55
- readonly humanVisual: () => string;
52
+ readonly humanTicketResolve: (nodeId: string) => string;
53
+ readonly humanTicketCancel: (nodeId: string) => string;
54
+ readonly humanReviews: () => string;
55
+ readonly humanReview: (reviewId: string) => string;
56
+ readonly humanReviewByBridge: (bridgeNodeId: string) => string;
57
+ readonly humanReviewOpen: (reviewId: string) => string;
58
+ readonly humanReviewSubmit: (reviewId: string) => string;
59
+ readonly humanReviewCancel: (reviewId: string) => string;
60
+ readonly humanReviewDocument: (reviewId: string) => string;
61
+ readonly humanReviewComments: (reviewId: string) => string;
62
+ readonly humanReviewCommentEvents: (reviewId: string) => string;
63
+ readonly humanReviewCommentRanges: (reviewId: string) => string;
64
+ readonly humanComment: (commentId: string) => string;
65
+ readonly humanCommentEdit: (commentId: string) => string;
66
+ readonly humanCommentResolve: (commentId: string) => string;
67
+ readonly humanCommentReopen: (commentId: string) => string;
68
+ readonly humanCommentDelete: (commentId: string) => string;
56
69
  readonly humanInbox: () => string;
57
70
  readonly humanInboxTicket: (ticketId: string) => string;
58
71
  readonly humanInboxRespond: (ticketId: string) => string;
package/dist/routes.js CHANGED
@@ -70,12 +70,28 @@ export const routes = {
70
70
  canvasRoster: () => `${V}/canvas/roster`,
71
71
  canvasPrune: () => `${V}/canvas/prune`,
72
72
  canvasRebuildIndex: () => `${V}/canvas/rebuild-index`,
73
- canvasConsults: () => `${V}/canvas/consults`,
74
- // Human bridge + completion-handler forwarding (spec §6.5)
73
+ // Human bridge creation + the pinned ticket route table (design §"The `/v1`
74
+ // surface") every ticket route is addressed by node id only.
75
75
  humanBridge: () => `${V}/human/bridge`,
76
- humanDeliver: () => `${V}/human/deliver`,
77
- humanConsult: () => `${V}/human/consult`,
78
- humanVisual: () => `${V}/human/visual`,
76
+ humanTicketResolve: (nodeId) => `${V}/human/tickets/${nodeId}/resolve`,
77
+ humanTicketCancel: (nodeId) => `${V}/human/tickets/${nodeId}/cancel`,
78
+ // Daemon-owned document reviews and comments. All interpolated ids are
79
+ // guarded by `CrtrClient` before they reach these pure builders.
80
+ humanReviews: () => `${V}/human/reviews`,
81
+ humanReview: (reviewId) => `${V}/human/reviews/${reviewId}`,
82
+ humanReviewByBridge: (bridgeNodeId) => `${V}/human/reviews/by-bridge/${bridgeNodeId}`,
83
+ humanReviewOpen: (reviewId) => `${V}/human/reviews/${reviewId}/open`,
84
+ humanReviewSubmit: (reviewId) => `${V}/human/reviews/${reviewId}/submit`,
85
+ humanReviewCancel: (reviewId) => `${V}/human/reviews/${reviewId}/cancel`,
86
+ humanReviewDocument: (reviewId) => `${V}/human/reviews/${reviewId}/document`,
87
+ humanReviewComments: (reviewId) => `${V}/human/reviews/${reviewId}/comments`,
88
+ humanReviewCommentEvents: (reviewId) => `${V}/human/reviews/${reviewId}/comment-events`,
89
+ humanReviewCommentRanges: (reviewId) => `${V}/human/reviews/${reviewId}/comment-ranges`,
90
+ humanComment: (commentId) => `${V}/human/comments/${commentId}`,
91
+ humanCommentEdit: (commentId) => `${V}/human/comments/${commentId}/edit`,
92
+ humanCommentResolve: (commentId) => `${V}/human/comments/${commentId}/resolve`,
93
+ humanCommentReopen: (commentId) => `${V}/human/comments/${commentId}/reopen`,
94
+ humanCommentDelete: (commentId) => `${V}/human/comments/${commentId}/delete`,
79
95
  // Humanloop inbox (Northlight crouter-inbox v1, inbox-contract.md §A)
80
96
  humanInbox: () => `${V}/human/inbox`,
81
97
  humanInboxTicket: (ticketId) => `${V}/human/inbox/${ticketId}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter-api",
3
- "version": "0.3.171",
3
+ "version": "0.3.173",
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/index.js",