@north-light/crouter-api 0.3.255 → 0.3.256

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.
@@ -20,7 +20,7 @@ import type { CreateReviewCommentRequest, EditReviewCommentRequest, ListReviewCo
20
20
  import type { CancelInboxTicketRequest, CanceledTicketResultDTO, InboxListDTO, InboxPageDTO, InboxPageHistoryDTO, InboxPageResponseDTO, InboxTicketIdDTO, PageFeedbackResolutionDTO, PageResponsesDTO, PageTicketResultDTO, RespondInboxPageRequest } from './dto/inbox.js';
21
21
  import type { CreateHumanRequestDTO, CreateHumanRequestRequest, HumanRequestDTO, HumanRequestIdDTO, ReplaceHumanRequestRequest, RespondHumanRequestRequest, SettleHumanRequestRequest } from './dto/human-requests.js';
22
22
  import type { AttentionCountsDTO, AttentionDTO, DashboardDTO, DashboardQuery, HistoryGrepQuery, HistoryGrepResultDTO, HistoryReadQuery, HistoryReadResultDTO, HistorySearchQuery, HistorySearchResultDTO, PruneRequest, PruneResultDTO, RebuildIndexResultDTO, RosterDTO, SnapshotDTO } from './dto/canvas.js';
23
- import type { AbandonWorktreeRequest, AbandonWorktreeResultDTO, CloseWorktreeResultDTO } from './dto/worktree.js';
23
+ import type { AbandonWorktreeRequest, AbandonWorktreeResultDTO, CloseWorktreeResultDTO, QuarantinedWorktreeDTO } from './dto/worktree.js';
24
24
  import type { BrokerExtensionStateDTO, BrokerGeneratedNameRequest, BrokerGeneratedNameResultDTO, BrokerInboxCursorDirective, BrokerInboxCursorRequest, BrokerModelCommitRequest, BrokerModelCommitResultDTO, BrokerPersonaAckRequest, BrokerPersonaAckResultDTO, BrokerSessionBoundRequest, BrokerSessionBoundResultDTO, BrokerSettleDirective, BrokerSettleRequest } from './dto/broker-ops.js';
25
25
  export interface CrtrClientOptions {
26
26
  /** Unix socket path (default local transport). Exactly one of socketPath|baseUrl. */
@@ -55,6 +55,16 @@ export interface CrtrClientOptions {
55
55
  * a slow-but-valid cold start cannot pass the authoritative verifier while
56
56
  * this poll times out first. */
57
57
  coldStartPollWindowMs?: number;
58
+ /** Injected check for a STANDING reason the daemon will never come up — one
59
+ * that the poll window cannot outlast because nothing about it changes with
60
+ * time. Consulted on each `/healthz` poll; a returned string ends the wait
61
+ * immediately and becomes the error message.
62
+ *
63
+ * Without this the caller waits out the whole cold-start window to report
64
+ * "not reachable", even when the reason it is unreachable — and the repair
65
+ * for it — were both known before the first poll. Must be synchronous and
66
+ * cheap; it runs on every poll tick. */
67
+ coldStartAbort?: () => string | null;
58
68
  }
59
69
  export declare class CrtrClient {
60
70
  private readonly socketPath?;
@@ -65,6 +75,7 @@ export declare class CrtrClient {
65
75
  private readonly onColdSocket?;
66
76
  private readonly coldStartDiagnostic?;
67
77
  private readonly coldStartPollWindowMs;
78
+ private readonly coldStartAbort?;
68
79
  /** Guards against re-entering the autostart path more than once per client. */
69
80
  private coldStartAttempted;
70
81
  constructor(opts: CrtrClientOptions);
@@ -114,6 +125,7 @@ export declare class CrtrClient {
114
125
  * crtrd is the repo host (same principle as spawnChild's creation git). */
115
126
  closeWorktree(id: string): Promise<CloseWorktreeResultDTO>;
116
127
  abandonWorktree(id: string, req: AbandonWorktreeRequest): Promise<AbandonWorktreeResultDTO>;
128
+ listQuarantinedWorktrees(): Promise<QuarantinedWorktreeDTO[]>;
117
129
  subscribe(id: string, req: SubscribeRequest): Promise<SubscriptionDTO>;
118
130
  listFocuses(): Promise<FocusDTO[]>;
119
131
  focusOf(nodeId: string): Promise<FocusDTO | null>;
@@ -48,6 +48,7 @@ export class CrtrClient {
48
48
  onColdSocket;
49
49
  coldStartDiagnostic;
50
50
  coldStartPollWindowMs;
51
+ coldStartAbort;
51
52
  /** Guards against re-entering the autostart path more than once per client. */
52
53
  coldStartAttempted = false;
53
54
  constructor(opts) {
@@ -67,6 +68,8 @@ export class CrtrClient {
67
68
  this.onColdSocket = opts.onColdSocket;
68
69
  if (opts.coldStartDiagnostic !== undefined)
69
70
  this.coldStartDiagnostic = opts.coldStartDiagnostic;
71
+ if (opts.coldStartAbort !== undefined)
72
+ this.coldStartAbort = opts.coldStartAbort;
70
73
  this.coldStartPollWindowMs = opts.coldStartPollWindowMs ?? HEALTHZ_POLL_WINDOW_MS;
71
74
  }
72
75
  /** Construct a client bound to the default local socket with autostart on. Pass
@@ -179,6 +182,9 @@ export class CrtrClient {
179
182
  abandonWorktree(id, req) {
180
183
  return this.request('POST', routes.nodeWorktreeAbandon(this.nodePath(id)), req);
181
184
  }
185
+ listQuarantinedWorktrees() {
186
+ return this.request('GET', routes.quarantinedWorktrees());
187
+ }
182
188
  subscribe(id, req) {
183
189
  return this.request('POST', routes.nodeSubscriptions(this.nodePath(id)), req);
184
190
  }
@@ -745,6 +751,17 @@ export class CrtrClient {
745
751
  if (!this.isColdSocketError(err))
746
752
  throw toTransportApiError(err);
747
753
  }
754
+ // Waiting cannot clear a standing block, and the repair is already known.
755
+ let standingBlock = null;
756
+ try {
757
+ standingBlock = this.coldStartAbort?.() ?? null;
758
+ }
759
+ catch {
760
+ standingBlock = null;
761
+ }
762
+ if (standingBlock !== null) {
763
+ throw new ApiError(503, 'daemon_unavailable', `crtrd cannot start: ${standingBlock}`);
764
+ }
748
765
  if (Date.now() >= deadline) {
749
766
  const diagnostic = safeColdStartDiagnostic(this.coldStartDiagnostic);
750
767
  throw new ApiError(503, 'daemon_unavailable', coldStartTimeoutMessage(diagnostic));
@@ -14,6 +14,10 @@ export interface CloseWorktreeResultDTO {
14
14
  /** False while the local branch remains checked out by the deferred cleanup. */
15
15
  branch_deleted: boolean;
16
16
  branch_delete_error?: string;
17
+ /** Present ONLY when landing had to stash local changes in the base checkout
18
+ * and re-applying them conflicted: names the preserved stash and how to
19
+ * re-apply it. Its absence means nothing local was left over. */
20
+ base_checkout_stash?: string;
17
21
  }
18
22
  export interface AbandonWorktreeRequest {
19
23
  by: string;
@@ -25,3 +29,16 @@ export interface AbandonWorktreeResultDTO {
25
29
  worktree_path: string;
26
30
  branch_deleted: boolean;
27
31
  }
32
+ /** A daemon-cleanup refusal retained for human intervention. */
33
+ export interface QuarantinedWorktreeDTO {
34
+ node_id: string;
35
+ path: string;
36
+ branch: string;
37
+ repo_root: string;
38
+ reason: string;
39
+ detail?: string;
40
+ attempts: number;
41
+ last_attempt: string;
42
+ /** Bytes occupied by the checkout, or null when it is gone or unmeasurable. */
43
+ size_bytes: number | null;
44
+ }
@@ -40,6 +40,7 @@ export declare const routes: {
40
40
  readonly nodeConfig: (id: string) => string;
41
41
  readonly nodeWorktreeClose: (id: string) => string;
42
42
  readonly nodeWorktreeAbandon: (id: string) => string;
43
+ readonly quarantinedWorktrees: () => string;
43
44
  readonly nodeAttach: (id: string) => string;
44
45
  readonly focuses: () => string;
45
46
  readonly focusByNode: () => string;
@@ -58,6 +58,7 @@ export const routes = {
58
58
  nodeConfig: (id) => `${V}/nodes/${id}/config`,
59
59
  nodeWorktreeClose: (id) => `${V}/nodes/${id}/worktree/close`,
60
60
  nodeWorktreeAbandon: (id) => `${V}/nodes/${id}/worktree/abandon`,
61
+ quarantinedWorktrees: () => `${V}/worktrees/quarantined`,
61
62
  nodeAttach: (id) => `${V}/nodes/${id}/attach`,
62
63
  // Focuses (viewer registry — the canvas.db `focuses` table)
63
64
  focuses: () => `${V}/focuses`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter-api",
3
- "version": "0.3.255",
3
+ "version": "0.3.256",
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",