pi-ptc-subagents 0.1.1 → 0.1.3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,61 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.3] - 2026-09-23
9
+
10
+ ### Added
11
+
12
+ - **PTC rows show what the program is doing while it runs.** Two partial-state
13
+ visuals on the `ptc_run_code` / `ptc_workflow` row, both absent until now:
14
+ - a **shimmer** on the call row — same text, one character at a time bright,
15
+ the highlight sweeping at 150ms — so a running row is distinguishable from a
16
+ settled one in a column (ADR-0020);
17
+ - a **sub-call tree** under it: one row per binding call the program made,
18
+ live from the moment the call is made, with its own five-state status
19
+ (`running` / `ok` / `error` / `cancelled` / `rejected`) and duration,
20
+ visible without expanding the row and capped at 32 with a `+N more` tail
21
+ (ADR-0021). A failed run shows the failure text but no sub-call tree: the
22
+ tool throws (pi's convention), and pi builds that error result with an empty
23
+ `details`, so the tracked calls are dropped with it.
24
+
25
+ ### Changed
26
+
27
+ - **Build pipeline: minify + source-map exclusion.** `pnpm run build`
28
+ (`vp pack`) now produces minified `dist/*.js` (rolldown's built-in oxc
29
+ minifier; no new dependency). The npm tarball excludes `dist/**/*.map`
30
+ via the `package.json#files` whitelist — sourcemaps stay on disk for
31
+ local stack traces, but no longer ship. Tarball shrinks from 168.7 kB
32
+ packed / 548.6 kB unpacked (v0.1.2 baseline) to 40.5 kB / 113.6 kB
33
+ (−76% / −79%); `dist/*.js` total shrinks from 161,303 B to 53,959 B
34
+ (−66.5%). All 39 public exports retain their original names. ADR-0019.
35
+
36
+ ## [0.1.2] - 2026-09-23
37
+
38
+ ### Fixed
39
+
40
+ - **`pi.dispatch` is registered in production again.** The injection check compared the
41
+ binding-name array by reference against `DEFAULT_BINDING_NAMES`; production resolves
42
+ names through a `.filter()` that always returns a fresh array, so the comparison never
43
+ held and shipped sessions had no `pi.dispatch` at all. Injection now keys off a new
44
+ `includeDispatch` option (defaulting to "the caller passed no explicit `names`"), and
45
+ both shipped tools pass it explicitly. ADR-0016.
46
+ - **The dispatch concurrency cap honours `dispatchConcurrency` (default 8) and rejects
47
+ immediately instead of queueing.** The dispatcher used to read `maxParallelSubCalls`
48
+ (default 10) and FIFO-queue the overflow; per ADR-0016 §2 the N+1th concurrent
49
+ `pi.dispatch` now resolves at once with `{ status: "rejected", errorMessage:
50
+ "dispatch concurrency limit reached" }`. The cap applies to `pi.dispatch` only and
51
+ has its own counter; builtin binding fan-out keeps DSH's `maxParallelSubCalls` (10)
52
+ FIFO-queueing semantics (ADR-0004), so in-flight builtin calls never consume
53
+ dispatch slots.
54
+ - **The depth-limit rejection message is verbatim again.** The program receives
55
+ exactly `dispatch depth limit reached`, matching what the child's
56
+ `<pi-ptc-context>` hint promises — the diagnostic suffix is gone.
57
+ - **`maxDispatchDepth` bounds recursion again.** Every run reported depth 0 and
58
+ children never inherited it, so the depth check could never fire. `dispatch()` now
59
+ stamps `PI_PTC_DEPTH` on the child subprocess's environment, the extension
60
+ entrypoint reads it back, and `runPtcProgram()` accepts a `depth` baseline that
61
+ reaches the binding context. ADR-0016 Recursive section.
62
+
8
63
  ## [0.1.1] - 2026-09-23
9
64
 
10
65
  PTC runs inside one agent turn no longer pay a cold start each. Nothing changes in
package/dist/index.d.ts CHANGED
@@ -201,16 +201,24 @@ interface PtcConfig {
201
201
  maxMessageBytes: number;
202
202
  /** Admission control for simultaneously in-flight worker→host binding calls (ADR-0004). */
203
203
  maxPendingCalls: number;
204
- /** Concurrent binding dispatches; DSH's `maxParallelSubCalls` (ADR-0004 consequence).
205
- * Renamed in spirit by ADR-0016 section 2: the cap that really matters for
206
- * resource safety is the per-run `dispatchConcurrency` below. This field
207
- * is kept for backward compatibility (and for the in-process builtin
208
- * binding fan-out) but is no longer the authoritative limit on the
209
- * parallel binding `pi.dispatch`. */
204
+ /**
205
+ * Concurrent builtin binding dispatches; DSH's `maxParallelSubCalls`
206
+ * (ADR-0004 consequence), mirrored verbatim (10). The overflow
207
+ * FIFO-queues for a slot instead of failing. This is the authoritative
208
+ * cap for the builtin fan-out path — independent of
209
+ * `dispatchConcurrency`, with its own counter: neither cap throttles
210
+ * the other.
211
+ */
210
212
  maxParallelSubCalls: number;
211
- /** Per-run hard cap on concurrently in-flight `pi.dispatch(...)` calls.
212
- * Default 8, matches pi's `subagent` extension `MAX_PARALLEL_TASKS`.
213
- * ADR-0016 section 2. */
213
+ /**
214
+ * Per-run hard cap on concurrently in-flight `pi.dispatch(...)` calls,
215
+ * enforced by the dispatcher: the next concurrent call resolves
216
+ * immediately with `{ status: "rejected", errorMessage: "dispatch
217
+ * concurrency limit reached" }` — never queued, never spawned.
218
+ * Default 8, matches pi's `subagent` extension `MAX_PARALLEL_TASKS`.
219
+ * ADR-0016 section 2. Independent of `maxParallelSubCalls`: builtin
220
+ * calls never consume a dispatch slot and vice versa.
221
+ */
214
222
  dispatchConcurrency: number;
215
223
  /** Maximum recursion depth for `pi.dispatch`. The child PTC run spawned by
216
224
  * the (depth+1)-th dispatch is allowed only when childDepth <= maxDispatchDepth.
@@ -227,9 +235,10 @@ interface PtcConfig {
227
235
  /** V8 young-generation cap handed to `new Worker({ resourceLimits })` (F2). */
228
236
  maxYoungGenerationSizeMb: number;
229
237
  /**
230
- * Per-turn worker pool capacity (ADR-0017 §3). Decoupled from `maxParallelSubCalls`
231
- * because pool capacity is "resident workers" while `maxParallelSubCalls` is
232
- * "in-flight calls" — two different ceilings. Default 4.
238
+ * Per-turn worker pool capacity (ADR-0017 §3). Decoupled from
239
+ * `dispatchConcurrency` because pool capacity is "resident workers" while
240
+ * `dispatchConcurrency` is "in-flight calls" — two different ceilings.
241
+ * Default 4.
233
242
  */
234
243
  poolSize: number;
235
244
  /**
@@ -335,6 +344,27 @@ interface PtcErrorShape {
335
344
  message: string;
336
345
  stack?: string;
337
346
  }
347
+ /**
348
+ * One binding call the program made, as the dispatcher recorded it.
349
+ *
350
+ * Host-side only: this shape never crosses the wire — the existing `call` /
351
+ * `call-result` frames already carry every fact, and the host reconstructs the
352
+ * record at the seam where the facts are known (`SubCallTracker`,
353
+ * `src/runtime/sub-call-tracker.ts`). A snapshot reaches the renderer
354
+ * via `PtcToolDetails.subCalls`.
355
+ */
356
+ type SubCallStatus = "running" | "ok" | "error" | "cancelled" | "rejected";
357
+ interface SubCallRecord {
358
+ callId: number;
359
+ name: string;
360
+ args: unknown;
361
+ status: SubCallStatus;
362
+ startMs: number;
363
+ endMs?: number;
364
+ durationMs?: number;
365
+ resultSummary?: string;
366
+ errorMessage?: string;
367
+ }
338
368
  //#endregion
339
369
  //#region src/tools/text.d.ts
340
370
  /** Hard cap for one rendered line; longer lines are truncated with `…`. */
@@ -361,6 +391,15 @@ export declare function renderModelValue(value: PtcJsonValue): string;
361
391
  /** pi's built-in tools that can be exposed as bindings, in native order. */
362
392
  export declare const BUILTIN_BINDING_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
363
393
  type BuiltinBindingName = (typeof BUILTIN_BINDING_NAMES)[number];
394
+ /**
395
+ * Bindings exposed when the caller does not pass an explicit name list.
396
+ *
397
+ * `bash` is included on purpose: DSH's PTC preset still mounts `tool-bash`/`tool-pwsh`
398
+ * (R1 §2 — PTC mode hides the tools from the wire list and re-exposes the same registry
399
+ * as bindings), so a PTC program written against DSH may run shell commands. Leaving it
400
+ * out would silently shrink the surface relative to DSH. Callers that want a read-only
401
+ * PTC surface pass an explicit subset.
402
+ */
364
403
  export declare const DEFAULT_BINDING_NAMES: readonly BuiltinBindingName[];
365
404
  interface BindingContext {
366
405
  /** Aborted when the run is cancelled, times out, or settles. */
@@ -382,6 +421,16 @@ interface CreateBuiltinBindingsOptions {
382
421
  cwd: string;
383
422
  /** Subset of {@link BUILTIN_BINDING_NAMES}; defaults to all of them (bash included). */
384
423
  names?: readonly string[];
424
+ /**
425
+ * Whether the parallel binding `pi.dispatch` (ADR-0016) joins the table. Defaults to
426
+ * "did the caller curate the surface": `true` when `names` is omitted, `false` when an
427
+ * explicit list is passed (R3's read-only PTC surface pattern). Deciding on whether
428
+ * `names` was provided — not on array identity with {@link DEFAULT_BINDING_NAMES} —
429
+ * matters because production callers resolve names through a `.filter()` that always
430
+ * returns a fresh array. The two shipped tools pass `true` explicitly: the dispatch
431
+ * binding is part of every production surface.
432
+ */
433
+ includeDispatch?: boolean;
385
434
  }
386
435
  /**
387
436
  * Build the binding table for one run.
@@ -483,6 +532,14 @@ interface RunPtcProgramOptions {
483
532
  config?: Partial<PtcConfig>;
484
533
  /** Cancels the run; the worker gets a cooperative cancel window before termination. */
485
534
  signal?: AbortSignal;
535
+ /**
536
+ * Depth of this run in the `pi.dispatch` recursion chain (ADR-0016 Recursive section):
537
+ * 0 for the parent turn's run, 1+ for a run inside a child spawned by `pi.dispatch`.
538
+ * Handed to the binding context so the dispatch binding can bound recursion. The
539
+ * extension entrypoint derives it from `PI_PTC_DEPTH`; direct library use defaults
540
+ * to 0.
541
+ */
542
+ depth?: number;
486
543
  /** Identifier carried to the worker; generated when omitted. */
487
544
  runId?: string;
488
545
  /**
@@ -493,6 +550,18 @@ interface RunPtcProgramOptions {
493
550
  * `kind: workerExit`.
494
551
  */
495
552
  pool?: WorkerPool;
553
+ /**
554
+ * Called every time a sub-call starts or ends, so the caller can push a live partial result
555
+ * and have the tree visible while the run is in flight (ADR-0021 §4). Never called after the
556
+ * run settles — `finish` owns the terminal snapshot. Absent means "no live updates wanted"
557
+ * (direct library use, tests that only assert the terminal outcome).
558
+ *
559
+ * The argument is a **thunk**, not the snapshot itself: a wide `Promise.all` produces an
560
+ * event per call, and `snapshot()` copies every record. Building it eagerly would make N
561
+ * sequential calls cost O(N²) copies for pushes that the caller's throttle mostly drops.
562
+ * Call it only when a push is actually due.
563
+ */
564
+ onSubCallChange?: (snapshot: () => readonly SubCallRecord[]) => void;
496
565
  }
497
566
  /**
498
567
  * One image hoisted out of a successful binding result (DSH parity — see ADR-0014,
@@ -532,6 +601,15 @@ interface PtcRunOutcome {
532
601
  images?: PtcImage[];
533
602
  /** Failure details; absent on success. */
534
603
  error?: PtcErrorShape;
604
+ /**
605
+ * One record per binding call the program made (ADR-0021).
606
+ *
607
+ * Present only when the dispatcher tracked sub-calls for the surface in question (always,
608
+ * post-ADR-0021 — the dispatcher wires `SubCallTracker` for every run). Order is host-side
609
+ * dispatch order; the renderer reads it as a point-in-time snapshot. Absent for runs that settled
610
+ * before the tracker was constructed (the pre-`Promise` abort and pool-acquire-failed paths).
611
+ */
612
+ subCalls?: readonly SubCallRecord[];
535
613
  }
536
614
  /**
537
615
  * Run one PTC program in a fresh worker and resolve with its outcome.