@orkestrel/probe 0.0.6 → 0.0.8

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.
@@ -202,6 +202,29 @@ export declare interface Inspection {
202
202
  readonly claim: Claim;
203
203
  }
204
204
 
205
+ /**
206
+ * Carries the bound a caller holds over one stage inspection.
207
+ *
208
+ * @remarks
209
+ * `LintStageInterface.inspect` is the only inspection in this package that reads the signal. Its
210
+ * wait is a foreign language server's silence, and abandoning that wait would leave the client
211
+ * holding a pending diagnostics request. The type and runtime stages accept no options and honor no
212
+ * cancellation: a coordinator abandons an overrunning one and replaces it, which is what `Probe`
213
+ * does when its own deadline expires.
214
+ *
215
+ * Supply the signal a coordinator already armed rather than minting a second bound here. A bound
216
+ * minted beside the coordinator's races it, and which one answers then depends on scheduling.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * const options: InspectionOptions = { signal: AbortSignal.timeout(30_000) }
221
+ * ```
222
+ */
223
+ export declare interface InspectionOptions {
224
+ /** Aborts the inspection's wait for the resident tool's answer. */
225
+ readonly signal: AbortSignal;
226
+ }
227
+
205
228
  /**
206
229
  * Reports whether a fault means the host refuses the name a caller supplied for a file to create.
207
230
  *
@@ -243,13 +266,22 @@ export declare function isRefusedName(file: string, error: unknown): boolean;
243
266
  * Inspects virtual documents through one resident Oxlint language server.
244
267
  *
245
268
  * @remarks
246
- * Construction starts the target workspace's Oxlint binary with its Language Server Protocol
247
- * mode. Each inspection opens the supplied text by URI, waits for published diagnostics, and
248
- * closes the document without writing it to disk.
269
+ * Construction starts the target workspace's Oxlint binary with its Language Server Protocol mode
270
+ * and hands the conversation to `@orkestrel/lsp`: `createStdioTransport` owns the child process and
271
+ * its bytes, and `createLSPClient` owns the framing, the request correlation, the capabilities this
272
+ * stage advertises, and the choice between pulled and pushed diagnostics. This stage owns the
273
+ * workspace, the candidate identity, and the projection from a diagnostic to an `Issue`.
274
+ *
275
+ * Each inspection opens the supplied text by URI, waits for the client's diagnostics, and closes the
276
+ * document without writing it to disk. The caller's own signal is what bounds that wait, so a server
277
+ * that admits a document and publishes nothing refuses the inspection when the caller's bound
278
+ * expires rather than holding it for the life of the process. This stage mints no bound of its own
279
+ * for the wait: a second one would race the caller's, and the answer would depend on scheduling.
249
280
  *
250
281
  * Teardown is bounded at both ends. Warming waits for the server's `initialize` response and the
251
- * ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so
252
- * `destroy` bounds each exchange and takes the ending back with a signal when the bound passes.
282
+ * ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so the
283
+ * client's deadline bounds each exchange and the transport's cooperative window takes the ending
284
+ * back with a signal when that window passes.
253
285
  *
254
286
  * The URI is the path the candidate declared, so the candidate receives exactly the rule set the
255
287
  * workspace's own lint gate applies to that path, including an override anchored to one directory,
@@ -262,11 +294,11 @@ export declare function isRefusedName(file: string, error: unknown): boolean;
262
294
  * @example
263
295
  * ```ts
264
296
  * const stage = new LintStage('/srv/checkout')
265
- * const check = await stage.inspect(subject)
297
+ * const check = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
266
298
  * await stage.destroy()
267
299
  * ```
268
300
  */
269
- export declare class LintStage implements StageInterface {
301
+ export declare class LintStage implements LintStageInterface {
270
302
  #private;
271
303
  /**
272
304
  * Starts warming the target workspace's Oxlint language server.
@@ -276,10 +308,42 @@ export declare class LintStage implements StageInterface {
276
308
  constructor(workspace?: string);
277
309
  get stage(): Stage_2;
278
310
  get progress(): number;
279
- inspect(subject: Case_2): Promise<Check_2>;
311
+ inspect(subject: Case_2, options?: InspectionOptions): Promise<Check_2>;
280
312
  destroy(): Promise<void>;
281
313
  }
282
314
 
315
+ /**
316
+ * Inspects one case under a bound the caller supplies.
317
+ *
318
+ * @remarks
319
+ * The lint stage carries a member the shared stage contract cannot. Its inspection waits for a
320
+ * foreign language server to publish, and only the caller knows how long that wait may run, so the
321
+ * bound belongs here rather than on `StageInterface`. The type and runtime stages read no signal
322
+ * and keep the shared one-argument `inspect`.
323
+ *
324
+ * `options` is optional because `StageInterface.inspect` accepts one argument and this contract
325
+ * extends it. An inspection that omits `options` is refused rather than served: a bound this stage
326
+ * minted for itself would race the coordinator's, and the client's own `timeout` covers the
327
+ * lifecycle exchanges alone.
328
+ *
329
+ * @example
330
+ * ```ts
331
+ * const check = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
332
+ * ```
333
+ */
334
+ export declare interface LintStageInterface extends StageInterface {
335
+ /**
336
+ * Inspects one case, under the bound the caller supplies.
337
+ *
338
+ * @param subject - The candidate drafts and test to inspect
339
+ * @param options - The bound this inspection waits under
340
+ * @returns One outcome for this stage
341
+ * @throws When the caller supplies no bound, when the resident language server cannot start, or
342
+ * when the stage has already been destroyed
343
+ */
344
+ inspect(subject: Case, options?: InspectionOptions): Promise<Check>;
345
+ }
346
+
283
347
  /**
284
348
  * Holds the listeners one emitter carried for a set of events at the moment it was captured.
285
349
  *
@@ -505,12 +569,18 @@ export declare interface OverlayInterface {
505
569
  * A containment walk and the write that follows it are separate calls, so a process that swaps the
506
570
  * final component between them decides where the bytes land. `writeFileSync` opens with the default
507
571
  * `w` flag, which follows a symbolic link at that component and creates the file when it is absent,
508
- * so the walk's reading does not bind the write. Opening `O_WRONLY | O_TRUNC | O_NOFOLLOW` moves
509
- * that decision into the call that writes: a link at the final component refuses the open, and the
572
+ * so the walk's reading does not bind the write. Opening `O_WRONLY | O_NOFOLLOW` moves that
573
+ * decision into the call that writes: a link at the final component refuses the open, and the
510
574
  * omitted `O_CREAT` fails `ENOENT` for a target that has gone since the walk saw it. This is the
511
575
  * mutating counterpart of the `wx` flag every create in this package uses. Which code the refusal
512
576
  * carries is the host's; Linux with Node v22.22.2 reported `ELOOP` on 2026-08-24.
513
577
  *
578
+ * Truncation runs through the held descriptor rather than through an `O_TRUNC` flag, so it reaches
579
+ * the file the open bound. A Windows host refuses the numeric `O_TRUNC` without `O_CREAT` outright:
580
+ * measured on 2026-08-26 on Windows 11 with Node v24.19.0 over NTFS, `openSync` reported `EINVAL`
581
+ * for `O_WRONLY | O_TRUNC` and for `O_RDWR | O_TRUNC` while `O_WRONLY` alone opened, and adding
582
+ * `O_CREAT` would trade that refusal for the create this function must never perform.
583
+ *
514
584
  * A directory component stays open, because Node exposes no descriptor-relative call to walk and
515
585
  * write through one set of descriptors. Where a host's Node build defines no `O_NOFOLLOW`, that flag
516
586
  * contributes nothing to the flag set and the final component is open on that host too.
@@ -531,20 +601,6 @@ export declare interface OverlayInterface {
531
601
  */
532
602
  export declare function overwriteFile(file: string, text: string): void;
533
603
 
534
- /**
535
- * Reads a JSON-RPC frame's declared byte length.
536
- *
537
- * @param header - The frame header text without its terminating empty line
538
- * @returns The non-negative content length, or `undefined` for an invalid header
539
- *
540
- * @example
541
- * ```ts
542
- * parseContentLength('Content-Length: 128') // 128
543
- * parseContentLength('Content-Type: application/json') // undefined
544
- * ```
545
- */
546
- export declare function parseContentLength(header: string): number | undefined;
547
-
548
604
  /**
549
605
  * Answers claims through resident TypeScript, Oxlint, and Vitest stages.
550
606
  *
@@ -202,6 +202,29 @@ export declare interface Inspection {
202
202
  readonly claim: Claim;
203
203
  }
204
204
 
205
+ /**
206
+ * Carries the bound a caller holds over one stage inspection.
207
+ *
208
+ * @remarks
209
+ * `LintStageInterface.inspect` is the only inspection in this package that reads the signal. Its
210
+ * wait is a foreign language server's silence, and abandoning that wait would leave the client
211
+ * holding a pending diagnostics request. The type and runtime stages accept no options and honor no
212
+ * cancellation: a coordinator abandons an overrunning one and replaces it, which is what `Probe`
213
+ * does when its own deadline expires.
214
+ *
215
+ * Supply the signal a coordinator already armed rather than minting a second bound here. A bound
216
+ * minted beside the coordinator's races it, and which one answers then depends on scheduling.
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * const options: InspectionOptions = { signal: AbortSignal.timeout(30_000) }
221
+ * ```
222
+ */
223
+ export declare interface InspectionOptions {
224
+ /** Aborts the inspection's wait for the resident tool's answer. */
225
+ readonly signal: AbortSignal;
226
+ }
227
+
205
228
  /**
206
229
  * Reports whether a fault means the host refuses the name a caller supplied for a file to create.
207
230
  *
@@ -243,13 +266,22 @@ export declare function isRefusedName(file: string, error: unknown): boolean;
243
266
  * Inspects virtual documents through one resident Oxlint language server.
244
267
  *
245
268
  * @remarks
246
- * Construction starts the target workspace's Oxlint binary with its Language Server Protocol
247
- * mode. Each inspection opens the supplied text by URI, waits for published diagnostics, and
248
- * closes the document without writing it to disk.
269
+ * Construction starts the target workspace's Oxlint binary with its Language Server Protocol mode
270
+ * and hands the conversation to `@orkestrel/lsp`: `createStdioTransport` owns the child process and
271
+ * its bytes, and `createLSPClient` owns the framing, the request correlation, the capabilities this
272
+ * stage advertises, and the choice between pulled and pushed diagnostics. This stage owns the
273
+ * workspace, the candidate identity, and the projection from a diagnostic to an `Issue`.
274
+ *
275
+ * Each inspection opens the supplied text by URI, waits for the client's diagnostics, and closes the
276
+ * document without writing it to disk. The caller's own signal is what bounds that wait, so a server
277
+ * that admits a document and publishes nothing refuses the inspection when the caller's bound
278
+ * expires rather than holding it for the life of the process. This stage mints no bound of its own
279
+ * for the wait: a second one would race the caller's, and the answer would depend on scheduling.
249
280
  *
250
281
  * Teardown is bounded at both ends. Warming waits for the server's `initialize` response and the
251
- * ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so
252
- * `destroy` bounds each exchange and takes the ending back with a signal when the bound passes.
282
+ * ending waits for its `shutdown` reply, and the protocol leaves both answers to the server, so the
283
+ * client's deadline bounds each exchange and the transport's cooperative window takes the ending
284
+ * back with a signal when that window passes.
253
285
  *
254
286
  * The URI is the path the candidate declared, so the candidate receives exactly the rule set the
255
287
  * workspace's own lint gate applies to that path, including an override anchored to one directory,
@@ -262,11 +294,11 @@ export declare function isRefusedName(file: string, error: unknown): boolean;
262
294
  * @example
263
295
  * ```ts
264
296
  * const stage = new LintStage('/srv/checkout')
265
- * const check = await stage.inspect(subject)
297
+ * const check = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
266
298
  * await stage.destroy()
267
299
  * ```
268
300
  */
269
- export declare class LintStage implements StageInterface {
301
+ export declare class LintStage implements LintStageInterface {
270
302
  #private;
271
303
  /**
272
304
  * Starts warming the target workspace's Oxlint language server.
@@ -276,10 +308,42 @@ export declare class LintStage implements StageInterface {
276
308
  constructor(workspace?: string);
277
309
  get stage(): Stage_2;
278
310
  get progress(): number;
279
- inspect(subject: Case_2): Promise<Check_2>;
311
+ inspect(subject: Case_2, options?: InspectionOptions): Promise<Check_2>;
280
312
  destroy(): Promise<void>;
281
313
  }
282
314
 
315
+ /**
316
+ * Inspects one case under a bound the caller supplies.
317
+ *
318
+ * @remarks
319
+ * The lint stage carries a member the shared stage contract cannot. Its inspection waits for a
320
+ * foreign language server to publish, and only the caller knows how long that wait may run, so the
321
+ * bound belongs here rather than on `StageInterface`. The type and runtime stages read no signal
322
+ * and keep the shared one-argument `inspect`.
323
+ *
324
+ * `options` is optional because `StageInterface.inspect` accepts one argument and this contract
325
+ * extends it. An inspection that omits `options` is refused rather than served: a bound this stage
326
+ * minted for itself would race the coordinator's, and the client's own `timeout` covers the
327
+ * lifecycle exchanges alone.
328
+ *
329
+ * @example
330
+ * ```ts
331
+ * const check = await stage.inspect(subject, { signal: AbortSignal.timeout(30_000) })
332
+ * ```
333
+ */
334
+ export declare interface LintStageInterface extends StageInterface {
335
+ /**
336
+ * Inspects one case, under the bound the caller supplies.
337
+ *
338
+ * @param subject - The candidate drafts and test to inspect
339
+ * @param options - The bound this inspection waits under
340
+ * @returns One outcome for this stage
341
+ * @throws When the caller supplies no bound, when the resident language server cannot start, or
342
+ * when the stage has already been destroyed
343
+ */
344
+ inspect(subject: Case, options?: InspectionOptions): Promise<Check>;
345
+ }
346
+
283
347
  /**
284
348
  * Holds the listeners one emitter carried for a set of events at the moment it was captured.
285
349
  *
@@ -505,12 +569,18 @@ export declare interface OverlayInterface {
505
569
  * A containment walk and the write that follows it are separate calls, so a process that swaps the
506
570
  * final component between them decides where the bytes land. `writeFileSync` opens with the default
507
571
  * `w` flag, which follows a symbolic link at that component and creates the file when it is absent,
508
- * so the walk's reading does not bind the write. Opening `O_WRONLY | O_TRUNC | O_NOFOLLOW` moves
509
- * that decision into the call that writes: a link at the final component refuses the open, and the
572
+ * so the walk's reading does not bind the write. Opening `O_WRONLY | O_NOFOLLOW` moves that
573
+ * decision into the call that writes: a link at the final component refuses the open, and the
510
574
  * omitted `O_CREAT` fails `ENOENT` for a target that has gone since the walk saw it. This is the
511
575
  * mutating counterpart of the `wx` flag every create in this package uses. Which code the refusal
512
576
  * carries is the host's; Linux with Node v22.22.2 reported `ELOOP` on 2026-08-24.
513
577
  *
578
+ * Truncation runs through the held descriptor rather than through an `O_TRUNC` flag, so it reaches
579
+ * the file the open bound. A Windows host refuses the numeric `O_TRUNC` without `O_CREAT` outright:
580
+ * measured on 2026-08-26 on Windows 11 with Node v24.19.0 over NTFS, `openSync` reported `EINVAL`
581
+ * for `O_WRONLY | O_TRUNC` and for `O_RDWR | O_TRUNC` while `O_WRONLY` alone opened, and adding
582
+ * `O_CREAT` would trade that refusal for the create this function must never perform.
583
+ *
514
584
  * A directory component stays open, because Node exposes no descriptor-relative call to walk and
515
585
  * write through one set of descriptors. Where a host's Node build defines no `O_NOFOLLOW`, that flag
516
586
  * contributes nothing to the flag set and the final component is open on that host too.
@@ -531,20 +601,6 @@ export declare interface OverlayInterface {
531
601
  */
532
602
  export declare function overwriteFile(file: string, text: string): void;
533
603
 
534
- /**
535
- * Reads a JSON-RPC frame's declared byte length.
536
- *
537
- * @param header - The frame header text without its terminating empty line
538
- * @returns The non-negative content length, or `undefined` for an invalid header
539
- *
540
- * @example
541
- * ```ts
542
- * parseContentLength('Content-Length: 128') // 128
543
- * parseContentLength('Content-Type: application/json') // undefined
544
- * ```
545
- */
546
- export declare function parseContentLength(header: string): number | undefined;
547
-
548
604
  /**
549
605
  * Answers claims through resident TypeScript, Oxlint, and Vitest stages.
550
606
  *