pi-ptc-subagents 1.1.1 → 1.2.1

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,143 @@ 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
+ ## [Unreleased]
9
+
10
+ ## [1.2.1] - 2026-09-30
11
+
12
+ ### Fixed
13
+
14
+ - **The `ptc_subagent` tests no longer depend on a pi agent being registered.**
15
+ Five tests reached for pi's `__smoke_echo` agent, which does not resolve on every pi build,
16
+ so the suite was green on one platform and red on the release runner. The fixture is now
17
+ written by the test into `<cwd>/.pi/agents`, the path the agent resolver actually reads at
18
+ project scope, and every dispatch asks for project scope explicitly rather than inheriting
19
+ the `user` default, which points at the real `~/.pi`. Verified with an empty `HOME`: the whole
20
+ suite is green with no ambient agent state at all.
21
+
22
+ No product code changed in this release.
23
+
24
+ ## [1.2.0] - 2026-09-30
25
+
26
+ ### Added
27
+
28
+ - **The surface default is detected from the pi that loaded us (ADR-0026).** With no
29
+ `surfaceMode` set, a pi that ships its own `codemode` resolves to `subagents` and a pi that
30
+ does not resolves to `full`. Setting the key always wins, and a probe that cannot answer
31
+ falls back to `full` rather than guessing.
32
+
33
+ This is the one behaviour change that is not invisible on upgrade: on pi 0.99.1 or newer, a
34
+ user who has never set `surfaceMode` moves from `full` to `subagents`. `codemode` ships
35
+ inactive (`defaultActive: false`), so such a session has a subagent front and no active
36
+ orchestrator until codemode is added to the tool list -- the startup warning says so. Set
37
+ `{ "surfaceMode": "full" }` to keep today's tools.
38
+
39
+ Detection is a filesystem probe over `process.argv[1]`, because pi's own tool listing is
40
+ unavailable at factory time: `getAllTools()` is a `notInitialized` stub until `bindCore`
41
+ runs, and a throwing factory makes the extension fail to load rather than return an empty
42
+ list.
43
+
44
+ A detection the user cannot see is the one failure this design has, so the outcome is
45
+ reported: at session start, through the TUI notification channel, a session with no
46
+ `surfaceMode` set is told how the probe came out whenever it could not answer, and which
47
+ surface the default therefore is. The expected case — a pi that ships `codemode`, detected as
48
+ `subagents` — stays silent. A second notice covers the case the probe structurally cannot
49
+ see: it walks the filesystem, so under `--no-extensions` or `--exclude-tools codemode` it
50
+ answers `present` for a tool the session does not have. `session_start` cross-checks the
51
+ probe against pi's own `getAllTools()` and reports a disagreement in either direction.
52
+
53
+ Both notices are `ui.notify`, which is TUI-only — and that gap is **new here**, not inherited:
54
+ measured, three `--print` runs that each emit one produced 0 bytes on stdout and 0 on
55
+ stderr. The README is the only channel on which a `--print` user learns why they got the
56
+ surface they got. What is established is that the outcome is issued through the documented
57
+ TUI channel; no test observes either notice end to end through a real pi TUI.
58
+
59
+ - **The model-facing surface is now a setting, and a subagent can be started
60
+ without writing a program (ADR-0025).** A new `surfaceMode` key in
61
+ `~/.pi/agent/ptc.json` decides what this extension registers: `full`
62
+ (today's behaviour, and the detected default on a pi without `codemode`)
63
+ registers `ptc_run_code`, `ptc_workflow` and the `ptc_task_*` trio;
64
+ `subagents` registers a new top-level `ptc_subagent`
65
+ plus the `ptc_task_*` trio and leaves orchestration to pi's own `codemode`;
66
+ `off` registers nothing at all, so the session is stock pi. The new tool takes
67
+ the same arguments as the `pi.dispatch` binding and calls the same dispatcher,
68
+ so depth, concurrency and the background task lifecycle behave identically and
69
+ a task spawned through it is listable with `ptc_task_list`.
70
+
71
+ Motivation, measured rather than assumed: pi 0.99.1 ships its own programmable
72
+ tool calling as the built-in `codemode`, which is stronger than `ptc_run_code` at
73
+ isolation and tool discovery but cannot spawn a process at all. With both
74
+ installed the model is taught two programming models per request
75
+ (`docs/research/codemode-vs-ptc-capability-20260930.md`).
76
+
77
+ - **The PTC tool descriptions now declare what a binding call resolves to
78
+ (ADR-0024).** `ptc_run_code` and `ptc_workflow` carry one shared binding
79
+ contract: a binding result is `{ content, details }`, `content` is an array of
80
+ content blocks (the text of a text-file result is `result.content[0].text`),
81
+ `details` is an object or `null`, and there is no `files` / `output` /
82
+ `matches` / `entries` field to read — `bash`, `grep`, `find` and `ls` return one text block
83
+ of newline-separated rows that the program splits itself. A `builtin binding`
84
+ that fails rejects with `ToolCallError`; `pi.dispatch` resolves to a
85
+ `DispatchResult` with `text` and `status` and no `content`.
86
+
87
+ Model-facing only: the wire, the worker and every existing program are
88
+ unchanged. Field report before: a pty-driven run of the real TUI with PTC mode
89
+ on produced 31 program crashes across 16 runs, the largest error class being the
90
+ model treating a binding result as a string or as an object with a `files`
91
+ field — neither is ever true, and nothing said so
92
+ (`docs/research/ptc-binding-contract-measurement-20260930.md`).
93
+
94
+ Re-measured after the change, same harness and tasks: **0 of those three crash
95
+ classes in 16 runs**, the correct `result.content[0].text` access in 16 of 16,
96
+ and the context median for a PTC run down from 36,669 to 8,360 with median
97
+ turns from 8 to 2. Exact-match rate is not claimed to have improved — it moved
98
+ 10/16 to 11/16 while the control arm moved 15/16 to 13/16, which is this
99
+ harness's noise floor
100
+ (`docs/research/ptc-binding-contract-re-measurement-20260930.md`).
101
+
102
+ ### Changed
103
+
104
+ - **The dispatch concurrency cap is one counter per session, not one per run.** The acquire
105
+ moved out of the dispatcher and into `dispatch()`, so a single `DispatchSlotCounter` now
106
+ serves every front: concurrent programs in the same session, the `ptc_subagent` tool, and
107
+ background children. The value is still `PtcConfig.dispatchConcurrency` (default 8) and the
108
+ refusal shape is unchanged; what changed is whose calls the cap counts.
109
+
110
+ This reduces effective concurrency in two measurable ways, and neither is a rounding
111
+ difference — 24 concurrent foreground calls against a real fake-`pi` spawn:
112
+
113
+ - two concurrent programs that could each have 8 in flight now share 8 (16 spawned -> 8);
114
+ - a program sharing a session with 8 live background children can now be refused **every**
115
+ foreground slot (8 foreground spawned -> 0). The refusal is a hard reject with no queue, so
116
+ an over-cap call is not parked behind a long-running child.
117
+
118
+ A single program on its own is unchanged (8 of 24, before and after), which is why the
119
+ change passed three review rounds. ADR-0016 §2 and ADR-0022 §9 are amended; the depth cap is
120
+ not.
121
+
122
+ The knob is now live rather than dead: the live control is
123
+ `createBackgroundTaskRuntime({ concurrency })`, which sizes the session counter from
124
+ `PtcConfig.dispatchConcurrency`. Passing `dispatchConcurrency` through
125
+ `runPtcProgram({ config })` no longer sizes the cap a pi session uses (measured: 2
126
+ configured, 8 dispatched).
127
+
128
+ ### Fixed
129
+
130
+ - **A background task that produced no answer is no longer reported as a
131
+ success (#70, field report).** A child that hits a rate limit or a model
132
+ error still exits 0: pi writes the reason onto the assistant `message_end`
133
+ as `stopReason: "error"`, retries, and closes clean. The background pump
134
+ read the exit code alone, so such a task was recorded `succeeded` and the
135
+ model was told it had worked — while `ptc_task_output` answered "(no output
136
+ yet; task X is succeeded)". `succeeded` now requires the child to exit 0
137
+ **and** to have produced assistant text, which is the rule
138
+ `decideCloseOutcome` already applied to the foreground path; one failure now
139
+ has one verdict and one sentence in both paths. A failing `resolve-exit`
140
+ writes `errorMessage`, and the child's own `stopReason: "error"` text is
141
+ carried onto the record so the model is told _why_, not only _that_
142
+ (ADR-0022 §2, amended). A non-zero exit is still left unlabelled and a model
143
+ stop still resolves `canceled` — neither is relabelled by this change.
144
+
8
145
  ## [1.1.1] - 2026-09-30
9
146
 
10
147
  ### Fixed
package/README.md CHANGED
@@ -74,10 +74,27 @@ const [read, scoutA, scoutB] = await Promise.all([
74
74
 
75
75
  **Bounded.** Three knobs keep fan-out from running away:
76
76
 
77
- - `PtcConfig.dispatchConcurrency` (default **8**) — hard cap on concurrently in-flight `pi.dispatch` calls per run. The N+1th concurrent call resolves immediately with `{ status: "rejected", errorMessage: "dispatch concurrency limit reached" }` instead of queuing or spawning.
77
+ - `PtcConfig.dispatchConcurrency` (default **8**) — hard cap on concurrently in-flight dispatch **in one pi session**. It is one counter, not one per run: foreground `pi.dispatch`, the top-level `ptc_subagent` front, and live background children all spend it, and a background child holds its slot for its whole lifetime. The N+1th concurrent call resolves immediately with `{ status: "rejected", errorMessage: "dispatch concurrency limit reached" }` instead of queuing or spawning — so a call over the cap is not made to wait for a slot to come back.
78
78
  - `PtcConfig.maxDispatchDepth` (default **3**) — recursion bound. The child subprocess loads pi-ptc too, so it can write its own PTC programs and call `pi.dispatch` itself; the `childDepth = parentDepth + 1` is rejected when it would exceed `maxDispatchDepth`. The child sees a `<pi-ptc-context depth="N" max-depth="M">…</pi-ptc-context>` hint appended to its system prompt so it can budget its recursion.
79
79
  - `signal` — when the parent run is cancelled (deadline, abort, user Esc), every in-flight child receives `SIGTERM` followed by `SIGKILL` after a 5-second grace window, the same shape as pi's `examples/extensions/subagent/index.ts` reference.
80
80
 
81
+ **What the concurrency cap now governs, and which knob is live.** The cap is **one counter per pi
82
+ session** ([ADR-0016](./docs/adr/0016-ptc-dispatch-binding.md) §2 as amended,
83
+ [ADR-0022](./docs/adr/0022-background-dispatch.md) §9), acquired inside `dispatch()` so a single
84
+ owner gates every front. Two consequences are worth stating plainly, because both were measured and
85
+ neither is a rounding difference: two programs running concurrently in one session now share 8
86
+ rather than 8 each, and a program sharing a session with eight live background children can be
87
+ refused **every** foreground slot. The live control is `createBackgroundTaskRuntime({ concurrency })`,
88
+ the call that builds that session counter, and the value it is given is `PtcConfig.dispatchConcurrency`.
89
+ It is not a background-only knob: changing it changes how many foreground children a whole session
90
+ can have in flight.
91
+
92
+ The `dispatchConcurrency` a caller passes to `runPtcProgram({ config })` sizes the
93
+ dispatcher's own per-run counter, and that counter is only reached when no session counter is
94
+ supplied (`dispatcher.ts` hands the binding `options.dispatchDeps?.slots ?? dispatchSlots`). In a
95
+ pi session a session counter always is, so the per-run one is not what enforces the cap you are
96
+ looking at.
97
+
81
98
  **Opt out.** Pass an explicit binding subset to `createBuiltinBindings` to opt out — the parallel binding is mixed in only when the caller accepts the default set:
82
99
 
83
100
  ```ts
@@ -111,7 +128,7 @@ A detached pump drives the task's lifecycle (`running` -> `succeeded` / `failed`
111
128
  - `ptc_task_output({ taskId, sinceBytes? })` — read a task's captured output, tail-truncated to pi's 50 KB / 2000-line contract (ADR-0015).
112
129
  - `ptc_task_stop({ taskId, reason? })` — ask a running task to stop.
113
130
 
114
- Background tasks count against the same `dispatchConcurrency` (default 8) for their whole lifetime and share the `maxDispatchDepth` (default 3) recursion bound. A pre-spawn refusal (depth or concurrency cap, unknown agent) still comes back as the familiar `DispatchResult` with `status: "rejected"`. Full guide: [`docs/usage/bgdispatch.md`](./docs/usage/bgdispatch.md).
131
+ Background tasks count against the same `dispatchConcurrency` (default 8) for their whole lifetime and share the `maxDispatchDepth` (default 3) recursion bound — and since the gate moved into `dispatch()` that cap is the **one session counter** the foreground path uses too, not a second one held beside it. A session running eight long background children therefore has no foreground dispatch headroom left, and a foreground call over the cap is refused outright rather than queued behind them. A pre-spawn refusal (depth or concurrency cap, unknown agent) still comes back as the familiar `DispatchResult` with `status: "rejected"`. Full guide: [`docs/usage/bgdispatch.md`](./docs/usage/bgdispatch.md).
115
132
 
116
133
  ## TUI rendering
117
134
 
@@ -183,10 +200,62 @@ the session. The mode's rationale and rejected alternatives are in [ADR-0010](./
183
200
  { "defaultMode": false }
184
201
  ```
185
202
 
203
+ **Choosing the surface.** `defaultMode` decides whether the session _enters_ PTC mode; `surfaceMode`
204
+ decides which model-facing tools this package registers at all. It is read once, at startup, so a
205
+ surface change needs a new session ([ADR-0025](./docs/adr/0025-extension-surface-is-a-setting.md)):
206
+
207
+ ```jsonc
208
+ // ~/.pi/agent/ptc.json
209
+ { "surfaceMode": "subagents" }
210
+ ```
211
+
212
+ - `off` — a stock pi session: no tool, no `/ptc` command, no briefing.
213
+ - `subagents` — `ptc_subagent` plus the three `ptc_task_*` tools, with pi's own `codemode`
214
+ doing the orchestration; warns at startup when `codemode` is not in the active tool set.
215
+ - `full` — today's set: `ptc_run_code` / `ptc_workflow` plus the three `ptc_task_*` tools.
216
+
217
+ **The default is detected, and it is not `full` everywhere.** With no `surfaceMode` key, a pi that
218
+ ships its own `codemode` resolves to `subagents` and a pi that does not resolves to `full`
219
+ ([ADR-0026](./docs/adr/0026-surface-default-is-detected.md)). Setting the key always wins. A probe
220
+ that cannot answer falls back to `full` — the safe direction, since `subagents` as a failure mode
221
+ would take away the orchestration tool the session was relying on.
222
+
223
+ > Upgrading onto pi 0.99.1 or newer without setting the key moves you to `subagents`. `codemode`
224
+ > ships **inactive** (`defaultActive: false`), so until you add it to your tool list you get a
225
+ > subagent front with no orchestrator, and the startup warning says so. If you would rather keep
226
+ > today's tools, set `{ "surfaceMode": "full" }`.
227
+
228
+ No file, or a value outside that set, falls back to the detected default and says so at startup
229
+ rather than half-applying: which tools exist is not something to change on a guess.
230
+
231
+ **A detection you cannot see is the failure this design has**, so the result is reported. With no
232
+ `surfaceMode` key, the outcome is issued through the TUI notification channel at session start —
233
+ how the probe came out and which surface the default therefore is — but only when the probe could
234
+ not answer. A pi that ships `codemode` and is detected as `subagents` is the expected case and says
235
+ nothing. A second notice is issued when the probe and pi's own tool registry disagree, which is the
236
+ case the probe structurally cannot see: it walks the filesystem, so under `--no-extensions` or
237
+ `--exclude-tools codemode` it answers `present` for a tool this session does not have (and the
238
+ mirror: a restructured `dist` answers `not-found` for one pi plainly registers). What is **not**
239
+ established is that either line actually paints in a real pi TUI: a pty capture at review time
240
+ showed neither the notice nor a control marker, and a TUI quits on stdin EOF before a toast
241
+ renders, so that is an unmeasured end to end rather than a broken one. No test in this repository
242
+ observes a notice through a real TUI. If you are relying on the notice rather than on your own
243
+ `surfaceMode` key, verify it once.
244
+
245
+ **On a `--print` session, none of it prints.** `ui.notify` is the TUI channel; measured across
246
+ three `--print` runs that each emit one of these notices, stdout and stderr received **0 bytes**
247
+ each. That makes this page the only channel on which a `--print` user learns why they got the
248
+ surface they got — ADR-0025's decision-4 warning shares the gap, and there the answer is the same
249
+ one line of JSON: set `surfaceMode` yourself and the detection no longer matters.
250
+
186
251
  **Where it does not run.** Print / JSON / RPC sessions are left exactly as launched, and so is a
187
252
  session started with an explicit tool restriction (`--tools`, `--exclude-tools`,
188
- `--no-builtin-tools`) — the extension does not override what you asked for. If another extension
189
- changes the tool set while the mode is on, the mode yields and tells you.
253
+ `--no-builtin-tools`, `--no-extensions`) — the extension does not override what you asked for.
254
+ `--no-extensions` is the one flag in that list that produces a `subagents` surface with **no
255
+ orchestrator at all**: pi's own `codemode` is a built-in extension, so turning extensions off does
256
+ not remove the probe's answer (`present`), and the model is left with `ptc_subagent` and nothing to
257
+ compose with. If that is the session you want, set `"surfaceMode": "full"` in `ptc.json` yourself.
258
+ If another extension changes the tool set while the mode is on, the mode yields and tells you.
190
259
 
191
260
  **The important consequence:** in a TUI session, bindings come from the loadout recorded _before_
192
261
  the mode narrowed it. That is what keeps `tools.read(…)` working — and it is why a `--tools`
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ExtensionAPI, Skill, truncateTail } from "@earendil-works/pi-coding-agent";
2
+ import "typebox";
2
3
  import "@earendil-works/pi-ai";
3
4
  import { MessagePort, Worker } from "node:worker_threads";
4
5
  //#region src/runtime/ulid.d.ts
@@ -271,6 +272,7 @@ type TaskCommand = {
271
272
  outputRef?: string;
272
273
  outputBytes?: number;
273
274
  outputPreview?: string;
275
+ childError?: string;
274
276
  };
275
277
  /** Outcome of one successful command: the persisted record, emitted events, and cursor. */
276
278
  interface TransitionResult {
@@ -362,10 +364,11 @@ declare class DispatchSlotCounter {
362
364
  release(holder?: string): void;
363
365
  }
364
366
  /**
365
- * Injected dependencies for the background branch. The foreground path ignores this object
366
- * entirely (it uses the module-level {@link DISPATCH_LIFECYCLE}); every field is optional so
367
- * existing zero-argument call sites keep working. Tests pass an in-memory registry and a
368
- * mock lifecycle so no real `pi` process is ever spawned.
367
+ * Injected dependencies. The background branch uses this object for everything; the foreground
368
+ * branch uses `slots` (the one cap both fronts share since ADR-0026 round 3) and
369
+ * `lifecycle`. Every field is optional so existing zero-argument call sites keep working, and
370
+ * both branches fall back to the module-level {@link DISPATCH_LIFECYCLE}. Tests pass an
371
+ * in-memory registry and a mock lifecycle so no real `pi` process is ever spawned.
369
372
  */
370
373
  interface DispatchDeps {
371
374
  /** Session-level TaskRegistry (ADR-0022 §3). Defaults to a lazy in-memory registry. */
@@ -544,6 +547,53 @@ interface DefaultModeConfig {
544
547
  * on** — the caller should surface the problem rather than silently changing behavior.
545
548
  */
546
549
  export declare function readDefaultModeConfig(agentDir: string): DefaultModeConfig;
550
+ /**
551
+ * Which model-facing tools this package registers, independent of PTC mode (which decides
552
+ * which registered tools are *active*). Read from the same agent-dir file as
553
+ * {@link readDefaultModeConfig}, beside the `defaultMode` key. ADR-0025.
554
+ *
555
+ * The order below is the order of increasing responsibility: `off` hands the whole
556
+ * orchestration question back to pi, `subagents` keeps only the subagent face and lets pi's
557
+ * `codemode` orchestrate, `full` keeps today's set.
558
+ */
559
+ declare const SURFACE_MODES: readonly ["off", "subagents", "full"];
560
+ type SurfaceMode = (typeof SURFACE_MODES)[number];
561
+ interface CodemodePresence {
562
+ /** Whether the directory was found. */
563
+ present: boolean;
564
+ /** How the answer was reached, so a test can tell a measured yes from a failed probe. */
565
+ how: "found" | "not-found" | "no-entry" | "unresolvable-entry";
566
+ }
567
+ /** Result of reading the surface mode, with enough detail to warn about a broken file. */
568
+ interface SurfaceModeConfig {
569
+ surfaceMode: SurfaceMode;
570
+ source: "file" | "default" | "invalid";
571
+ error?: string;
572
+ /**
573
+ * What the probe found, on the paths where the surface was NOT decided by the file. Absent
574
+ * when the user set the key: that call never consults the probe (see
575
+ * {@link readSurfaceModeConfig}), so there is nothing to report.
576
+ */
577
+ codemode?: CodemodePresence;
578
+ }
579
+ /**
580
+ * Read `surfaceMode` from the agent-dir config file.
581
+ *
582
+ * A pure function over the filesystem, shaped like {@link readDefaultModeConfig} on purpose:
583
+ * an absent file, an absent key, unparseable JSON, a non-object, a wrong-typed value and an
584
+ * out-of-set value all resolve to the detected default rather than a hardcoded one, and every
585
+ * malformed shape additionally reports `invalid` with a reason. A malformed setting must never
586
+ * half-apply - which tools exist is not something to change on a guess.
587
+ *
588
+ * The `presence` argument is a parameter rather than a hidden call, so a test can state the pi it
589
+ * is reasoning about instead of depending on the machine it runs on. Omit it and the real probe
590
+ * answers, but only on a path that actually needs the answer: it is resolved inside the
591
+ * fallback branches rather than in a default parameter, because a default parameter is evaluated
592
+ * on EVERY call -- including the ones an explicit `surfaceMode` key short-circuits, where the
593
+ * user paid a `realpathSync` plus up to three `statSync` to set one line of JSON and get a
594
+ * constant.
595
+ */
596
+ export declare function readSurfaceModeConfig(agentDir: string, presence?: CodemodePresence): SurfaceModeConfig;
547
597
  /** Why the mode declined to turn on. Surfaced in the entry notification / debug logs. */
548
598
  type ModeBlockReason = "not-tui" | "config-off" | "tools-unavailable" | "restricted-session";
549
599
  /** Either the loadout to apply, or the reason the mode stayed off. */
@@ -689,13 +739,26 @@ interface PtcConfig {
689
739
  */
690
740
  maxParallelSubCalls: number;
691
741
  /**
692
- * Per-run hard cap on concurrently in-flight `pi.dispatch(...)` calls,
693
- * enforced by the dispatcher: the next concurrent call resolves
694
- * immediately with `{ status: "rejected", errorMessage: "dispatch
695
- * concurrency limit reached" }` — never queued, never spawned.
742
+ * Hard cap on concurrently in-flight dispatch in ONE pi session, not
743
+ * per run. Enforced inside `dispatch()` by a single
744
+ * `DispatchSlotCounter`, so every front spends it: concurrent programs,
745
+ * the `ptc_subagent` tool, and background children (which hold their
746
+ * slot for the task's whole lifetime). The next call over the cap
747
+ * resolves immediately with `{ status: "rejected", errorMessage:
748
+ * "dispatch concurrency limit reached" }` — never queued, never
749
+ * spawned, and never parked behind a long-running child.
696
750
  * Default 8, matches pi's `subagent` extension `MAX_PARALLEL_TASKS`.
697
- * ADR-0016 section 2. Independent of `maxParallelSubCalls`: builtin
698
- * calls never consume a dispatch slot and vice versa.
751
+ * ADR-0016 section 2 (as amended 2026-09-30), ADR-0022 section 9.
752
+ *
753
+ * Where the number is READ from is the counter's construction, not
754
+ * this field alone: a pi session's counter is built by
755
+ * `createBackgroundTaskRuntime({ concurrency })` with this value, and
756
+ * the dispatcher hands the binding `options.dispatchDeps?.slots ??
757
+ * dispatchSlots` — so a `runPtcProgram({ config })` override sizes only
758
+ * the per-run counter, which a pi session never reaches.
759
+ *
760
+ * Independent of `maxParallelSubCalls`: builtin calls never consume a
761
+ * dispatch slot and vice versa.
699
762
  */
700
763
  dispatchConcurrency: number;
701
764
  /** Maximum recursion depth for `pi.dispatch`. The child PTC run spawned by
@@ -1170,6 +1233,20 @@ export declare class TurnPools {
1170
1233
  export interface PtcSubagentsOptions {
1171
1234
  /** Use this session-scoped background runtime instead of constructing one. */
1172
1235
  backgroundRuntime?: BackgroundTaskRuntime;
1236
+ /**
1237
+ * Test seam for ADR-0025's surface mode. When set it wins over the agent-dir `ptc.json`,
1238
+ * so a test never reads the developer's real settings -- and the four test files that all
1239
+ * build this factory through one stub would otherwise inherit whatever the machine happens
1240
+ * to have. Undefined in production, where the file is the only source.
1241
+ */
1242
+ surfaceMode?: SurfaceMode;
1243
+ /**
1244
+ * ADR-0026 test seam: what the codemode probe found. Undefined in production, where the
1245
+ * probe really runs. A test that exercises the DETECTED default states the pi it
1246
+ * assumes rather than inheriting whatever process.argv the test runner happens to have,
1247
+ * which is how the previous version of that test passed for the wrong reason.
1248
+ */
1249
+ codemode?: CodemodePresence;
1173
1250
  }
1174
1251
  export default function ptcSubagents(pi: ExtensionAPI, options?: PtcSubagentsOptions): void;
1175
1252
  //#endregion
package/dist/index.js CHANGED
@@ -1,43 +1,46 @@
1
- import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,writeFileSync as ee}from"node:fs";import*as E from"node:os";import{tmpdir as te}from"node:os";import*as D from"node:path";import{dirname as O,join as k,resolve as A}from"node:path";import{spawn as ne}from"node:child_process";import{randomBytes as re,randomUUID as j}from"node:crypto";import{ok as M}from"node:assert/strict";import{MessageChannel as ie,Worker as N}from"node:worker_threads";import P from"node:diagnostics_channel";import{fileURLToPath as ae,pathToFileURL as F}from"node:url";import{truncateToWidth as I,visibleWidth as L}from"@earendil-works/pi-tui";import{appendFile as oe,mkdir as se,readFile as R,readdir as ce,rename as le,unlink as ue,writeFile as de}from"node:fs/promises";const fe=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function pe(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(fe[n%32]??`0`)+t,n=Math.floor(n/32);return t}function me(e){let t=``,n=0,r=0;for(let i=0;i<e.length&&t.length<16;i++)for(n=n<<8|(e[i]??0),r+=8;r>=5&&t.length<16;)r-=5,t+=fe[n>>>r&31];return t.padEnd(16,`0`)}function he(e){let t=new Uint8Array(e);for(let e=t.length-1;e>=0;e--){if((t[e]??0)<255)return t[e]=(t[e]??0)+1,t;t[e]=0}return t}function ge(e){let t=e.randomBytes??(e=>new Uint8Array(re(e))),n=-1,r=/* @__PURE__ */ new Uint8Array(10);return{next(){let i=Math.max(0,Math.floor(e.now())),a=i>n?i:n,o=a===n?he(r):t(10);return n=a,r=o,pe(a)+me(o)}}}const _e=ge({now:()=>Date.now()});function ve(){return _e.next()}function ye(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function be(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function xe(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function Se(e,t){if(e.exited)return;e.exited=!0,e.exitValue=t;for(let n of e.exitWaiters)n(t);e.exitWaiters=[];let n=e.eventWaiters;e.eventWaiters=[];for(let e of n)e(null);for(let t of e.stderrWaiters)t(e.stderr);e.stderrWaiters=[]}function Ce(e,t){let n=t.sessionDir===void 0?[...e]:e.filter(e=>e!==`--no-session`);return t.sessionDir!==void 0&&(n.push(`--session-dir`,t.sessionDir),t.sessionId!==void 0&&n.push(`--session-id`,t.sessionId),t.sessionName!==void 0&&n.push(`--name`,t.sessionName)),n}const we={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Te(e){return e.length<=200?e:e.slice(0,200)+`…`}var Ee=class{#e;constructor(e={}){this.#e=e.logger??we}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=Ce(e,t),r=n[0],i=n.slice(1),a=ne(r,i,{cwd:t.cwd,shell:!1,stdio:[`ignore`,`pipe`,`pipe`],env:t.env}),o={proc:a,events:[],eventWaiters:[],exited:!1,exitValue:null,stderrWaiters:[],exitWaiters:[],stderr:``,lineBuffer:``},s={id:ve(),opaque:o},c=a.stdout;c&&c.on(`data`,e=>{o.lineBuffer+=e.toString(`utf-8`);let t=o.lineBuffer.indexOf(`
2
- `);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=ye(e);n?xe(o,n):e.trim().length>0&&this.#t(s,e),t=o.lineBuffer.indexOf(`
3
- `)}});let l=a.stderr;return l&&l.on(`data`,e=>{o.stderr+=e.toString(`utf-8`)}),a.on(`close`,(e,t)=>{let n=o.lineBuffer.trim();if(n.length>0){let e=ye(n);e?xe(o,e):this.#t(s,n),o.lineBuffer=``}Se(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
4
- `,o.exited||Se(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;be(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Te(t))}};const z=Object.freeze({timeoutMs:12e4,maxTimeoutMs:6e5,maxOutputBytes:67108864,maxMessageBytes:134217728,maxPendingCalls:128,maxParallelSubCalls:10,dispatchConcurrency:8,maxDispatchDepth:3,maxItemsPerCall:4096,graceMs:3e3,maxOldGenerationSizeMb:512,maxYoungGenerationSizeMb:64,poolSize:4,poolAcquireTimeoutMs:3e4,drainGraceMs:5e3}),De=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Oe(e=process.env){let t={};for(let n of De){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function ke(e={}){let t={...z};for(let n of Object.keys(z)){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0)throw TypeError(`invalid PTC config override for ${n}: ${String(r)}`);t[n]=r}}return t}function Ae(e,t=z){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const je={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Me=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Ne=/* @__PURE__ */ new Set([`running`,`stopping`]);function Pe(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Fe(e){return typeof e==`string`&&e.length>0}const Ie=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function Le(e){return typeof e==`string`&&Ie.has(e)}function Re(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function ze(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Be(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ve=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??ze,this.#a=ge({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Fe(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())Ne.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Fe(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!Pe(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!Le(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=n.status===`stopping`?`canceled`:e.exitCode===0?`succeeded`:`failed`;return this.#v(n,r),this.#m(n,r,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#p(e,t){let n=await this.#y(e.taskId);if(!Ne.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};Me.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=je[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Fe(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Be(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function He(e,t){return new Ve(e,t)}function Ue(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function We(e){for(let t=1;t<e.length;t++)if(Ue(e[t-1],e[t])>0)return!1;return!0}var Ge=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){M(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){M(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=We(t)?[...t]:[...t].sort(Ue),i=n.length===0?void 0:n[n.length-1]?.eventId,a=r[0]?.eventId;if(i===void 0||a!==void 0&&i<=a){for(let e of r)n.push(structuredClone(e));this.#r.set(e,n);return}let o=[...n,...r.map(e=>structuredClone(e))];o.sort(Ue),this.#r.set(e,o)}async*loadEvents(e,t){if(!this.#a(e))throw Error(`loadEvents: unknown subscriptionId ${e}`);let n=this.#r.get(e)??[],r=0;if(t!==void 0){let e=0,i=n.length;for(;e<i;){let r=e+i>>>1;(n[r]?.eventId??``)<=t?e=r+1:i=r}r=e}for(let e=r;e<n.length;e++)yield structuredClone(n[e])}};const B=new Ee;var Ke=class{limit;#e;#t=/* @__PURE__ */ new Set;constructor(e){if(!Number.isInteger(e)||e<0)throw TypeError(`DispatchSlotCounter: limit must be a non-negative integer, got ${String(e)}`);this.limit=e,this.#e=0}get active(){return this.#e}tryAcquire(e){return e!==void 0&&this.#t.has(e)||this.#e>=this.limit?!1:(e!==void 0&&this.#t.add(e),this.#e+=1,!0)}release(e){if(e!==void 0){if(!this.#t.delete(e))return;--this.#e;return}this.#e>this.#t.size&&--this.#e}};const qe=new Ke(z.dispatchConcurrency);let Je;function Ye(e,t){return e.taskRegistry===void 0?(Je??=new Ve(new Ge,{clock:t}),Je):e.taskRegistry}const Xe={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}};function Ze(e,t,n){let r=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`</pi-ptc-context>`].join(`
1
+ import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,realpathSync as ee,statSync as E,writeFileSync as te}from"node:fs";import*as ne from"node:os";import{tmpdir as re}from"node:os";import*as D from"node:path";import{dirname as O,join as k,resolve as A}from"node:path";import{spawn as ie}from"node:child_process";import{randomBytes as ae,randomUUID as j}from"node:crypto";import{ok as M}from"node:assert/strict";import{MessageChannel as oe,Worker as se}from"node:worker_threads";import N from"node:diagnostics_channel";import{fileURLToPath as ce,pathToFileURL as le}from"node:url";import{truncateToWidth as P,visibleWidth as F}from"@earendil-works/pi-tui";import{appendFile as ue,mkdir as de,readFile as fe,readdir as pe,rename as me,unlink as he,writeFile as ge}from"node:fs/promises";const _e=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function ve(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(_e[n%32]??`0`)+t,n=Math.floor(n/32);return t}function ye(e){let t=``,n=0,r=0;for(let i=0;i<e.length&&t.length<16;i++)for(n=n<<8|(e[i]??0),r+=8;r>=5&&t.length<16;)r-=5,t+=_e[n>>>r&31];return t.padEnd(16,`0`)}function be(e){let t=new Uint8Array(e);for(let e=t.length-1;e>=0;e--){if((t[e]??0)<255)return t[e]=(t[e]??0)+1,t;t[e]=0}return t}function xe(e){let t=e.randomBytes??(e=>new Uint8Array(ae(e))),n=-1,r=/* @__PURE__ */ new Uint8Array(10);return{next(){let i=Math.max(0,Math.floor(e.now())),a=i>n?i:n,o=a===n?be(r):t(10);return n=a,r=o,ve(a)+ye(o)}}}const Se=xe({now:()=>Date.now()});function Ce(){return Se.next()}function we(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function Te(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function Ee(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function De(e,t){if(e.exited)return;e.exited=!0,e.exitValue=t;for(let n of e.exitWaiters)n(t);e.exitWaiters=[];let n=e.eventWaiters;e.eventWaiters=[];for(let e of n)e(null);for(let t of e.stderrWaiters)t(e.stderr);e.stderrWaiters=[]}function Oe(e,t){let n=t.sessionDir===void 0?[...e]:e.filter(e=>e!==`--no-session`);return t.sessionDir!==void 0&&(n.push(`--session-dir`,t.sessionDir),t.sessionId!==void 0&&n.push(`--session-id`,t.sessionId),t.sessionName!==void 0&&n.push(`--name`,t.sessionName)),n}const ke={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Ae(e){return e.length<=200?e:e.slice(0,200)+`…`}var je=class{#e;constructor(e={}){this.#e=e.logger??ke}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=Oe(e,t),r=n[0],i=n.slice(1),a=ie(r,i,{cwd:t.cwd,shell:!1,stdio:[`ignore`,`pipe`,`pipe`],env:t.env}),o={proc:a,events:[],eventWaiters:[],exited:!1,exitValue:null,stderrWaiters:[],exitWaiters:[],stderr:``,lineBuffer:``},s={id:Ce(),opaque:o},c=a.stdout;c&&c.on(`data`,e=>{o.lineBuffer+=e.toString(`utf-8`);let t=o.lineBuffer.indexOf(`
2
+ `);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=we(e);n?Ee(o,n):e.trim().length>0&&this.#t(s,e),t=o.lineBuffer.indexOf(`
3
+ `)}});let l=a.stderr;return l&&l.on(`data`,e=>{o.stderr+=e.toString(`utf-8`)}),a.on(`close`,(e,t)=>{let n=o.lineBuffer.trim();if(n.length>0){let e=we(n);e?Ee(o,e):this.#t(s,n),o.lineBuffer=``}De(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
4
+ `,o.exited||De(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Te(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Ae(t))}};const I=Object.freeze({timeoutMs:12e4,maxTimeoutMs:6e5,maxOutputBytes:67108864,maxMessageBytes:134217728,maxPendingCalls:128,maxParallelSubCalls:10,dispatchConcurrency:8,maxDispatchDepth:3,maxItemsPerCall:4096,graceMs:3e3,maxOldGenerationSizeMb:512,maxYoungGenerationSizeMb:64,poolSize:4,poolAcquireTimeoutMs:3e4,drainGraceMs:5e3}),Me=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Ne(e=process.env){let t={};for(let n of Me){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function L(e={}){let t={...I};for(let n of Object.keys(I)){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0)throw TypeError(`invalid PTC config override for ${n}: ${String(r)}`);t[n]=r}}return t}function Pe(e,t=I){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Fe={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ie=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Le=/* @__PURE__ */ new Set([`running`,`stopping`]);function Re(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function ze(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Be(e){return typeof e==`string`&&e.length>0}const Ve=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function He(e){return typeof e==`string`&&Ve.has(e)}function Ue(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function We(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Ge(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ke=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??We,this.#a=xe({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Be(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())Le.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Be(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!ze(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!He(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=(e.outputBytes??0)>0,i=n.status===`stopping`?`canceled`:e.exitCode===0&&r?`succeeded`:`failed`;return this.#v(n,i),this.#m(n,i,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview,errorMessage:Re(n,e,i,r)})}async#p(e,t){let n=await this.#y(e.taskId);if(!Le.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};Ie.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=Fe[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Be(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Ge(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function qe(e,t){return new Ke(e,t)}function Je(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function Ye(e){for(let t=1;t<e.length;t++)if(Je(e[t-1],e[t])>0)return!1;return!0}var Xe=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){M(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){M(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=Ye(t)?[...t]:[...t].sort(Je),i=n.length===0?void 0:n[n.length-1]?.eventId,a=r[0]?.eventId;if(i===void 0||a!==void 0&&i<=a){for(let e of r)n.push(structuredClone(e));this.#r.set(e,n);return}let o=[...n,...r.map(e=>structuredClone(e))];o.sort(Je),this.#r.set(e,o)}async*loadEvents(e,t){if(!this.#a(e))throw Error(`loadEvents: unknown subscriptionId ${e}`);let n=this.#r.get(e)??[],r=0;if(t!==void 0){let e=0,i=n.length;for(;e<i;){let r=e+i>>>1;(n[r]?.eventId??``)<=t?e=r+1:i=r}r=e}for(let e=r;e<n.length;e++)yield structuredClone(n[e])}};const R=new je;var Ze=class{limit;#e;#t=/* @__PURE__ */ new Set;constructor(e){if(!Number.isInteger(e)||e<0)throw TypeError(`DispatchSlotCounter: limit must be a non-negative integer, got ${String(e)}`);this.limit=e,this.#e=0}get active(){return this.#e}tryAcquire(e){return e!==void 0&&this.#t.has(e)||this.#e>=this.limit?!1:(e!==void 0&&this.#t.add(e),this.#e+=1,!0)}release(e){if(e!==void 0){if(!this.#t.delete(e))return;--this.#e;return}this.#e>this.#t.size&&--this.#e}};const Qe=new Ze(I.dispatchConcurrency);let $e;function et(e,t){return e.taskRegistry===void 0?($e??=new Ke(new Xe,{clock:t}),$e):e.taskRegistry}const tt={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}};function nt(e,t,n){let r=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`</pi-ptc-context>`].join(`
5
5
  `);return e.length===0?r:e+`
6
6
 
7
- `+r}function Qe(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch depth limit reached`}}const $e=`dispatch concurrency limit reached`;function et(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:$e}}function tt(e,t,n={}){e.kill(t,`SIGTERM`);let r=setTimeout(()=>{n.isDone?.()!==!0&&e.kill(t,`SIGKILL`)},5e3);return n.unref===!0&&r.unref(),()=>clearTimeout(r)}function nt(){return{...Qe(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function rt(){return{...et(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function it(e){return e.aborted?{status:`rejected`,errorMessage:`dispatch cancelled`}:e.exitCode===0&&e.finalText.length>0?{status:`fulfilled`}:e.exitCode===0?{status:`rejected`,errorMessage:`dispatch produced no final text`}:{status:`rejected`}}function at(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();if(r.length>=2){let e=r[0],t=r[r.length-1];(e===`"`&&t===`"`||e===`'`&&t===`'`)&&(r=r.slice(1,-1))}return r.length===0?void 0:r}function ot(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();r.startsWith(`[`)&&r.endsWith(`]`)&&(r=r.slice(1,-1));let i=r.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return i.length===0?void 0:i}function st(e){let t=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return null;let n=t[1]??``,r=t[2]??``,i=at(n,`name`);if(!i)return null;let a=at(n,`description`)??``,o=at(n,`model`)??``,s=ot(n,`tools`),c={name:i,systemPrompt:r.trim()};return a!==void 0&&(c.description=a),o!==void 0&&(c.model=o),s!==void 0&&(c.tools=s),c}function ct(e,t,n,r){let{userDir:i,projectDir:a}=lt({cwd:t,agentScope:n,homeDir:r?.homeDir}),o=[];(n===`user`||n===`both`)&&o.push({path:D.join(i,e+`.md`),source:`user`}),(n===`project`||n===`both`)&&o.push({path:D.join(a,e+`.md`),source:`project`});for(let t of o){let n;try{n=C.readFileSync(t.path,`utf-8`)}catch{continue}let r=st(n);if(r&&r.name===e){let e={name:r.name,source:t.source,systemPrompt:r.systemPrompt};return r.model!==void 0&&(e.model=r.model),r.tools!==void 0&&(e.tools=r.tools),e}}return null}function lt(e){let t=e.homeDir??E.homedir();return{userDir:D.join(t,`.pi`,`agent`,`agents`),projectDir:D.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function ut(e){let t=e?.code;return typeof t==`string`?t:String(e)}function dt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function ft(e,t){let n=D.resolve(e),r=D.resolve(t),i=e=>D.dirname(e),a=n,o=!1;for(let e=0;e<=8;e+=1){try{if(C.statSync(a).isDirectory()){o=!0;break}}catch{}if(a===r)break;let e=i(a);if(e===a)break;a=e}if(o){for(let e=n;e!==a&&e!==i(e);e=i(e))if(pt(e))return!0;return!1}return a===r&&pt(r)}function pt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function mt(e,t,n){let r=ut(n);return r!==`ENOENT`&&r!==`ENOTDIR`||dt(e)?!1:!ft(e,t)}function ht(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=lt(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i});let o=/* @__PURE__ */ new Set;for(let{dir:e,boundary:t}of a){let n;try{n=C.readdirSync(e)}catch(n){if(!mt(e,t,n)){let t=ut(n);console.warn(`pi.dispatch: cannot read agent directory ${e} (${t}); the agents registered there are not listed`)}continue}for(let t of n){if(!t.endsWith(`.md`))continue;let n=t.slice(0,-3),r=D.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`pi.dispatch: cannot read agent file ${r}: ${t}; falling back to the filename`),o.add(n);continue}let a=st(i)?.name??n;a.length>0&&o.add(a)}}return[...o].sort()}function gt(e){let{userDir:t,projectDir:n}=lt(e),r=ht(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t}/<name>.md (user scope) or ${n}/<name>.md (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body`}function _t(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,errorMessage:`agent is required (there is no default agent) — `+gt(e)}}function vt(e){return typeof e!=`string`||e.trim().length===0}function yt(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+gt({cwd:n,agentScope:t})}}function bt(e,t,n){let r=[`--mode`,`json`,`-p`,`--no-session`],i=e.model??t.model;i&&r.push(`--model`,i);let a=e.thinkingLevel??`off`;return r.push(`--thinking`,a),t.tools&&t.tools.length>0&&r.push(`--tools`,t.tools.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}async function xt(e,t){let n=await C.promises.mkdtemp(D.join(E.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=D.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function St(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Ct(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message.content;if(!Array.isArray(t))return;let n;for(let e of t)e&&e.type===`text`&&typeof e.text==`string`&&(n=e.text);return n}async function wt(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return nt();if(vt(e.agent))return _t({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`});let i=ve(),a=n.slots??qe;if(!a.tryAcquire(i))return rt();let o=n.clock??(()=>Date.now()),s=n.logger??Xe,c=e.cwd??t.cwd,l=e.agentScope??`user`,u=n.lifecycle??B,d=t.callerId??`dispatch:`+String(t.callId),f=Ye(n,o),p=n.outputStorage,m,h;try{let n=ct(e.agent,c,l);if(!n)return a.release(i),yt(e.agent,l,c);let g=e.label??e.task.slice(0,64),_=Ze(n.systemPrompt,r,t.maxDispatchDepth),v=await xt(n.name,_);h=v;let y=bt(e,n,v.filePath),b={cwd:c,env:{...process.env,PI_PTC_DEPTH:String(r),PI_PTC_TASK_ID:i},promptFile:v.filePath};t.sessionDir!==void 0&&(b.sessionDir=t.sessionDir,b.sessionId=i,b.sessionName=`bgdispatch:`+i),m=u.spawn([`pi`,...y],b);let x=m,S={kind:`ptc-program`,callerId:d};await f.transition({kind:`spawn`,handle:{taskId:i,label:g,status:`running`},record:{label:g,agentName:n.name,depth:r,startedAt:Math.max(0,Math.floor(o())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:S,parentTaskId:t.parentTaskId}},{clock:o,callerId:d,logger:s});let C=!1,w,T=f.onTransition((e,t)=>{e.id===i&&t.status===`stopping`&&(C||w!==void 0||(w=tt(u,x,{isDone:()=>C,unref:!0})))});return(async()=>{let e=``;try{for await(let t of u.events(x)){let n=Ct(t);n!==void 0&&(e=n)}C=!0,w?.();let t=(await u.exit(x)).code??-1,n=Buffer.byteLength(e,`utf8`),r=n<=2048?e:void 0,a;if(p!==void 0)try{await p.writeOutput(i,e),a=p.outputRef(i)}catch(e){let t=e instanceof Error?e.message:String(e);s.warn(`background dispatch output persistence for task `+i+` failed: `+t)}await f.transition({kind:`resolve-exit`,taskId:i,exitCode:t,outputRef:a,outputBytes:n,outputPreview:r},{clock:o,callerId:d,logger:s})}catch(t){let n=t instanceof Error?t.message:String(t);s.warn(`background dispatch pump for task `+i+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{T(),w?.(),St(v),a.release(i)}})(),{taskId:i,label:g,status:`running`}}catch(t){let n=t instanceof Error?t.message:String(t);return m!==void 0&&tt(u,m,{unref:!0}),h!==void 0&&St(h),a.release(i),s.warn(`background dispatch failed for agent `+e.agent+`: `+n),{text:``,status:`rejected`,started:m!==void 0,agentName:e.agent,durationMs:0,exitCode:-1,errorMessage:`background dispatch failed: `+n}}}async function Tt(e,t,n={}){if(e.background===!0)return await wt(e,t,n);let r=t.depth+1;if(r>t.maxDispatchDepth)return Qe();let i=e.cwd??t.cwd,a=e.agentScope??`user`,o=Date.now();if(vt(e.agent))return _t({cwd:i,agentScope:a});let s=ct(e.agent,i,a);if(!s)return yt(e.agent,a,i,Date.now()-o);let c=Ze(s.systemPrompt,r,t.maxDispatchDepth),l=await xt(s.name,c),u=bt(e,s,l.filePath);return await new Promise(e=>{let n=``,a,c=-1,d=``,f=!1,p,m,h=!1,g=(r,i,u=!0)=>{if(f)return;f=!0,p?.(),t.signal&&t.signal.removeEventListener(`abort`,_),St(l);let m={text:n,status:r,started:u,agentName:s.name,durationMs:Date.now()-o,exitCode:c};a&&(m.usage=a),d.length>0&&(m.stderr=d),i&&(m.errorMessage=i),e(m)},_=()=>{m&&!f&&(h=!0,p=tt(B,m,{isDone:()=>f}))};try{m=B.spawn([`pi`,...u],{cwd:i,env:{...process.env,PI_PTC_DEPTH:String(r)},promptFile:l.filePath})}catch(e){g(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?_():t.signal.addEventListener(`abort`,_,{once:!0})),(async()=>{if(!m)return;let e=m;try{for await(let t of B.events(e))if(t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(e.usage){let t=a??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};t.input+=e.usage.input??0,t.output+=e.usage.output??0,t.cacheRead+=e.usage.cacheRead??0,t.cacheWrite+=e.usage.cacheWrite??0,t.cost+=e.usage.cost?.total??0,t.turns+=1,a=t}if(Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(n=t.text)}let t=await B.exit(e);c=t.code??-1,d=await B.stderr(e);let r=d.match(/^\[spawn-error\] (.+)$/m);if(r&&t.code===null&&t.signal===null){g(`rejected`,`failed to spawn pi: `+r[1],!1);return}let{status:i,errorMessage:o}=it({exitCode:c,finalText:n,aborted:h});g(i,o)}catch(e){let t=e instanceof Error?e.message:String(e);g(`rejected`,`dispatch internal error: `+t)}})()})}const V=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],H=`pi.dispatch`,Et=V,Dt={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},Ot={name:H,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:x.Object({agent:x.String({minLength:1}),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)])),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String())})};function kt(e){let t=e.names??Et,n=e.includeDispatch??e.names===void 0,r=/* @__PURE__ */ new Map;for(let n of t){let t=Dt[n];if(!t)throw TypeError(`unknown PTC binding "${n}"; known bindings: ${V.join(`, `)}`);let i=t(e.cwd);r.set(n,{name:n,execute:async(e,t)=>{let n=`ptc:${t.callId}`,r={type:`toolCall`,id:n,name:i.name,arguments:e},a=S(i,r),o=await i.execute(n,a,t.signal,void 0);return{content:o.content,details:o.details===void 0?null:o.details}}})}return n&&r.set(H,{name:H,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:H,arguments:t},i;try{i=S(Ot,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return vt(i)?_t({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}):{text:``,status:`rejected`,started:!1,agentName:i,durationMs:0,exitCode:1,errorMessage:n instanceof Error?n.message:String(n)}}return Tt(i,{signal:n.signal,callId:n.callId,cwd:e.cwd,depth:n.depth,maxDispatchDepth:n.maxDispatchDepth,...n.callerId===void 0?{}:{callerId:n.callerId},...n.sessionDir===void 0?{}:{sessionDir:n.sessionDir},...n.parentTaskId===void 0?{}:{parentTaskId:n.parentTaskId}},n.dispatchDeps)}}),r}function At(){let e=/* @__PURE__ */ new Map;return{recordStart(t,n,r){if(e.has(t))throw Error(`duplicate sub-call callId ${t}`);e.set(t,{callId:t,name:n,args:r,status:`running`,startMs:Date.now()})},recordEnd(t,n,r){let i=e.get(t);if(i===void 0)throw Error(`recordEnd on unknown callId ${t}`);return i.status=n,i.endMs=Date.now(),i.durationMs=i.endMs-i.startMs,n===`rejected`&&(i.durationMs=0),r?.errorMessage!==void 0&&(i.errorMessage=r.errorMessage),r?.resultSummary!==void 0&&(i.resultSummary=r.resultSummary),i},snapshot(){return[...e.values()].map(e=>({...e}))}}}function jt(e){return{name:`ptc-${e.surface}`,env:e.env,workerData:e.runId===void 0?{env:e.env}:{runId:e.runId,env:e.env},resourceLimits:{maxOldGenerationSizeMb:e.limits.maxOldGenerationSizeMb,maxYoungGenerationSizeMb:e.limits.maxYoungGenerationSizeMb}}}const U={acquireLatency:P.channel(`ptc:pool:acquire-latency`),resetTime:P.channel(`ptc:worker:reset-time`),imageBytes:P.channel(`ptc:image:hoist-bytes`)};function W(e,t){e.publish(t)}var Mt=class{#e;#t;#n;#r;#i;#a=[];#o=/* @__PURE__ */ new Set;#s=[];#c=/* @__PURE__ */ new WeakMap;#l=0;#u=0;#d=!1;constructor(e){if(typeof e.buildWorkerUrl!=`function`)throw TypeError(`WorkerPool: buildWorkerUrl must be a function`);if(e.size!==void 0&&(typeof e.size!=`number`||!Number.isFinite(e.size)||e.size<=0))throw TypeError(`WorkerPool: size must be a positive finite number, received ${String(e.size)}`);if(e.acquireTimeoutMs!==void 0&&(typeof e.acquireTimeoutMs!=`number`||!Number.isFinite(e.acquireTimeoutMs)||e.acquireTimeoutMs<=0))throw TypeError(`WorkerPool: acquireTimeoutMs must be a positive finite number, received ${String(e.acquireTimeoutMs)}`);if(e.drainGraceMs!==void 0&&(typeof e.drainGraceMs!=`number`||!Number.isFinite(e.drainGraceMs)||e.drainGraceMs<=0))throw TypeError(`WorkerPool: drainGraceMs must be a positive finite number, received ${String(e.drainGraceMs)}`);this.#e=e.buildWorkerUrl,this.#t=e.size??4,this.#n=e.acquireTimeoutMs??3e4,this.#r=e.drainGraceMs??5e3,this.#i=e.workerOptions}async acquire(){if(this.#d)throw Error(`pool has been drained and can no longer serve workers`);this.#l+=1;let e=Date.now(),t=this.#a.shift();for(;t!==void 0&&!this.#p(t);)t=this.#a.shift();if(t!==void 0)return this.#o.add(t),t.ref(),W(U.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t;if(this.#o.size<this.#t){let t=this.#f();return this.#o.add(t),W(U.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t}return this.#u+=1,await new Promise((t,n)=>{let r=setTimeout(()=>{let e=this.#s.findIndex(e=>e.timer===r);e>=0&&this.#s.splice(e,1),n(/* @__PURE__ */ Error(`pool acquire timed out after ${this.#n} ms`))},this.#n);this.#s.push({resolve:t,reject:n,timer:r,startedAt:e})})}release(e){if(!this.#o.delete(e)||!this.#p(e))return;this.#c.set(e,Date.now());let t=this.#s.shift();if(t){clearTimeout(t.timer),this.#o.add(e),W(U.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-t.startedAt}),t.resolve(e);return}this.#a.push(e),e.unref()}lastSettledAt(e){return this.#c.get(e)}async drain(){for(;this.#s.length>0;){let e=this.#s.shift();if(!e)break;clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`pool drained before acquire could be satisfied`))}let e=Date.now()+this.#r;for(;this.#o.size>0&&Date.now()<e;)await new Promise(e=>setTimeout(e,5));let t=[...this.#a,...this.#o];this.#a.length=0,this.#o.clear(),await Promise.all(t.map(e=>e.terminate().catch(()=>void 0))),this.#d=!0}stats(){return{resident:this.#o.size+this.#a.length,inFlight:this.#o.size,waiters:this.#s.length,totalAcquires:this.#l,poolExhaustions:this.#u}}#f(){let e=new N(this.#e(),this.#i);return e.once(`exit`,()=>{let t=this.#a.indexOf(e);if(t>=0){this.#a.splice(t,1);return}this.#o.delete(e)}),e}#p(e){return e.threadId!==-1}};function Nt(e){W(U.imageBytes,{byteLength:e})}function Pt(e){W(U.resetTime,{durationMs:e})}function Ft(){let e=O(ae(import.meta.url)),t=[A(e,`worker.js`),A(e,`worker-entry.ts`)];for(let e of t)if(w(e))return F(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function It(e){if(typeof e!=`object`||!e)return;let t=e;if(t.status!==`rejected`)return;let n=typeof t.errorMessage==`string`?t.errorMessage:t.started===!1?`dispatch refused`:`dispatch failed`;return{kind:t.started===!1?`refused`:`failed`,message:n}}function Lt(e){return typeof e==`object`&&!!e&&e.background===!0}function G(e){return e instanceof Error?e.message:String(e)}function Rt(e){if(typeof e!=`object`||!e)return;let t=e.content;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e==`object`&&e){let t=e.text;if(typeof t==`string`&&t.length>0){let e=t.indexOf(`
8
- `);return e===-1?t:t.slice(0,e)}}}}function zt(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Bt(e,t){let n=/* @__PURE__ */ new WeakSet,r=e=>{if(e!=null){if(e instanceof ArrayBuffer){t(e);return}if(ArrayBuffer.isView(e)){t(e);return}if(typeof e==`object`&&!n.has(e)){if(n.add(e),Array.isArray(e)){for(let t of e)r(t);return}for(let t of Object.keys(e))r(e[t])}}};r(e)}function Vt(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>zt(t)?null:t)??``,`utf8`),n=0;return Bt(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function Ht(e){let i=ke(e.config),s=Oe(),c=e.runId??j(),l=Ae(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new N(Ft(),jt({surface:e.surface,env:s,limits:i,runId:c}))}catch(e){return{logs:u,narrations:d,phases:f,error:{kind:n.workerExit,message:`pool acquire failed: ${G(e)}`}}}return await new Promise(s=>{let m=new ie,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=At(),b=()=>{v||e.onSubCallChange?.(()=>y.snapshot())},x={recordStart(e,t,n){y.recordStart(e,t,n),b()},recordEnd(e,t,n){let r=y.recordEnd(e,t,n);return b(),r},snapshot:()=>y.snapshot()},S,C=!1,w=0,T=0,ee=new Ke(i.dispatchConcurrency),E=0,te=[],D=e.depth??0,O,k,A=[],ne=e=>{let t=[],n=e?.content;if(!Array.isArray(n))return t;for(let e of n){if(typeof e!=`object`||!e)continue;let n=e;if(n.type!==`image`)continue;let r;typeof n.data==`string`&&n.data.length>0?r=n.data:n.bytes instanceof ArrayBuffer&&n.bytes.byteLength>0&&(r=Buffer.from(n.bytes).toString(`base64`)),r!==void 0&&t.push({data:r,mimeType:typeof n.mimeType==`string`?n.mimeType:`application/octet-stream`})}return t},re=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,j=e=>e===`timeout`?n.timeout:n.abort,M=t=>{if(v)return;v=!0,O&&clearTimeout(O),k&&clearTimeout(k),e.signal?.removeEventListener(`abort`,ue),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},N=(e,t,n)=>{M({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},P=e=>{if(!v){if(!r(e)){N(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},ae=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...V],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){N(n.protocol,`internal error: malformed init frame`);return}let a=Vt(t);if(a>i.maxMessageBytes){N(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}P(t)},F=(e,t)=>(T+=e,T<=i.maxOutputBytes||(N(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),I=async()=>{if(E<i.maxParallelSubCalls){E+=1;return}await new Promise(e=>{te.push(e)})},L=()=>{let e=te.shift();if(e){e();return}--E},oe=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),N(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}se(e).finally(()=>{--w})},se=async t=>{let r=e.bindings.get(t.tool);if(!r){x.recordEnd(t.callId,`error`,{errorMessage:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)}),R({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)});return}let a=t.tool===H,s=a&&Lt(t.args);if(a){if(!s&&!ee.tryAcquire()){x.recordEnd(t.callId,`rejected`,{errorMessage:$e}),R({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:et()});return}}else if(await I(),v){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),L();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:D,maxDispatchDepth:i.maxDispatchDepth,callerId:c,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...e.sessionDir===void 0?{}:{sessionDir:e.sessionDir},dispatchDeps:{...e.dispatchDeps,slots:e.dispatchDeps?.slots??ee}}),l=ne(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Vt(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),N(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(R(u))for(let e of l)A.push(e),Nt(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?It(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:Rt(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:G(e)}):x.recordEnd(t.callId,`error`,{errorMessage:G(e)}),R({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:G(e)})}finally{a?s||ee.release():L()}},R=e=>{if(v)return!1;try{return h.postMessage(e),!0}catch(t){try{h.postMessage({kind:o.callResult,callId:e.callId,tool:e.tool,ok:!1,message:`binding result could not be transferred: ${G(t)}`})}catch{N(n.protocol,`binding result is not transferable`)}return!1}},ce=e=>S?{logs:u,narrations:d,phases:f,error:{kind:j(S),message:re(S)}}:e,le=r=>{if(v)return;if(!a(r)){N(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Vt(r);if(!Number.isFinite(o)){N(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){N(n.protocol,`control frame of ${o} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}switch(r.kind){case t.ready:if(e.pool){let t=e.pool.lastSettledAt(p);t!==void 0&&Pt(Date.now()-t)}if(!C&&(C=!0,S)){de(S);return}ae();return;case t.call:oe(r);return;case t.log:F(o,`console output`)&&u.push(r.text);return;case t.narration:F(o,`workflow narration`)&&d.push(r.message);return;case t.phase:F(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!F(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...A.length>0?{images:A}:{}};M(ce(r.value===void 0?e:{...e,value:r.value}));return}case t.error:M(ce({logs:u,narrations:d,phases:f,error:r.error}));return;default:N(n.protocol,`unknown worker frame`)}};function ue(){fe(`abort`)}let de=e=>{k&&clearTimeout(k),k=setTimeout(()=>{N(j(e),re(e))},i.graceMs)};function fe(e){if(!v){if(S){N(j(S),re(S));return}S=e,_.abort(),P({kind:o.cancel,reason:e}),de(e)}}p.on(`error`,e=>{N(n.workerExit,`worker failed: ${G(e)}`)}),p.on(`exit`,e=>{N(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,le),h.on(`messageerror`,()=>{N(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,ue,{once:!0}),O=setTimeout(()=>{fe(`timeout`)},l);let pe={kind:o.connect,port:g};r(pe)?p.postMessage(pe,[g]):N(n.protocol,`internal error: malformed connect frame`)})}const Ut=`pi-ptc-output-`;function Wt(e,t=Ut){let n=k(te(),`${t}${j()}.txt`);return ee(n,e,`utf8`),n}function Gt(e,t){let n=e.totalLines-e.outputLines+1,r=e.totalLines;return e.lastLinePartial?`[Showing last ${_(e.outputBytes)} of line ${r}. Full output: ${t}]`:e.truncatedBy===`lines`?`[Showing lines ${n}-${r} of ${e.totalLines}. Full output: ${t}]`:`[Showing lines ${n}-${r} of ${e.totalLines} (${_(s)} limit). Full output: ${t}]`}function Kt(e,t=Ut,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Wt(n.fullText??e,t);return{text:`${r.content}\n\n${Gt(r,i)}`,truncated:!0,fullPath:i}}const qt=200,Jt=new RegExp([`(?:\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\u005C|\\u009C))`,`[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]`].join(`|`),`g`);function Yt(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(Jt,``)}function K(e){let t=Yt(e).replace(/\r/g,``);if(t.length===0)return t;let n=``;for(let e of t){let t=e.codePointAt(0);if(t!==void 0){if(t===10||t===9){n+=e;continue}t<=31||t>=65529&&t<=65531||(n+=e)}}return n}const Xt=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Zt(e){return Xt.test(e)?e:JSON.stringify(e)}function Qt(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=K(e);return t.includes(`
9
- `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=Qt(n);if(e===void 0)return;t.push(e)}return`[${t.join(`, `)}]`}let t=Object.keys(e);if(t.length===0)return`{}`;let n=[];for(let r of t){let t=Qt(e[r]??null);if(t===void 0)return;n.push(`${Zt(r)}: ${t}`)}return`{${n.join(`, `)}}`}function $t(e){let t=Qt(e);if(t!==void 0)return t.length<=100?t:void 0}function en(e){return e===null?`null`:typeof e==`string`?K(e):String(e)}function tn(e,t){if(typeof e!=`object`||!e)return[`${t}${en(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=$t(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...nn(r,t+` `))}return n.push(`${t}]`),n}let n=Object.keys(e);if(n.length===0)return[`${t}{}`];let r=[`${t}{`],i=t+` `;for(let t of n){let n=e[t]??null,a=$t(n);if(a!==void 0){r.push(`${i}${Zt(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${Zt(t)}:`);for(let e of K(n).split(`
10
- `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=tn(n,i);r.push(`${i}${Zt(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function nn(e,t){return typeof e==`string`?K(e).split(`
11
- `):typeof e!=`object`||!e?[String(e)]:tn(e,t)}function rn(e){return e.split(`
7
+ `+r}function rt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch depth limit reached`}}function it(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch concurrency limit reached`}}function z(e,t,n={}){e.kill(t,`SIGTERM`);let r=setTimeout(()=>{n.isDone?.()!==!0&&e.kill(t,`SIGKILL`)},5e3);return n.unref===!0&&r.unref(),()=>clearTimeout(r)}function at(){return{...rt(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function ot(){return{...it(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function st(e){return e.aborted?{status:`rejected`,errorMessage:`dispatch cancelled`}:e.exitCode===0&&e.finalText.length>0?{status:`fulfilled`}:e.exitCode===0?{status:`rejected`,errorMessage:`dispatch produced no final text`}:{status:`rejected`}}function ct(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();if(r.length>=2){let e=r[0],t=r[r.length-1];(e===`"`&&t===`"`||e===`'`&&t===`'`)&&(r=r.slice(1,-1))}return r.length===0?void 0:r}function lt(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();r.startsWith(`[`)&&r.endsWith(`]`)&&(r=r.slice(1,-1));let i=r.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return i.length===0?void 0:i}function ut(e){let t=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return null;let n=t[1]??``,r=t[2]??``,i=ct(n,`name`);if(!i)return null;let a=ct(n,`description`)??``,o=ct(n,`model`)??``,s=lt(n,`tools`),c={name:i,systemPrompt:r.trim()};return a!==void 0&&(c.description=a),o!==void 0&&(c.model=o),s!==void 0&&(c.tools=s),c}function dt(e,t,n,r){let{userDir:i,projectDir:a}=ft({cwd:t,agentScope:n,homeDir:r?.homeDir}),o=[];(n===`user`||n===`both`)&&o.push({path:D.join(i,e+`.md`),source:`user`}),(n===`project`||n===`both`)&&o.push({path:D.join(a,e+`.md`),source:`project`});for(let t of o){let n;try{n=C.readFileSync(t.path,`utf-8`)}catch{continue}let r=ut(n);if(r&&r.name===e){let e={name:r.name,source:t.source,systemPrompt:r.systemPrompt};return r.model!==void 0&&(e.model=r.model),r.tools!==void 0&&(e.tools=r.tools),e}}return null}function ft(e){let t=e.homeDir??ne.homedir();return{userDir:D.join(t,`.pi`,`agent`,`agents`),projectDir:D.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function pt(e){let t=e?.code;return typeof t==`string`?t:String(e)}function mt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function ht(e,t){let n=D.resolve(e),r=D.resolve(t),i=e=>D.dirname(e),a=n,o=!1;for(let e=0;e<=8;e+=1){try{if(C.statSync(a).isDirectory()){o=!0;break}}catch{}if(a===r)break;let e=i(a);if(e===a)break;a=e}if(o){for(let e=n;e!==a&&e!==i(e);e=i(e))if(gt(e))return!0;return!1}return a===r&&gt(r)}function gt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function _t(e,t,n){let r=pt(n);return r!==`ENOENT`&&r!==`ENOTDIR`||mt(e)?!1:!ht(e,t)}function vt(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=ft(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i});let o=/* @__PURE__ */ new Set;for(let{dir:e,boundary:t}of a){let n;try{n=C.readdirSync(e)}catch(n){if(!_t(e,t,n)){let t=pt(n);console.warn(`pi.dispatch: cannot read agent directory ${e} (${t}); the agents registered there are not listed`)}continue}for(let t of n){if(!t.endsWith(`.md`))continue;let n=t.slice(0,-3),r=D.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`pi.dispatch: cannot read agent file ${r}: ${t}; falling back to the filename`),o.add(n);continue}let a=ut(i)?.name??n;a.length>0&&o.add(a)}}return[...o].sort()}function yt(e){let{userDir:t,projectDir:n}=ft(e),r=vt(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t}/<name>.md (user scope) or ${n}/<name>.md (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body`}function bt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,errorMessage:`agent is required (there is no default agent) — `+yt(e)}}function xt(e){return typeof e!=`string`||e.trim().length===0}function St(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+yt({cwd:n,agentScope:t})}}function Ct(e,t,n){let r=[`--mode`,`json`,`-p`,`--no-session`],i=e.model??t.model;i&&r.push(`--model`,i);let a=e.thinkingLevel??`off`;return r.push(`--thinking`,a),t.tools&&t.tools.length>0&&r.push(`--tools`,t.tools.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let wt=Tt;async function Tt(e,t){let n=await C.promises.mkdtemp(D.join(ne.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=D.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function Et(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Dt(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message.content;if(!Array.isArray(t))return;let n;for(let e of t)e&&e.type===`text`&&typeof e.text==`string`&&(n=e.text);return n}function Ot(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message;if(t.stopReason!==`error`)return;let n=t.errorMessage;return typeof n==`string`&&n.trim().length>0?n.trim():`child reported stopReason: error`}async function kt(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return at();if(xt(e.agent))return bt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`});let i=Ce(),a=n.slots??Qe;if(!a.tryAcquire(i))return ot();let o=n.clock??(()=>Date.now()),s=n.logger??tt,c=e.cwd??t.cwd,l=e.agentScope??`user`,u=n.lifecycle??R,d=t.callerId??`dispatch:`+String(t.callId),f=et(n,o),p=n.outputStorage,m,h;try{let n=dt(e.agent,c,l);if(!n)return a.release(i),St(e.agent,l,c);let g=e.label??e.task.slice(0,64),_=nt(n.systemPrompt,r,t.maxDispatchDepth),v=await wt(n.name,_);h=v;let y=Ct(e,n,v.filePath),b={cwd:c,env:{...process.env,PI_PTC_DEPTH:String(r),PI_PTC_TASK_ID:i},promptFile:v.filePath};t.sessionDir!==void 0&&(b.sessionDir=t.sessionDir,b.sessionId=i,b.sessionName=`bgdispatch:`+i),m=u.spawn([`pi`,...y],b);let x=m,S={kind:`ptc-program`,callerId:d};await f.transition({kind:`spawn`,handle:{taskId:i,label:g,status:`running`},record:{label:g,agentName:n.name,depth:r,startedAt:Math.max(0,Math.floor(o())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:S,parentTaskId:t.parentTaskId}},{clock:o,callerId:d,logger:s});let C=!1,w,T=f.onTransition((e,t)=>{e.id===i&&t.status===`stopping`&&(C||w!==void 0||(w=z(u,x,{isDone:()=>C,unref:!0})))});return(async()=>{let e=``,t;try{for await(let n of u.events(x)){let r=Dt(n);r!==void 0&&(e=r);let i=Ot(n);i!==void 0&&(t=i)}C=!0,w?.();let n=(await u.exit(x)).code??-1,r=Buffer.byteLength(e,`utf8`),a=r<=2048?e:void 0,c;if(p!==void 0)try{await p.writeOutput(i,e),c=p.outputRef(i)}catch(e){let t=e instanceof Error?e.message:String(e);s.warn(`background dispatch output persistence for task `+i+` failed: `+t)}await f.transition({kind:`resolve-exit`,taskId:i,exitCode:n,outputRef:c,outputBytes:r,outputPreview:a,childError:t},{clock:o,callerId:d,logger:s})}catch(t){let n=t instanceof Error?t.message:String(t);s.warn(`background dispatch pump for task `+i+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{T(),w?.(),Et(v),a.release(i)}})(),{taskId:i,label:g,status:`running`}}catch(t){let n=t instanceof Error?t.message:String(t);return m!==void 0&&z(u,m,{unref:!0}),h!==void 0&&Et(h),a.release(i),s.warn(`background dispatch failed for agent `+e.agent+`: `+n),{text:``,status:`rejected`,started:m!==void 0,agentName:e.agent,durationMs:0,exitCode:-1,errorMessage:`background dispatch failed: `+n}}}async function At(e,t,n={}){if(e.background===!0)return await kt(e,t,n);let r=t.depth+1;if(r>t.maxDispatchDepth)return rt();let i=e.cwd??t.cwd,a=e.agentScope??`user`,o=Date.now();if(xt(e.agent))return bt({cwd:i,agentScope:a});let s=n.slots??Qe;if(!s.tryAcquire())return it();let c=dt(e.agent,i,a);if(!c)return s.release(),St(e.agent,a,i,Date.now()-o);let l=nt(c.systemPrompt,r,t.maxDispatchDepth),u,d=n.lifecycle??R,f;try{u=await wt(c.name,l),f=Ct(e,c,u.filePath)}catch(e){throw s.release(),e}return await new Promise(e=>{let a=``,l,p=-1,m=``,h=!1,g,_,v=!1,y=(r,i,f=!0)=>{if(h)return;h=!0,s.release(),_!==void 0&&d.exit(_).catch(e=>{(n.logger??tt).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),g?.(),t.signal&&t.signal.removeEventListener(`abort`,b),Et(u);let v={text:a,status:r,started:f,agentName:c.name,durationMs:Date.now()-o,exitCode:p};l&&(v.usage=l),m.length>0&&(v.stderr=m),i&&(v.errorMessage=i),e(v)},b=()=>{_&&!h&&(v=!0,g=z(d,_,{isDone:()=>h}))};try{_=d.spawn([`pi`,...f],{cwd:i,env:{...process.env,PI_PTC_DEPTH:String(r)},promptFile:u.filePath})}catch(e){y(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?b():t.signal.addEventListener(`abort`,b,{once:!0})),(async()=>{if(!_)return;let e=_;try{for await(let t of d.events(e))if(t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(e.usage){let t=l??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};t.input+=e.usage.input??0,t.output+=e.usage.output??0,t.cacheRead+=e.usage.cacheRead??0,t.cacheWrite+=e.usage.cacheWrite??0,t.cost+=e.usage.cost?.total??0,t.turns+=1,l=t}if(Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(a=t.text)}let t=await R.exit(e);p=t.code??-1,m=await R.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){y(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:r,errorMessage:i}=st({exitCode:p,finalText:a,aborted:v});y(r,i)}catch(e){let t=e instanceof Error?e.message:String(e);y(`rejected`,`dispatch internal error: `+t)}})()})}const B=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],V=`pi.dispatch`,jt=B,Mt={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},Nt=x.Object({agent:x.String({minLength:1}),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)])),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String())}),Pt={name:V,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:Nt};function Ft(e){let t=e.names??jt,n=e.includeDispatch??e.names===void 0,r=/* @__PURE__ */ new Map;for(let n of t){let t=Mt[n];if(!t)throw TypeError(`unknown PTC binding "${n}"; known bindings: ${B.join(`, `)}`);let i=t(e.cwd);r.set(n,{name:n,execute:async(e,t)=>{let n=`ptc:${t.callId}`,r={type:`toolCall`,id:n,name:i.name,arguments:e},a=S(i,r),o=await i.execute(n,a,t.signal,void 0);return{content:o.content,details:o.details===void 0?null:o.details}}})}return n&&r.set(V,{name:V,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:V,arguments:t},i;try{i=S(Pt,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return xt(i)?bt({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}):{text:``,status:`rejected`,started:!1,agentName:i,durationMs:0,exitCode:1,errorMessage:n instanceof Error?n.message:String(n)}}return At(i,{signal:n.signal,callId:n.callId,cwd:e.cwd,depth:n.depth,maxDispatchDepth:n.maxDispatchDepth,...n.callerId===void 0?{}:{callerId:n.callerId},...n.sessionDir===void 0?{}:{sessionDir:n.sessionDir},...n.parentTaskId===void 0?{}:{parentTaskId:n.parentTaskId}},n.dispatchDeps)}}),r}function It(){let e=/* @__PURE__ */ new Map;return{recordStart(t,n,r){if(e.has(t))throw Error(`duplicate sub-call callId ${t}`);e.set(t,{callId:t,name:n,args:r,status:`running`,startMs:Date.now()})},recordEnd(t,n,r){let i=e.get(t);if(i===void 0)throw Error(`recordEnd on unknown callId ${t}`);return i.status=n,i.endMs=Date.now(),i.durationMs=i.endMs-i.startMs,n===`rejected`&&(i.durationMs=0),r?.errorMessage!==void 0&&(i.errorMessage=r.errorMessage),r?.resultSummary!==void 0&&(i.resultSummary=r.resultSummary),i},snapshot(){return[...e.values()].map(e=>({...e}))}}}function Lt(e){return{name:`ptc-${e.surface}`,env:e.env,workerData:e.runId===void 0?{env:e.env}:{runId:e.runId,env:e.env},resourceLimits:{maxOldGenerationSizeMb:e.limits.maxOldGenerationSizeMb,maxYoungGenerationSizeMb:e.limits.maxYoungGenerationSizeMb}}}const H={acquireLatency:N.channel(`ptc:pool:acquire-latency`),resetTime:N.channel(`ptc:worker:reset-time`),imageBytes:N.channel(`ptc:image:hoist-bytes`)};function U(e,t){e.publish(t)}var Rt=class{#e;#t;#n;#r;#i;#a=[];#o=/* @__PURE__ */ new Set;#s=[];#c=/* @__PURE__ */ new WeakMap;#l=0;#u=0;#d=!1;constructor(e){if(typeof e.buildWorkerUrl!=`function`)throw TypeError(`WorkerPool: buildWorkerUrl must be a function`);if(e.size!==void 0&&(typeof e.size!=`number`||!Number.isFinite(e.size)||e.size<=0))throw TypeError(`WorkerPool: size must be a positive finite number, received ${String(e.size)}`);if(e.acquireTimeoutMs!==void 0&&(typeof e.acquireTimeoutMs!=`number`||!Number.isFinite(e.acquireTimeoutMs)||e.acquireTimeoutMs<=0))throw TypeError(`WorkerPool: acquireTimeoutMs must be a positive finite number, received ${String(e.acquireTimeoutMs)}`);if(e.drainGraceMs!==void 0&&(typeof e.drainGraceMs!=`number`||!Number.isFinite(e.drainGraceMs)||e.drainGraceMs<=0))throw TypeError(`WorkerPool: drainGraceMs must be a positive finite number, received ${String(e.drainGraceMs)}`);this.#e=e.buildWorkerUrl,this.#t=e.size??4,this.#n=e.acquireTimeoutMs??3e4,this.#r=e.drainGraceMs??5e3,this.#i=e.workerOptions}async acquire(){if(this.#d)throw Error(`pool has been drained and can no longer serve workers`);this.#l+=1;let e=Date.now(),t=this.#a.shift();for(;t!==void 0&&!this.#p(t);)t=this.#a.shift();if(t!==void 0)return this.#o.add(t),t.ref(),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t;if(this.#o.size<this.#t){let t=this.#f();return this.#o.add(t),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t}return this.#u+=1,await new Promise((t,n)=>{let r=setTimeout(()=>{let e=this.#s.findIndex(e=>e.timer===r);e>=0&&this.#s.splice(e,1),n(/* @__PURE__ */ Error(`pool acquire timed out after ${this.#n} ms`))},this.#n);this.#s.push({resolve:t,reject:n,timer:r,startedAt:e})})}release(e){if(!this.#o.delete(e)||!this.#p(e))return;this.#c.set(e,Date.now());let t=this.#s.shift();if(t){clearTimeout(t.timer),this.#o.add(e),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-t.startedAt}),t.resolve(e);return}this.#a.push(e),e.unref()}lastSettledAt(e){return this.#c.get(e)}async drain(){for(;this.#s.length>0;){let e=this.#s.shift();if(!e)break;clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`pool drained before acquire could be satisfied`))}let e=Date.now()+this.#r;for(;this.#o.size>0&&Date.now()<e;)await new Promise(e=>setTimeout(e,5));let t=[...this.#a,...this.#o];this.#a.length=0,this.#o.clear(),await Promise.all(t.map(e=>e.terminate().catch(()=>void 0))),this.#d=!0}stats(){return{resident:this.#o.size+this.#a.length,inFlight:this.#o.size,waiters:this.#s.length,totalAcquires:this.#l,poolExhaustions:this.#u}}#f(){let e=new se(this.#e(),this.#i);return e.once(`exit`,()=>{let t=this.#a.indexOf(e);if(t>=0){this.#a.splice(t,1);return}this.#o.delete(e)}),e}#p(e){return e.threadId!==-1}};function zt(e){U(H.imageBytes,{byteLength:e})}function Bt(e){U(H.resetTime,{durationMs:e})}function Vt(){let e=O(ce(import.meta.url)),t=[A(e,`worker.js`),A(e,`worker-entry.ts`)];for(let e of t)if(w(e))return le(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function Ht(e){if(typeof e!=`object`||!e)return;let t=e;if(t.status!==`rejected`)return;let n=typeof t.errorMessage==`string`?t.errorMessage:t.started===!1?`dispatch refused`:`dispatch failed`;return{kind:t.started===!1?`refused`:`failed`,message:n}}function W(e){return e instanceof Error?e.message:String(e)}function Ut(e){if(typeof e!=`object`||!e)return;let t=e.content;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e==`object`&&e){let t=e.text;if(typeof t==`string`&&t.length>0){let e=t.indexOf(`
8
+ `);return e===-1?t:t.slice(0,e)}}}}function Wt(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Gt(e,t){let n=/* @__PURE__ */ new WeakSet,r=e=>{if(e!=null){if(e instanceof ArrayBuffer){t(e);return}if(ArrayBuffer.isView(e)){t(e);return}if(typeof e==`object`&&!n.has(e)){if(n.add(e),Array.isArray(e)){for(let t of e)r(t);return}for(let t of Object.keys(e))r(e[t])}}};r(e)}function Kt(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>Wt(t)?null:t)??``,`utf8`),n=0;return Gt(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function qt(e){let i=L(e.config),s=Ne(),c=e.runId??j(),l=Pe(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new se(Vt(),Lt({surface:e.surface,env:s,limits:i,runId:c}))}catch(e){return{logs:u,narrations:d,phases:f,error:{kind:n.workerExit,message:`pool acquire failed: ${W(e)}`}}}return await new Promise(s=>{let m=new oe,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=It(),b=()=>{v||e.onSubCallChange?.(()=>y.snapshot())},x={recordStart(e,t,n){y.recordStart(e,t,n),b()},recordEnd(e,t,n){let r=y.recordEnd(e,t,n);return b(),r},snapshot:()=>y.snapshot()},S,C=!1,w=0,T=0,ee=new Ze(i.dispatchConcurrency),E=0,te=[],ne=e.depth??0,re,D,O=[],k=e=>{let t=[],n=e?.content;if(!Array.isArray(n))return t;for(let e of n){if(typeof e!=`object`||!e)continue;let n=e;if(n.type!==`image`)continue;let r;typeof n.data==`string`&&n.data.length>0?r=n.data:n.bytes instanceof ArrayBuffer&&n.bytes.byteLength>0&&(r=Buffer.from(n.bytes).toString(`base64`)),r!==void 0&&t.push({data:r,mimeType:typeof n.mimeType==`string`?n.mimeType:`application/octet-stream`})}return t},A=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,ie=e=>e===`timeout`?n.timeout:n.abort,ae=t=>{if(v)return;v=!0,re&&clearTimeout(re),D&&clearTimeout(D),e.signal?.removeEventListener(`abort`,pe),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},j=(e,t,n)=>{ae({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},M=e=>{if(!v){if(!r(e)){j(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},se=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...B],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){j(n.protocol,`internal error: malformed init frame`);return}let a=Kt(t);if(a>i.maxMessageBytes){j(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}M(t)},N=(e,t)=>(T+=e,T<=i.maxOutputBytes||(j(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),ce=async()=>{if(E<i.maxParallelSubCalls){E+=1;return}await new Promise(e=>{te.push(e)})},le=()=>{let e=te.shift();if(e){e();return}--E},P=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),j(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}F(e).finally(()=>{--w})},F=async t=>{let r=e.bindings.get(t.tool);if(!r){x.recordEnd(t.callId,`error`,{errorMessage:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)});return}let a=t.tool===V;if(!a&&(await ce(),v)){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),le();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:ne,maxDispatchDepth:i.maxDispatchDepth,callerId:c,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...e.sessionDir===void 0?{}:{sessionDir:e.sessionDir},dispatchDeps:{...e.dispatchDeps,slots:e.dispatchDeps?.slots??ee}}),l=k(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Kt(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),j(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(ue(u))for(let e of l)O.push(e),zt(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?Ht(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:Ut(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:W(e)}):x.recordEnd(t.callId,`error`,{errorMessage:W(e)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:W(e)})}finally{a||le()}},ue=e=>{if(v)return!1;try{return h.postMessage(e),!0}catch(t){try{h.postMessage({kind:o.callResult,callId:e.callId,tool:e.tool,ok:!1,message:`binding result could not be transferred: ${W(t)}`})}catch{j(n.protocol,`binding result is not transferable`)}return!1}},de=e=>S?{logs:u,narrations:d,phases:f,error:{kind:ie(S),message:A(S)}}:e,fe=r=>{if(v)return;if(!a(r)){j(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Kt(r);if(!Number.isFinite(o)){j(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){j(n.protocol,`control frame of ${o} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}switch(r.kind){case t.ready:if(e.pool){let t=e.pool.lastSettledAt(p);t!==void 0&&Bt(Date.now()-t)}if(!C&&(C=!0,S)){me(S);return}se();return;case t.call:P(r);return;case t.log:N(o,`console output`)&&u.push(r.text);return;case t.narration:N(o,`workflow narration`)&&d.push(r.message);return;case t.phase:N(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!N(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...O.length>0?{images:O}:{}};ae(de(r.value===void 0?e:{...e,value:r.value}));return}case t.error:ae(de({logs:u,narrations:d,phases:f,error:r.error}));return;default:j(n.protocol,`unknown worker frame`)}};function pe(){he(`abort`)}let me=e=>{D&&clearTimeout(D),D=setTimeout(()=>{j(ie(e),A(e))},i.graceMs)};function he(e){if(!v){if(S){j(ie(S),A(S));return}S=e,_.abort(),M({kind:o.cancel,reason:e}),me(e)}}p.on(`error`,e=>{j(n.workerExit,`worker failed: ${W(e)}`)}),p.on(`exit`,e=>{j(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,fe),h.on(`messageerror`,()=>{j(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,pe,{once:!0}),re=setTimeout(()=>{he(`timeout`)},l);let ge={kind:o.connect,port:g};r(ge)?p.postMessage(ge,[g]):j(n.protocol,`internal error: malformed connect frame`)})}const Jt=["Return value: every `tools.<name>(args)` call above resolves to `{ content, details }`.","`content` is an ARRAY of content blocks, never a string, so a text result is","`result.content[0].text`; `details` is that tool's own detail object or `null`, never","`undefined`. No binding result has a `files`, `output`, `matches` or `entries` field:","`bash`, `grep`, `find` and `ls` hand back ONE text block of newline-separated rows that","you split yourself, and the empty answer is a sentinel string (`No matches found`,","`No files found matching pattern`, `(empty directory)`) rather than an empty list.","A failing call REJECTS with `ToolCallError` instead of resolving, so wrap the call in","`try`/`catch` (or `Promise.allSettled`): a path that is not there, a builtin this run did not",`bind. A name that is not a builtin is simply not a function.`],Yt=/* @__PURE__ */ new Map([[`bash`,"`bash` rejects on a non-zero exit rather than resolving with its output."],[`write`,"`write` always reports `details: null`."],[`edit`,"`edit` always reports a `details` object carrying `diff` and `patch`."],[V,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),Xt=[Jt.join(`
9
+ `),`Exceptions: `+[...Yt.values()].join(` `)].join(`
10
+ `),Zt=`pi-ptc-output-`;function Qt(e,t=Zt){let n=k(re(),`${t}${j()}.txt`);return te(n,e,`utf8`),n}function $t(e,t){let n=e.totalLines-e.outputLines+1,r=e.totalLines;return e.lastLinePartial?`[Showing last ${_(e.outputBytes)} of line ${r}. Full output: ${t}]`:e.truncatedBy===`lines`?`[Showing lines ${n}-${r} of ${e.totalLines}. Full output: ${t}]`:`[Showing lines ${n}-${r} of ${e.totalLines} (${_(s)} limit). Full output: ${t}]`}function en(e,t=Zt,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Qt(n.fullText??e,t);return{text:`${r.content}\n\n${$t(r,i)}`,truncated:!0,fullPath:i}}const tn=200,nn=new RegExp([`(?:\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\u005C|\\u009C))`,`[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]`].join(`|`),`g`);function rn(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(nn,``)}function G(e){let t=rn(e).replace(/\r/g,``);if(t.length===0)return t;let n=``;for(let e of t){let t=e.codePointAt(0);if(t!==void 0){if(t===10||t===9){n+=e;continue}t<=31||t>=65529&&t<=65531||(n+=e)}}return n}const an=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function on(e){return an.test(e)?e:JSON.stringify(e)}function sn(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=G(e);return t.includes(`
11
+ `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=sn(n);if(e===void 0)return;t.push(e)}return`[${t.join(`, `)}]`}let t=Object.keys(e);if(t.length===0)return`{}`;let n=[];for(let r of t){let t=sn(e[r]??null);if(t===void 0)return;n.push(`${on(r)}: ${t}`)}return`{${n.join(`, `)}}`}function cn(e){let t=sn(e);if(t!==void 0)return t.length<=100?t:void 0}function ln(e){return e===null?`null`:typeof e==`string`?G(e):String(e)}function un(e,t){if(typeof e!=`object`||!e)return[`${t}${ln(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=cn(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...dn(r,t+` `))}return n.push(`${t}]`),n}let n=Object.keys(e);if(n.length===0)return[`${t}{}`];let r=[`${t}{`],i=t+` `;for(let t of n){let n=e[t]??null,a=cn(n);if(a!==void 0){r.push(`${i}${on(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${on(t)}:`);for(let e of G(n).split(`
12
+ `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=un(n,i);r.push(`${i}${on(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function dn(e,t){return typeof e==`string`?G(e).split(`
13
+ `):typeof e!=`object`||!e?[String(e)]:un(e,t)}function fn(e){return e.split(`
12
14
  `).map(e=>e.length>200?`${e.slice(0,199)}…`:e).join(`
13
- `)}function an(e){if(typeof e==`string`)return rn(K(e));if(typeof e!=`object`||!e)return String(e);let t=$t(e);return rn((t===void 0?nn(e,``):[t]).join(`
14
- `))}function on(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function sn(e=process.env){let t=e.PI_PTC_TASK_ID;if(t!==void 0&&/^[0-9A-HJKMNP-TV-Z]{26}$/.test(t))return t}function q(e){if(e===void 0)return V;let t=new Set(e);return V.filter(e=>t.has(e))}const cn=["Image-bearing tool results inside a program (a `tools.read` on a PNG, say) are attached to you after the run — never return image data as the completion value.",`Use ptc_run_code when a task needs several tool calls whose intermediate output you do not need to see — gather it inside the program and return only the final value.`,`Use ptc_workflow instead of ptc_run_code when the work has named phases and the user benefits from seeing progress narration.`],ln={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function un(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function dn(e){let{surface:t,startedAt:n,onUpdate:r}=e;if(r===void 0)return{update:()=>{},cancel:()=>{}};let i=0,a,o,s=()=>{if(o===void 0)return;let e=o;o=void 0,i=Date.now(),r({content:[],details:{surface:t,logs:[],narrations:[],phases:[],warnings:[],durationMs:Date.now()-n,imageCount:0,subCalls:e()}})};return{update(e){o=e;let t=100-(Date.now()-i);if(t<=0){a!==void 0&&(clearTimeout(a),a=void 0),s();return}a??=setTimeout(()=>{a=void 0,s()},t)},cancel(){a!==void 0&&(clearTimeout(a),a=void 0),o=void 0}}}function fn(e){return[...e.phases.map(e=>`[phase] ${K(e)}`),...e.narrations.map(e=>`[log] ${K(e)}`),...e.logs.map(e=>K(e))]}function pn(e){let t=e.error;if(t===void 0)return/* @__PURE__ */ Error(`internal error: a successful PTC run was rendered as a failure`);let n=fn(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
15
- `)}`,i=Error(K(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function mn(e){let{outcome:t,surface:n}=e,r=[...e.warnings??[]],i=t.images??[],a=[];t.phases.length>0&&a.push(`Phases: ${t.phases.map(e=>K(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>K(e)).join(`
16
- `)),t.logs.length>0&&a.push(t.logs.map(e=>K(e)).join(`
17
- `)),t.value!==void 0&&a.push(an(t.value));for(let e of r)a.push(`Warning: ${K(e)}`);let o=Kt(a.length>0?a.join(`
18
- `):`(${ln[n]} completed with no output)`),s=o.text,c=o.truncated?o.fullPath:void 0;return{content:[{type:`text`,text:s},...i.map(e=>({type:`image`,data:e.data,mimeType:e.mimeType}))],details:{surface:n,logs:[...t.logs],narrations:[...t.narrations],phases:[...t.phases],warnings:r,...t.value===void 0?{}:{result:t.value},durationMs:e.durationMs,imageCount:i.length,...c===void 0?{}:{fullOutputPath:c},...t.subCalls===void 0?{}:{subCalls:t.subCalls}}}}const hn=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function gn(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function _n(e,t){if(e.charCodeAt(t)!==27)return t;let n=e.charCodeAt(t+1);if(n===93){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t===7)return n+1;if(t===27&&e.charCodeAt(n+1)===92)return n+2;n+=1}return n}if(n===91){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t>=64&&t<=126)return n+1;n+=1}return n}return t+2}function vn(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=_n(e,n):(n+=1,r+=1);return n}function yn(e,t){let n=t.intervalMs??150,{state:r}=t;t.isPartial?(r.startedAt??=Date.now(),r.interval??=setInterval(()=>t.requestInvalidate(),n)):(r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0),r.startedAt=void 0);let i=e.render.bind(e),a=e;return a.render=e=>{let a=i(e);return r.startedAt===void 0?a:bn(a,Math.floor((Date.now()-r.startedAt)/n),t.theme)},a.dispose=()=>{r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0)},e}function bn(e,t,n){return e.map(e=>{let r=gn(e),i=hn.exec(r);if(i===null)return e;let a=(i[3]??``).slice(1);if(a.length===0)return e;let o=t%(a.length+1),s=i[0].length-a.length,c=vn(e,s),l=vn(e,s+a.length),u=o>=a.length?n.fg(`dim`,a):`${o>0?n.fg(`dim`,a.slice(0,o)):``}${n.fg(`accent`,a.slice(o,o+1))}${n.fg(`dim`,a.slice(o+1))}`;return`${e.slice(0,c)}${u}${e.slice(l)}`})}const xn={run_code:`PTC`,workflow:`PTC workflow`};var Sn=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>Cn(e,t))}};function Cn(e,t){let{left:n,right:r}=e;if(r===void 0)return I(n,t,`…`);let i=L(r);if(i>=t)return I(r,t,`…`);let a=I(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-L(a));return a+` `.repeat(o)+r}function J(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function wn(e){return J((K(e).split(`
19
- `).find(e=>e.trim().length>0)??``).trim(),120)}function Tn(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function En(e,t){return`${e} ${t}${e===1?``:`s`}`}function Dn(e){for(let t of e.split(`
20
- `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return J(e.replace(/\s*\/\/.*$/,``),120)}}function On(e){if(e===void 0)return;if(typeof e==`string`){let t=K(e).split(`
21
- `),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:J(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=an(e);if(!t.includes(`
22
- `)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function kn(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,En(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,En(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,En(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,En(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Tn(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function An(e){if(e!==void 0)return{surface:e.surface??`run_code`,logs:e.logs??[],narrations:e.narrations??[],phases:e.phases??[],warnings:e.warnings??[],durationMs:e.durationMs??0,imageCount:e.imageCount??0,...e.result===void 0?{}:{result:e.result},...e.fullOutputPath===void 0?{}:{fullOutputPath:e.fullOutputPath},...e.subCalls===void 0?{}:{subCalls:e.subCalls}}}function jn(e,t,n){let r=` `+(t?`└─ `:`├─ `),i=` `+(t?` `:`│ `),a=` `.repeat(8),o=[],s=e.lines[0]??``;o.push({left:`${r}${e.label.padEnd(8)}${n.fg(`dim`,s)}`});for(let t=1;t<e.lines.length;t++)o.push({left:`${i}${a}${n.fg(`dim`,e.lines[t]??``)}`});return e.more!==void 0&&e.more>0&&o.push({left:`${i}${a}…+${e.more} more lines`}),o}function Mn(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const Nn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Pn(e){return Nn.test(e)?e:JSON.stringify(e)}function Fn(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=K(e);if(n.length===0)return`""`;if(n.includes(`
23
- `)){let e=J(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(J(n,Math.max(2,t-5)))+`…`}return`?`}function In(e){return typeof e!=`object`||!e}function Ln(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(In))return;let n=`[`+e.map(e=>Fn(e,Math.max(2,Math.floor(t/4)))).join(`, `)+`]`;return n.length<=t?n:void 0}if(typeof e!=`object`||!e)return;let n=Object.keys(e);if(n.length===0)return`{}`;if(n.length>5||!Object.values(e).every(In))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Pn(n)+`: `+Fn(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Rn(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(Y(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(Y(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(Y(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-L(l)-t.length);c.push(Y(l+t+Fn(e,n),o));return}let d=Ln(e,Math.max(0,o-L(l)-t.length));if(d!==void 0){c.push(Y(l+t+d,o));return}let f=Array.isArray(e),p=f?e.length:Object.keys(e).length,m;m=f?`Array(`+p+`)`:p>a?`{`+a+` of `+p+`}`:`{`+p+` keys}`,c.push(Y(l+t+m,o));let h=Math.min(a,p);if(f)for(let t=0;t<h;t+=1){let n=t===h-1&&p<=h;Rn(e[t]??null,`[`+t+`] `,u,n,i,a,o,s+1,c)}else{let t=Object.keys(e);for(let n=0;n<h;n+=1){let r=n===h-1&&p<=h,l=t[n];Rn(e[l]??null,Pn(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(Y(u+`└─ …+`+(p-h)+` more `+e,o))}}function Y(e,t){if(L(e)<=t)return e;let n=e.match(/^([\s│├└─]*)/),r=n&&n[1]?n[1]:``,i=L(r),a=Math.max(0,t-i-1),o=``,s=0;for(let t of e.slice(r.length)){let e=L(t);if(s+e>a)break;o+=t,s+=e}return r+o+`…`}function zn(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Mn(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Fn(e,i)];let o=[];if(Array.isArray(e)){let t=e.length,s=Math.min(r,t);for(let c=0;c<s;c+=1){let l=!a&&c===s-1&&t<=s;Rn(e[c]??null,`[`+c+`] `,``,l,n,r,i,0,o)}return t>s&&o.push((a?`├─ `:`└─ `)+`…+`+(t-s)+` more items`),o}let s=Object.keys(e),c=s.length,l=Math.min(r,c);for(let t=0;t<l;t+=1){let u=!a&&t===l-1&&c<=l,d=s[t];Rn(e[d]??null,Pn(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}function Bn(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Dn(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return yn(new Sn([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(xn[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??Vn,state:r.state??{}})}function Vn(){}function Hn(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return wn(t?.text??``)||`failed`}function Un(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t&&`agent`in t)return`→ ${String(t.agent)}`;if(typeof t==`object`&&t){let n=t,r=e=>typeof n[e]==`string`?n[e]:void 0,i=e===`read`?r(`path`):e===`bash`?r(`command`):e===`grep`||e===`find`?r(`pattern`):e===`ls`||e===`edit`||e===`write`?r(`path`):void 0;if(typeof i==`string`)return i}try{let e=JSON.stringify(t).replace(/\n/g,` `);return e.length>40?`${e.slice(0,39)}…`:e}catch{return String(t).slice(0,40)}}const Wn={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Tn(e.durationMs)}`,themeSlot:`accent`},error:{text:e=>`failed: ${e.errorMessage??`error`}`,themeSlot:`error`},cancelled:{text:()=>`cancelled`,themeSlot:`muted`},rejected:{text:e=>`rejected: ${e.errorMessage??`concurrency`}`,themeSlot:`warning`}};function Gn(e,t){if(e.length===0)return[];let n=e.slice(0,32),r=e.length>32?e.length-32:0,i=[];return n.forEach((e,a)=>{let o=a===n.length-1&&r===0?`└─ `:`├─ `,s=e.name.length>=8?`${e.name} `:e.name.padEnd(8),c=Un(e.name,e.args),l=Wn[e.status];i.push({left:` ${o}${t.fg(`toolTitle`,s)}${t.fg(l.themeSlot,l.text(e))}${t.fg(`dim`,` `+c)}`})}),r>0&&i.push({left:` └─ …+${r} more calls`}),i}function Kn(e,t,n,r=!1,i=!1){let a=kn(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${Hn(e)}`)}`})];if(i&&e.details?.result===void 0)return[];let s=e.details?.result;if(s===void 0)return[o({left:` ${n.fg(`muted`,`done`)}`})];if(Mn(s))return zn(s,{maxDepth:4,maxChildren:6,maxLineChars:120,moreAfter:r}).map((e,t)=>{let n={left:` ${e}`};return t===0&&a!==void 0?{...n,right:a}:n});let c=On(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function qn(e,t,n,r={}){let i=An(e.details),a=[...Kn({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...Gn(i.subCalls,n)),new Sn(a)}function Jn(e,t,n,r,i={}){let a=An(e.details);if(n){let t=[...Kn({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...Gn(a.subCalls,r));let n=K(e.content?.find(e=>e.type===`text`)?.text??Hn(e));for(let e of n.split(`
24
- `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new Sn(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
25
- `).map(e=>J(e,120)),t=e.slice(0,3);o.push({label:`code`,lines:t,...e.length>t.length?{more:e.length-t.length}:{}})}if(a!==void 0&&a.surface===`workflow`&&a.phases.length>0){let e=a.phases.slice(0,8),t=a.phases.length-e.length,n=t>0?` …+${t} more phases`:``;o.push({label:`phases`,lines:[`${e.join(` → `)}${n}`]})}if(a!==void 0&&a.narrations.length>0){let e=a.narrations.slice(0,12);o.push({label:`log`,lines:e.map(e=>K(e)),...a.narrations.length>e.length?{more:a.narrations.length-e.length}:{}})}if(a!==void 0&&a.logs.length>0){let e=a.logs.slice(0,12);o.push({label:`out`,lines:e.map(e=>K(e)),...a.logs.length>e.length?{more:a.logs.length-e.length}:{}})}if(a!==void 0&&a.warnings.length>0){let e=a.warnings.slice(0,4);o.push({label:`warn`,lines:e.map(e=>K(e)),...a.warnings.length>e.length?{more:a.warnings.length-e.length}:{}})}if(a!==void 0&&a.imageCount>0){let e=a.imageCount===1?`1 image attached`:`${a.imageCount} images attached`;o.push({label:`image`,lines:[e]})}let c=a?.subCalls,l=c!==void 0&&c.length>0||o.length>0,u=Kn({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...Gn(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...jn(o[e]??{label:``,lines:[]},t,r))}return new Sn(u)}function Yn(e){return{renderCall(t,n,r){return Bn(t,n,e,{...r?.invalidate===void 0?{}:{requestInvalidate:r.invalidate},...r?.isPartial===void 0?{}:{isPartial:r.isPartial},...r?.state===void 0?{}:{state:r.state}})},renderResult(e,t,n,r){let i=t.isPartial===!0;return t.expanded===!0?Jn(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):qn(e,r?.isError===!0,n,{isPartial:i})}}}const Xn=["Run a TypeScript program that composes pi's tools in one shot. Required arguments: `code` —","the body of an async function (top-level `return` and `await` work; type annotations are","advisory, the code runs type-stripped) — and `description`, a 5-10 word summary of what the",`program does.`,``,"Inside the program, call this session's enabled built-in tools as `tools.<name>(args)` — e.g.",'`await tools.read({ path: "src/index.ts" })` or `await tools.bash({ command: "npm test" })`.',"The bound names mirror the session's active tools (a default session has `read`, `bash`, `edit`,","`write`); calling a name that is not bound rejects with an error the program can catch, and","independent calls may overlap under `Promise.all`.",``,"The parallel binding `pi.dispatch` is always available, registered under its literal dot name —",'call it with string indexing, e.g. `await tools["pi.dispatch"]({ agent: "reviewer", task: "..." })`;',"`tools.pi.dispatch` does not exist. It fans work out to child pi agents, and independent","foreground dispatches compose under `Promise.all` exactly like the built-in calls. The run's","actual bound names (this run, not a static list) are on the `ptcBindings` global, so the program",`never has to guess what is bound.`,``,"Only the program's return value and its `console.log` output come back. This surface has no","helpers: `log` / `phase` / `parallel` / `pipeline` exist only in `ptc_workflow`.",``,"Image-bearing tool results inside the program (a `tools.read` on a PNG, say) are attached to you",`after the run, so never return image data as the completion value — that only spends your context`,`on base64.`].join(`
26
- `),Zn=x.Object({code:x.String({description:`The program: the body of an async TypeScript function.`}),description:x.String({description:`Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI).`}),timeoutMs:x.Optional(x.Number({description:`Elapsed deadline in milliseconds for the whole run, including tool calls. Omit it (or pass 0) for the default of ${z.timeoutMs/1e3} s; anything above ${z.maxTimeoutMs/1e3} s is capped. The deadline bounds the whole run: if it expires, in-flight foreground dispatches spawned by the program are terminated with it.`}))});function Qn(e={}){return g({name:`ptc_run_code`,label:`PTC Run Code`,description:Xn,promptSnippet:`Run a TypeScript program that composes pi's tools in one shot (tools.<name>(args)); only its return value and console.log come back`,promptGuidelines:[...cn],parameters:Zn,async execute(t,n,r,i,a){let o=un(a),s=q(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=dn({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await Ht({code:n.code,surface:`run_code`,cwd:o,bindings:kt({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...n.timeoutMs===void 0?{}:{timeoutMs:n.timeoutMs},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw pn(p);return mn({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...Yn(`run_code`)})}const $n=[`Run a structured TypeScript workflow: a named plan that reports phases and narration as it`,"goes. `script` is the body of an async function, `meta` names it (`{ name, description, phases? }`,","where `phases` is the ordered plan), and optional `args` is plain-JSON input bound to the","program's `args` global.",``,"Helpers inside the script: `log(message)` narrates progress; `phase(title)` frames the workflow","(titles outside `meta.phases` are reported as warnings); `parallel(thunks)` runs thunks","concurrently, a failed item becoming `null`; `pipeline(items, ...stages)` chains stages per item","with the same per-item `null` on failure. There is no `agent()` helper.",``,"Tools are reachable as `tools.<name>(args)` exactly as in `ptc_run_code`, and the bound names","mirror the session's enabled tools. The parallel binding `pi.dispatch` is always available under",'its literal dot name — call it with string indexing: `await tools["pi.dispatch"]({ agent, task })`;',"the run's actual bound names are on the `ptcBindings` global. What comes back is the script's","return value, its `log`/`phase` narration and its `console.log` output.",``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
27
- `),er=x.Object({meta:x.Object({name:x.String({description:`Short workflow name, shown in the UI.`}),description:x.String({description:`What this workflow does, in active voice.`}),phases:x.Optional(x.Array(x.Object({name:x.String({description:`Phase title, matched against phase(title) calls.`})}),{description:`Ordered plan of the workflow's phases. phase() titles outside this list are reported as warnings.`}))},{description:`Workflow metadata: what this run is and which phases it declares.`}),script:x.String({description:`The program: the body of an async TypeScript function.`}),args:x.Optional(x.Record(x.String(),x.Unknown(),{description:"Plain-JSON input bound to the program's `args` global. No functions, symbols, undefined values or cycles."}))});function tr(t){if(t!==void 0){if(typeof t!=`object`||!t||Array.isArray(t))throw TypeError(`ptc_workflow args must be a plain JSON object, received ${e(t)}`);for(let e of Object.keys(t)){let n=nr(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function nr(t,n,r){if(t===null||typeof t==`string`||typeof t==`boolean`)return;if(t===void 0)return`${n} is undefined`;if(typeof t==`number`)return Number.isFinite(t)?void 0:`${n} is ${String(t)}, which is not representable as JSON`;if(typeof t!=`object`)return`${n} is ${e(t)}`;let i=t;if(r.has(i))return`${n} is a circular reference`;r.add(i);try{if(Array.isArray(i)){for(let e=0;e<i.length;e+=1){let t=nr(i[e],`${n}[${e}]`,r);if(t!==void 0)return t}return}let e=Object.getPrototypeOf(i);if(e!==Object.prototype&&e!==null){let e=i.constructor?.name;return`${n} is a ${typeof e==`string`&&e.length>0?e:`non-plain object`}, not plain JSON`}for(let e of Object.keys(i)){let t=nr(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function rr(e,t){if(t===void 0||t.length===0)return[];let n=new Set(t),r=/* @__PURE__ */ new Set,i=[];for(let t of e.phases)n.has(t)||r.has(t)||(r.add(t),i.push(`phase "${t}" is not listed in meta.phases (declared: ${[...n].join(`, `)})`));return i}function ir(e={}){return g({name:`ptc_workflow`,label:`PTC Workflow`,description:$n,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...cn],parameters:er,async execute(t,n,r,i,a){tr(n.args);let o=un(a),s=q(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=dn({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await Ht({code:n.script,surface:`workflow`,cwd:o,bindings:kt({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...n.args===void 0?{}:{args:n.args},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw pn(p);let m=n.meta.phases?.map(e=>e.name);return mn({outcome:p,surface:`workflow`,warnings:rr(p,m),durationMs:Date.now()-c})},...Yn(`workflow`)})}var ar=class{#e;constructor(e){this.#e=new Map(e??[])}async readOutput(e){let t=this.#e.get(e);return t===void 0?null:t}async writeOutput(e,t){this.#e.set(e,t)}outputRef(e){return`memory:tasks/${e}/output.log`}};function or(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var sr=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await R(this.#t(e),`utf8`)}catch(e){if(or(e))return null;throw e}}async writeOutput(e,t){let n=k(this.#e,`tasks`,e);await se(n,{recursive:!0}),await de(k(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return k(this.#e,`tasks`,e,`output.log`)}};function cr(e,t){return Kt(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const lr={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},ur={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var X=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>dr(e,t))}};function dr(e,t){let{left:n,right:r}=e;if(r===void 0)return I(n,t,`…`);let i=L(r);if(i>=t)return I(r,t,`…`);let a=I(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-L(a));return a+` `.repeat(o)+r}function fr(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function pr(e){return fr((K(e).split(`
28
- `).find(e=>e.trim().length>0)??``).trim(),120)}function mr(e){return typeof e==`object`&&e?e:{}}function hr(e){return e===`running`||e===`stopping`}function gr(e){let t=Math.max(0,Math.floor(e));if(t<1e3)return`${t}ms`;let n=Math.floor(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;return r<60?`${r}m${i}s`:`${Math.floor(r/60)}h${String(r%60).padStart(2,`0`)}m`}function _r(e,t){if(hr(e.status))return gr(t-e.createdAt);if(e.durationMs!==void 0)return gr(e.durationMs);if(e.finishedAt!==void 0)return gr(e.finishedAt-e.createdAt)}function vr(e,t){let{state:n}=t;t.isLive?n.interval??=setInterval(()=>t.requestInvalidate(),1e3):n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0);let r=e;return r.dispose=()=>{n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0)},e}function yr(){}function br(e,t,n){return new X([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function xr(e,t,n){let r=mr(t);switch(e){case`task-list`:{let e=Array.isArray(r.status)?r.status:void 0,t=e!==void 0&&e.length>0?e.join(`,`):`all`,i=typeof r.limit==`number`?` · limit=${r.limit}`:``;return br(`PTC task list`,n.fg(`dim`,`status=${t}${i}`),n)}case`task-output`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.sinceBytes==`number`?` · since=${r.sinceBytes}B`:``;return br(`PTC task output`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}case`task-stop`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.reason==`string`&&r.reason.length>0?` · reason=${K(r.reason)}`:``;return br(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Sr(e,t,n,r){let i=lr[e.status]??`muted`,a=n.fg(i,ur[e.status]??`?`),o=fr(K(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,K(e.agentName))],c=_r(e,r);return c!==void 0&&s.push(n.fg(`dim`,c)),e.outputBytes!==void 0&&s.push(n.fg(`dim`,`${e.outputBytes}B`)),{left:` ${t?`└─ `:`├─ `}${s.join(n.fg(`dim`,` · `))}`}}function Cr(e,t){let n=mr(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return vr(new X([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>hr(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>Sr(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),vr(new X(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function wr(e,t,n){let r=[];if(e!==void 0&&r.push(n.fg(`dim`,`${e}B`)),t&&r.push(n.fg(`warning`,`truncated`)),r.length!==0)return`${n.fg(`dim`,`•`)} ${r.join(n.fg(`dim`,` · `))}`}function Tr(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Er(e,t){let n=mr(e),r=typeof n.output==`string`?n.output:``,i=typeof n.outputBytes==`number`?n.outputBytes:void 0,a=n.outputTruncated===!0,o=typeof n.outputFullPath==`string`&&n.outputFullPath.length>0?n.outputFullPath:void 0,s=wr(i,a,t.theme),c=[];if(r.length>0){let e=K(r).split(`
29
- `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,fr(e,160));c.push(n===0&&s!==void 0?{left:` ${r}`,right:s}:{left:` ${r}`})}),e.length>n.length&&c.push({left:` ${t.theme.fg(`dim`,`…+${e.length-n.length} more lines`)}`}),a&&o!==void 0&&c.push({left:Tr(o,t.theme)})}else o===void 0?c.push({left:` ${t.theme.fg(`muted`,`(no output yet)`)}`,...s===void 0?{}:{right:s}}):c.push({left:Tr(o,t.theme),...s===void 0?{}:{right:s}});return new X(c)}function Dr(e,t){let n=mr(e),r=n.task;if(typeof r!=`object`||!r)return new X([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=lr[r.status]??`muted`,a=t.theme.fg(i,ur[r.status]??`?`),o=typeof n.fromStatus==`string`?n.fromStatus:void 0,s=o===void 0?r.status===`stopping`?`running → stopping`:`→ ${String(r.status)}`:`${o} → ${r.status}`,c=[`${a} ${t.theme.fg(`text`,K(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${K(r.stopReason)}`)),new X([{left:` ${c.join(` `)}`}])}function Or(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=pr(n?.text??``)||`failed`;return new X([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function kr(e,t,n){switch(e){case`task-list`:return Cr(t.details,n);case`task-output`:return Er(t.details,n);case`task-stop`:return Dr(t.details,n)}}function Ar(e){return{renderCall(t,n){return xr(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Or(t,r):kr(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??yr,state:i?.state??{},now:Date.now()})}}}const jr=[`Use ptc_task_list to see the background tasks this session dispatched and their live status.`,`Use ptc_task_output to read a task's captured output (it is tail-truncated; the footer names the full-output file).`,`Use ptc_task_stop to ask a running task to stop; the dispatcher delivers the actual signal, so the task transitions through stopping to canceled.`,`These background-task tools stay callable when PTC mode is off — /ptc off only blocks new dispatches.`],Mr=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Nr=x.Object({status:x.Optional(x.Array(Mr,{description:`Only return tasks in these states. Omit for all six states (running, stopping, succeeded, failed, canceled, lost).`})),limit:x.Optional(x.Number({description:`Maximum number of tasks to return, newest first. Defaults to 100.`}))});function Pr(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,K(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${K(e.errorMessage)}`),t.join(` `)}function Fr(e){return g({name:`ptc_task_list`,label:`PTC Task List`,description:[`List the background tasks this session has dispatched (from pi.dispatch({ background: true })).`,`Returns each task's id, status, agent, depth, label and output size, newest first.`,`Filter with status (e.g. ["running"]); limit caps the row count (default 100).`].join(`
30
- `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...jr],parameters:Nr,async execute(t,n){let r=await e.query({...n.status===void 0?{}:{status:n.status},limit:n.limit??100,orderBy:`createdAt-desc`});return{content:[{type:`text`,text:r.length===0?`(no background tasks)`:r.map(e=>Pr(e)).join(`
31
- `)}],details:{tasks:r,count:r.length}}},...Ar(`task-list`)})}async function Ir(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}const Lr=x.Object({taskId:x.String({description:`The background task's id (as returned by ptc_task_list or the dispatch handle).`}),sinceBytes:x.Optional(x.Number({description:`Skip this many bytes of the stored output before returning it. Use for paging larger logs; defaults to 0.`}))});function Rr(e,t){return g({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
32
- `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...jr],parameters:Lr,async execute(n,r){let i=r.taskId,a=await Ir(e,i,`ptc_task_output`),o=await t.readOutput(i)??``,s=Buffer.byteLength(o,`utf8`),c=r.sinceBytes??0;if(!Number.isInteger(c)||c<0)throw Error(`ptc_task_output: sinceBytes must be a non-negative integer, got ${String(r.sinceBytes)}`);if(c>s)throw Error(`ptc_task_output: sinceBytes ${c} exceeds the ${s}-byte output of task ${i}`);let l=Buffer.from(o,`utf8`);if(c<s&&((l[c]??0)&192)==128)throw Error(`ptc_task_output: sinceBytes ${c} splits a UTF-8 character in task ${i}; use a byte offset on a character boundary`);let u=cr(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath}};return{content:[{type:`text`,text:f.output.length>0?f.output:`(no output yet; task ${i} is ${a.status})`}],details:f}},...Ar(`task-output`)})}const zr=x.Object({taskId:x.String({description:`The running task's id (as returned by ptc_task_list or the dispatch handle).`}),reason:x.Optional(x.String({description:`Why the task is being stopped; recorded as the task's stopReason. Defaults to "model stop".`}))});function Br(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return g({name:`ptc_task_stop`,label:`PTC Task Stop`,description:[`Ask a running background task to stop.`,`The task moves to "stopping"; the dispatcher sends the signal and records the terminal "canceled" state when the child exits.`,`The call is idempotent when the task is already stopping, and errors when the task is already terminal.`].join(`
33
- `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...jr],parameters:zr,async execute(t,n){let i=n.taskId,a=await Ir(e,i,`ptc_task_stop`),o=a.spawnSource.callerId.length>0?a.spawnSource.callerId:`ptc_task_stop`,{record:s,fromStatus:c}=await e.transition({kind:`stop`,taskId:i,reason:n.reason??`model stop`},{clock:r,callerId:o}),l=s.stopReason===void 0?``:` reason=${K(s.stopReason)}`;return{content:[{type:`text`,text:`${s.id} ${s.status}${l}`}],details:{task:s,fromStatus:c??a.status}}},...Ar(`task-stop`)})}var Vr=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=ke(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Oe(),r=new Mt({buildWorkerUrl:Ft,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:jt({surface:e,env:n,limits:this.#e})});return this.#t.set(e,r),r}async drain(){let e=[...this.#t.values()];this.#t.clear(),await Promise.all(e.map(e=>e.drain()))}};const Hr={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var Ur=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??Hr,this.#r=[],this.#i=/* @__PURE__ */ new Map}async subscribe(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r!==null)return r;let i={subscriberId:e,taskId:t,cursor:n??`00000000000000000000`,status:`active`,createdAt:this.#t()};return await this.#e.saveSubscription(i),i}async drainPending(e,t){let n=await this.#o(e,t,`drainPending`);return this.#s(n)}async acknowledgeEvents(e,t,n){await this.#a(e,t,async()=>{let r=await this.#o(e,t,`acknowledgeEvents`);n<=r.cursor||await this.#e.saveSubscription({...r,cursor:n})})}#a(e,t,n){let r=`${e}-${t}`,i=(this.#i.get(r)??Promise.resolve()).then(n),a=i.then(()=>void 0,()=>void 0);return this.#i.set(r,a),a.then(()=>{this.#i.get(r)===a&&this.#i.delete(r)}),i}onIdleWake(e){this.#r.push(e)}async pendingCount(e,t){let n=await this.#o(e,t,`pendingCount`);return(await this.#s(n)).length}async notifyIdle(e,t){let n=await this.drainPending(e,t);if(n.length===0)return n;let r=this.#r.slice();for(let i of r)try{i(e,n)}catch(n){let r=n instanceof Error?n.message:String(n);this.#n.warn(`notifyIdle: idle-wake handler for subscriber ${e} / task ${t} threw: ${r}`)}return n}async#o(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r===null)throw Error(`${n}: unknown subscription for subscriber ${e} / task ${t}`);return r}async#s(e){let t=[];for await(let n of this.#e.loadEvents(e.subscriberId,e.cursor===`00000000000000000000`?void 0:e.cursor))n.taskId===e.taskId&&t.push(n);return t}};const Wr={mkdir:(e,t)=>se(e,t),readFile:(e,t)=>R(e,t),writeFile:(e,t,n)=>de(e,t,n),appendFile:(e,t,n)=>oe(e,t,n),rename:(e,t)=>le(e,t),unlink:e=>ue(e),readdir:e=>ce(e)};function Gr(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function Kr(e){return e instanceof Error?e.message:String(e)}function qr(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var Jr=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??Wr}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){M(e,`saveTask: record is required`),await this.#o(this.#f(e.id),e)}async deleteTask(e){let t=this.#f(e);if(!await this.#c(t))throw Error(`deleteTask: unknown taskId `+e);await this.#t.unlink(t)}async*listTasks(e){let t=this.#l();for(let n of(await this.#s(t)).sort()){if(!n.endsWith(`.json`))continue;let r=await this.#r(k(t,n));r!==null&&(e?.status===void 0||r.status===e.status)&&(e?.label===void 0||r.label===e.label)&&(yield r)}}async loadSubscription(e,t){return await this.#r(this.#p(e,t))}async saveSubscription(e){M(e,`saveSubscription: sub is required`),await this.#o(this.#p(e.subscriberId,e.taskId),e)}async appendEvents(e,t){if(t.length===0){if((await this.#n(e)).length===0)throw Error(`appendEvents: unknown subscriptionId `+e);return}let n=/* @__PURE__ */ new Map;for(let e of t){let t=n.get(e.taskId);t===void 0?n.set(e.taskId,[e]):t.push(e)}let r;for(let t of n.keys())if(await this.loadSubscription(e,t)===null){r=t;break}if(r!==void 0)throw(await this.#n(e)).length===0?Error(`appendEvents: unknown subscriptionId `+e):Error(`appendEvents: no subscription for subscriber `+e+` on task `+r);await this.#t.mkdir(this.#d(),{recursive:!0});for(let[t,r]of n){let n=(r.every((e,t)=>t===0||qr(r[t-1],e)<=0)?r:[...r].sort(qr)).map(e=>JSON.stringify(e)).join(`
15
+ `)}function pn(e){if(typeof e==`string`)return fn(G(e));if(typeof e!=`object`||!e)return String(e);let t=cn(e);return fn((t===void 0?dn(e,``):[t]).join(`
16
+ `))}function mn(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function hn(e=process.env){let t=e.PI_PTC_TASK_ID;if(t!==void 0&&/^[0-9A-HJKMNP-TV-Z]{26}$/.test(t))return t}function K(e){if(e===void 0)return B;let t=new Set(e);return B.filter(e=>t.has(e))}const gn=["Image-bearing tool results inside a program (a `tools.read` on a PNG, say) are attached to you after the run — never return image data as the completion value.",`Use ptc_run_code when a task needs several tool calls whose intermediate output you do not need to see — gather it inside the program and return only the final value.`,`Use ptc_workflow instead of ptc_run_code when the work has named phases and the user benefits from seeing progress narration.`],_n={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function vn(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function yn(e){let{surface:t,startedAt:n,onUpdate:r}=e;if(r===void 0)return{update:()=>{},cancel:()=>{}};let i=0,a,o,s=()=>{if(o===void 0)return;let e=o;o=void 0,i=Date.now(),r({content:[],details:{surface:t,logs:[],narrations:[],phases:[],warnings:[],durationMs:Date.now()-n,imageCount:0,subCalls:e()}})};return{update(e){o=e;let t=100-(Date.now()-i);if(t<=0){a!==void 0&&(clearTimeout(a),a=void 0),s();return}a??=setTimeout(()=>{a=void 0,s()},t)},cancel(){a!==void 0&&(clearTimeout(a),a=void 0),o=void 0}}}function bn(e){return[...e.phases.map(e=>`[phase] ${G(e)}`),...e.narrations.map(e=>`[log] ${G(e)}`),...e.logs.map(e=>G(e))]}function xn(e){let t=e.error;if(t===void 0)return/* @__PURE__ */ Error(`internal error: a successful PTC run was rendered as a failure`);let n=bn(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
17
+ `)}`,i=Error(G(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function Sn(e){let{outcome:t,surface:n}=e,r=[...e.warnings??[]],i=t.images??[],a=[];t.phases.length>0&&a.push(`Phases: ${t.phases.map(e=>G(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>G(e)).join(`
18
+ `)),t.logs.length>0&&a.push(t.logs.map(e=>G(e)).join(`
19
+ `)),t.value!==void 0&&a.push(pn(t.value));for(let e of r)a.push(`Warning: ${G(e)}`);let o=en(a.length>0?a.join(`
20
+ `):`(${_n[n]} completed with no output)`),s=o.text,c=o.truncated?o.fullPath:void 0;return{content:[{type:`text`,text:s},...i.map(e=>({type:`image`,data:e.data,mimeType:e.mimeType}))],details:{surface:n,logs:[...t.logs],narrations:[...t.narrations],phases:[...t.phases],warnings:r,...t.value===void 0?{}:{result:t.value},durationMs:e.durationMs,imageCount:i.length,...c===void 0?{}:{fullOutputPath:c},...t.subCalls===void 0?{}:{subCalls:t.subCalls}}}}const Cn=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function wn(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function Tn(e,t){if(e.charCodeAt(t)!==27)return t;let n=e.charCodeAt(t+1);if(n===93){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t===7)return n+1;if(t===27&&e.charCodeAt(n+1)===92)return n+2;n+=1}return n}if(n===91){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t>=64&&t<=126)return n+1;n+=1}return n}return t+2}function En(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=Tn(e,n):(n+=1,r+=1);return n}function Dn(e,t){let n=t.intervalMs??150,{state:r}=t;t.isPartial?(r.startedAt??=Date.now(),r.interval??=setInterval(()=>t.requestInvalidate(),n)):(r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0),r.startedAt=void 0);let i=e.render.bind(e),a=e;return a.render=e=>{let a=i(e);return r.startedAt===void 0?a:On(a,Math.floor((Date.now()-r.startedAt)/n),t.theme)},a.dispose=()=>{r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0)},e}function On(e,t,n){return e.map(e=>{let r=wn(e),i=Cn.exec(r);if(i===null)return e;let a=(i[3]??``).slice(1);if(a.length===0)return e;let o=t%(a.length+1),s=i[0].length-a.length,c=En(e,s),l=En(e,s+a.length),u=o>=a.length?n.fg(`dim`,a):`${o>0?n.fg(`dim`,a.slice(0,o)):``}${n.fg(`accent`,a.slice(o,o+1))}${n.fg(`dim`,a.slice(o+1))}`;return`${e.slice(0,c)}${u}${e.slice(l)}`})}const kn={run_code:`PTC`,workflow:`PTC workflow`};var An=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>jn(e,t))}};function jn(e,t){let{left:n,right:r}=e;if(r===void 0)return P(n,t,`…`);let i=F(r);if(i>=t)return P(r,t,`…`);let a=P(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-F(a));return a+` `.repeat(o)+r}function q(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Mn(e){return q((G(e).split(`
21
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function Nn(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function Pn(e,t){return`${e} ${t}${e===1?``:`s`}`}function Fn(e){for(let t of e.split(`
22
+ `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return q(e.replace(/\s*\/\/.*$/,``),120)}}function In(e){if(e===void 0)return;if(typeof e==`string`){let t=G(e).split(`
23
+ `),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:q(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=pn(e);if(!t.includes(`
24
+ `)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function Ln(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,Pn(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,Pn(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,Pn(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,Pn(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Nn(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Rn(e){if(e!==void 0)return{surface:e.surface??`run_code`,logs:e.logs??[],narrations:e.narrations??[],phases:e.phases??[],warnings:e.warnings??[],durationMs:e.durationMs??0,imageCount:e.imageCount??0,...e.result===void 0?{}:{result:e.result},...e.fullOutputPath===void 0?{}:{fullOutputPath:e.fullOutputPath},...e.subCalls===void 0?{}:{subCalls:e.subCalls}}}function zn(e,t,n){let r=` `+(t?`└─ `:`├─ `),i=` `+(t?` `:`│ `),a=` `.repeat(8),o=[],s=e.lines[0]??``;o.push({left:`${r}${e.label.padEnd(8)}${n.fg(`dim`,s)}`});for(let t=1;t<e.lines.length;t++)o.push({left:`${i}${a}${n.fg(`dim`,e.lines[t]??``)}`});return e.more!==void 0&&e.more>0&&o.push({left:`${i}${a}…+${e.more} more lines`}),o}function Bn(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const Vn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Hn(e){return Vn.test(e)?e:JSON.stringify(e)}function Un(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=G(e);if(n.length===0)return`""`;if(n.includes(`
25
+ `)){let e=q(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(q(n,Math.max(2,t-5)))+`…`}return`?`}function Wn(e){return typeof e!=`object`||!e}function Gn(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Wn))return;let n=`[`+e.map(e=>Un(e,Math.max(2,Math.floor(t/4)))).join(`, `)+`]`;return n.length<=t?n:void 0}if(typeof e!=`object`||!e)return;let n=Object.keys(e);if(n.length===0)return`{}`;if(n.length>5||!Object.values(e).every(Wn))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Hn(n)+`: `+Un(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Kn(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(J(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(J(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(J(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-F(l)-t.length);c.push(J(l+t+Un(e,n),o));return}let d=Gn(e,Math.max(0,o-F(l)-t.length));if(d!==void 0){c.push(J(l+t+d,o));return}let f=Array.isArray(e),p=f?e.length:Object.keys(e).length,m;m=f?`Array(`+p+`)`:p>a?`{`+a+` of `+p+`}`:`{`+p+` keys}`,c.push(J(l+t+m,o));let h=Math.min(a,p);if(f)for(let t=0;t<h;t+=1){let n=t===h-1&&p<=h;Kn(e[t]??null,`[`+t+`] `,u,n,i,a,o,s+1,c)}else{let t=Object.keys(e);for(let n=0;n<h;n+=1){let r=n===h-1&&p<=h,l=t[n];Kn(e[l]??null,Hn(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(J(u+`└─ …+`+(p-h)+` more `+e,o))}}function J(e,t){if(F(e)<=t)return e;let n=e.match(/^([\s│├└─]*)/),r=n&&n[1]?n[1]:``,i=F(r),a=Math.max(0,t-i-1),o=``,s=0;for(let t of e.slice(r.length)){let e=F(t);if(s+e>a)break;o+=t,s+=e}return r+o+`…`}function qn(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Bn(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Un(e,i)];let o=[];if(Array.isArray(e)){let t=e.length,s=Math.min(r,t);for(let c=0;c<s;c+=1){let l=!a&&c===s-1&&t<=s;Kn(e[c]??null,`[`+c+`] `,``,l,n,r,i,0,o)}return t>s&&o.push((a?`├─ `:`└─ `)+`…+`+(t-s)+` more items`),o}let s=Object.keys(e),c=s.length,l=Math.min(r,c);for(let t=0;t<l;t+=1){let u=!a&&t===l-1&&c<=l,d=s[t];Kn(e[d]??null,Hn(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}function Jn(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Fn(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return Dn(new An([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(kn[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??Yn,state:r.state??{}})}function Yn(){}function Xn(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Mn(t?.text??``)||`failed`}function Zn(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t&&`agent`in t)return`→ ${String(t.agent)}`;if(typeof t==`object`&&t){let n=t,r=e=>typeof n[e]==`string`?n[e]:void 0,i=e===`read`?r(`path`):e===`bash`?r(`command`):e===`grep`||e===`find`?r(`pattern`):e===`ls`||e===`edit`||e===`write`?r(`path`):void 0;if(typeof i==`string`)return i}try{let e=JSON.stringify(t).replace(/\n/g,` `);return e.length>40?`${e.slice(0,39)}…`:e}catch{return String(t).slice(0,40)}}const Qn={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Nn(e.durationMs)}`,themeSlot:`accent`},error:{text:e=>`failed: ${e.errorMessage??`error`}`,themeSlot:`error`},cancelled:{text:()=>`cancelled`,themeSlot:`muted`},rejected:{text:e=>`rejected: ${e.errorMessage??`concurrency`}`,themeSlot:`warning`}};function $n(e,t){if(e.length===0)return[];let n=e.slice(0,32),r=e.length>32?e.length-32:0,i=[];return n.forEach((e,a)=>{let o=a===n.length-1&&r===0?`└─ `:`├─ `,s=e.name.length>=8?`${e.name} `:e.name.padEnd(8),c=Zn(e.name,e.args),l=Qn[e.status];i.push({left:` ${o}${t.fg(`toolTitle`,s)}${t.fg(l.themeSlot,l.text(e))}${t.fg(`dim`,` `+c)}`})}),r>0&&i.push({left:` └─ …+${r} more calls`}),i}function er(e,t,n,r=!1,i=!1){let a=Ln(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${Xn(e)}`)}`})];if(i&&e.details?.result===void 0)return[];let s=e.details?.result;if(s===void 0)return[o({left:` ${n.fg(`muted`,`done`)}`})];if(Bn(s))return qn(s,{maxDepth:4,maxChildren:6,maxLineChars:120,moreAfter:r}).map((e,t)=>{let n={left:` ${e}`};return t===0&&a!==void 0?{...n,right:a}:n});let c=In(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function tr(e,t,n,r={}){let i=Rn(e.details),a=[...er({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...$n(i.subCalls,n)),new An(a)}function nr(e,t,n,r,i={}){let a=Rn(e.details);if(n){let t=[...er({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...$n(a.subCalls,r));let n=G(e.content?.find(e=>e.type===`text`)?.text??Xn(e));for(let e of n.split(`
26
+ `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new An(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
27
+ `).map(e=>q(e,120)),t=e.slice(0,3);o.push({label:`code`,lines:t,...e.length>t.length?{more:e.length-t.length}:{}})}if(a!==void 0&&a.surface===`workflow`&&a.phases.length>0){let e=a.phases.slice(0,8),t=a.phases.length-e.length,n=t>0?` …+${t} more phases`:``;o.push({label:`phases`,lines:[`${e.join(` → `)}${n}`]})}if(a!==void 0&&a.narrations.length>0){let e=a.narrations.slice(0,12);o.push({label:`log`,lines:e.map(e=>G(e)),...a.narrations.length>e.length?{more:a.narrations.length-e.length}:{}})}if(a!==void 0&&a.logs.length>0){let e=a.logs.slice(0,12);o.push({label:`out`,lines:e.map(e=>G(e)),...a.logs.length>e.length?{more:a.logs.length-e.length}:{}})}if(a!==void 0&&a.warnings.length>0){let e=a.warnings.slice(0,4);o.push({label:`warn`,lines:e.map(e=>G(e)),...a.warnings.length>e.length?{more:a.warnings.length-e.length}:{}})}if(a!==void 0&&a.imageCount>0){let e=a.imageCount===1?`1 image attached`:`${a.imageCount} images attached`;o.push({label:`image`,lines:[e]})}let c=a?.subCalls,l=c!==void 0&&c.length>0||o.length>0,u=er({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...$n(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...zn(o[e]??{label:``,lines:[]},t,r))}return new An(u)}function rr(e){return{renderCall(t,n,r){return Jn(t,n,e,{...r?.invalidate===void 0?{}:{requestInvalidate:r.invalidate},...r?.isPartial===void 0?{}:{isPartial:r.isPartial},...r?.state===void 0?{}:{state:r.state}})},renderResult(e,t,n,r){let i=t.isPartial===!0;return t.expanded===!0?nr(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):tr(e,r?.isError===!0,n,{isPartial:i})}}}const ir=["Run a TypeScript program that composes pi's tools in one shot. Required arguments: `code` —","the body of an async function (top-level `return` and `await` work; type annotations are","advisory, the code runs type-stripped) — and `description`, a 5-10 word summary of what the",`program does.`,``,"Inside the program, call this session's enabled built-in tools as `tools.<name>(args)` — e.g.",'`await tools.read({ path: "src/index.ts" })` or `await tools.bash({ command: "npm test" })`.',"The bound names mirror the session's active tools (a default session has `read`, `bash`, `edit`,","`write`); independent calls may overlap under `Promise.all`.",``,"The parallel binding `pi.dispatch` is always available, registered under its literal dot name —",'call it with string indexing, e.g. `await tools["pi.dispatch"]({ agent: "reviewer", task: "..." })`;',"`tools.pi.dispatch` does not exist. It fans work out to child pi agents, and independent","foreground dispatches compose under `Promise.all` exactly like the built-in calls. The run's","actual bound names (this run, not a static list) are on the `ptcBindings` global, so the program",`never has to guess what is bound.`,``,Xt,``,"Only the program's return value and its `console.log` output come back. This surface has no","helpers: `log` / `phase` / `parallel` / `pipeline` exist only in `ptc_workflow`.",``,"Image-bearing tool results inside the program (a `tools.read` on a PNG, say) are attached to you",`after the run, so never return image data as the completion value — that only spends your context`,`on base64.`].join(`
28
+ `),ar=x.Object({code:x.String({description:`The program: the body of an async TypeScript function.`}),description:x.String({description:`Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI).`}),timeoutMs:x.Optional(x.Number({description:`Elapsed deadline in milliseconds for the whole run, including tool calls. Omit it (or pass 0) for the default of ${I.timeoutMs/1e3} s; anything above ${I.maxTimeoutMs/1e3} s is capped. The deadline bounds the whole run: if it expires, in-flight foreground dispatches spawned by the program are terminated with it.`}))});function or(e={}){return g({name:`ptc_run_code`,label:`PTC Run Code`,description:ir,promptSnippet:`Run a TypeScript program that composes pi's tools in one shot (tools.<name>(args)); only its return value and console.log come back`,promptGuidelines:[...gn],parameters:ar,async execute(t,n,r,i,a){let o=vn(a),s=K(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=yn({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await qt({code:n.code,surface:`run_code`,cwd:o,bindings:Ft({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...n.timeoutMs===void 0?{}:{timeoutMs:n.timeoutMs},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw xn(p);return Sn({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...rr(`run_code`)})}const sr=[`Run a structured TypeScript workflow: a named plan that reports phases and narration as it`,"goes. `script` is the body of an async function, `meta` names it (`{ name, description, phases? }`,","where `phases` is the ordered plan), and optional `args` is plain-JSON input bound to the","program's `args` global.",``,"Helpers inside the script: `log(message)` narrates progress; `phase(title)` frames the workflow","(titles outside `meta.phases` are reported as warnings); `parallel(thunks)` runs thunks","concurrently, a failed item becoming `null`; `pipeline(items, ...stages)` chains stages per item","with the same per-item `null` on failure. There is no `agent()` helper.",``,"Tools are reachable as `tools.<name>(args)` exactly as in `ptc_run_code`, and the bound names","mirror the session's enabled tools. The parallel binding `pi.dispatch` is always available under",'its literal dot name — call it with string indexing: `await tools["pi.dispatch"]({ agent, task })`;',"the run's actual bound names are on the `ptcBindings` global. What comes back is the script's","return value, its `log`/`phase` narration and its `console.log` output.",``,Xt,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
29
+ `),cr=x.Object({meta:x.Object({name:x.String({description:`Short workflow name, shown in the UI.`}),description:x.String({description:`What this workflow does, in active voice.`}),phases:x.Optional(x.Array(x.Object({name:x.String({description:`Phase title, matched against phase(title) calls.`})}),{description:`Ordered plan of the workflow's phases. phase() titles outside this list are reported as warnings.`}))},{description:`Workflow metadata: what this run is and which phases it declares.`}),script:x.String({description:`The program: the body of an async TypeScript function.`}),args:x.Optional(x.Record(x.String(),x.Unknown(),{description:"Plain-JSON input bound to the program's `args` global. No functions, symbols, undefined values or cycles."}))});function lr(t){if(t!==void 0){if(typeof t!=`object`||!t||Array.isArray(t))throw TypeError(`ptc_workflow args must be a plain JSON object, received ${e(t)}`);for(let e of Object.keys(t)){let n=ur(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function ur(t,n,r){if(t===null||typeof t==`string`||typeof t==`boolean`)return;if(t===void 0)return`${n} is undefined`;if(typeof t==`number`)return Number.isFinite(t)?void 0:`${n} is ${String(t)}, which is not representable as JSON`;if(typeof t!=`object`)return`${n} is ${e(t)}`;let i=t;if(r.has(i))return`${n} is a circular reference`;r.add(i);try{if(Array.isArray(i)){for(let e=0;e<i.length;e+=1){let t=ur(i[e],`${n}[${e}]`,r);if(t!==void 0)return t}return}let e=Object.getPrototypeOf(i);if(e!==Object.prototype&&e!==null){let e=i.constructor?.name;return`${n} is a ${typeof e==`string`&&e.length>0?e:`non-plain object`}, not plain JSON`}for(let e of Object.keys(i)){let t=ur(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function dr(e,t){if(t===void 0||t.length===0)return[];let n=new Set(t),r=/* @__PURE__ */ new Set,i=[];for(let t of e.phases)n.has(t)||r.has(t)||(r.add(t),i.push(`phase "${t}" is not listed in meta.phases (declared: ${[...n].join(`, `)})`));return i}function fr(e={}){return g({name:`ptc_workflow`,label:`PTC Workflow`,description:sr,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...gn],parameters:cr,async execute(t,n,r,i,a){lr(n.args);let o=vn(a),s=K(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=yn({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await qt({code:n.script,surface:`workflow`,cwd:o,bindings:Ft({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...n.args===void 0?{}:{args:n.args},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw xn(p);let m=n.meta.phases?.map(e=>e.name);return Sn({outcome:p,surface:`workflow`,warnings:dr(p,m),durationMs:Date.now()-c})},...rr(`workflow`)})}var pr=class{#e;constructor(e){this.#e=new Map(e??[])}async readOutput(e){let t=this.#e.get(e);return t===void 0?null:t}async writeOutput(e,t){this.#e.set(e,t)}outputRef(e){return`memory:tasks/${e}/output.log`}};function mr(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var hr=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await fe(this.#t(e),`utf8`)}catch(e){if(mr(e))return null;throw e}}async writeOutput(e,t){let n=k(this.#e,`tasks`,e);await de(n,{recursive:!0}),await ge(k(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return k(this.#e,`tasks`,e,`output.log`)}};function gr(e,t){return en(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const _r={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},vr={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var Y=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>yr(e,t))}};function yr(e,t){let{left:n,right:r}=e;if(r===void 0)return P(n,t,`…`);let i=F(r);if(i>=t)return P(r,t,`…`);let a=P(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-F(a));return a+` `.repeat(o)+r}function br(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function xr(e){return br((G(e).split(`
30
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function Sr(e){return typeof e==`object`&&e?e:{}}function Cr(e){return e===`running`||e===`stopping`}function wr(e){let t=Math.max(0,Math.floor(e));if(t<1e3)return`${t}ms`;let n=Math.floor(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;return r<60?`${r}m${i}s`:`${Math.floor(r/60)}h${String(r%60).padStart(2,`0`)}m`}function Tr(e,t){if(Cr(e.status))return wr(t-e.createdAt);if(e.durationMs!==void 0)return wr(e.durationMs);if(e.finishedAt!==void 0)return wr(e.finishedAt-e.createdAt)}function Er(e,t){let{state:n}=t;t.isLive?n.interval??=setInterval(()=>t.requestInvalidate(),1e3):n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0);let r=e;return r.dispose=()=>{n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0)},e}function Dr(){}function Or(e,t,n){return new Y([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function kr(e,t,n){let r=Sr(t);switch(e){case`task-list`:{let e=Array.isArray(r.status)?r.status:void 0,t=e!==void 0&&e.length>0?e.join(`,`):`all`,i=typeof r.limit==`number`?` · limit=${r.limit}`:``;return Or(`PTC task list`,n.fg(`dim`,`status=${t}${i}`),n)}case`task-output`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.sinceBytes==`number`?` · since=${r.sinceBytes}B`:``;return Or(`PTC task output`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}case`task-stop`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.reason==`string`&&r.reason.length>0?` · reason=${G(r.reason)}`:``;return Or(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Ar(e,t,n,r){let i=_r[e.status]??`muted`,a=n.fg(i,vr[e.status]??`?`),o=br(G(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,G(e.agentName))],c=Tr(e,r);return c!==void 0&&s.push(n.fg(`dim`,c)),e.outputBytes!==void 0&&s.push(n.fg(`dim`,`${e.outputBytes}B`)),{left:` ${t?`└─ `:`├─ `}${s.join(n.fg(`dim`,` · `))}`}}function jr(e,t){let n=Sr(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Er(new Y([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>Cr(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>Ar(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Er(new Y(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Mr(e,t,n){let r=[];if(e!==void 0&&r.push(n.fg(`dim`,`${e}B`)),t&&r.push(n.fg(`warning`,`truncated`)),r.length!==0)return`${n.fg(`dim`,`•`)} ${r.join(n.fg(`dim`,` · `))}`}function Nr(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Pr(e,t){let n=Sr(e),r=typeof n.output==`string`?n.output:``,i=typeof n.outputBytes==`number`?n.outputBytes:void 0,a=n.outputTruncated===!0,o=typeof n.outputFullPath==`string`&&n.outputFullPath.length>0?n.outputFullPath:void 0,s=Mr(i,a,t.theme),c=[];if(r.length>0){let e=G(r).split(`
31
+ `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,br(e,160));c.push(n===0&&s!==void 0?{left:` ${r}`,right:s}:{left:` ${r}`})}),e.length>n.length&&c.push({left:` ${t.theme.fg(`dim`,`…+${e.length-n.length} more lines`)}`}),a&&o!==void 0&&c.push({left:Nr(o,t.theme)})}else o===void 0?c.push({left:` ${t.theme.fg(`muted`,`(no output yet)`)}`,...s===void 0?{}:{right:s}}):c.push({left:Nr(o,t.theme),...s===void 0?{}:{right:s}});return new Y(c)}function Fr(e,t){let n=Sr(e),r=n.task;if(typeof r!=`object`||!r)return new Y([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=_r[r.status]??`muted`,a=t.theme.fg(i,vr[r.status]??`?`),o=typeof n.fromStatus==`string`?n.fromStatus:void 0,s=o===void 0?r.status===`stopping`?`running → stopping`:`→ ${String(r.status)}`:`${o} → ${r.status}`,c=[`${a} ${t.theme.fg(`text`,G(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${G(r.stopReason)}`)),new Y([{left:` ${c.join(` `)}`}])}function Ir(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=xr(n?.text??``)||`failed`;return new Y([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Lr(e,t,n){switch(e){case`task-list`:return jr(t.details,n);case`task-output`:return Pr(t.details,n);case`task-stop`:return Fr(t.details,n)}}function Rr(e){return{renderCall(t,n){return kr(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Ir(t,r):Lr(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Dr,state:i?.state??{},now:Date.now()})}}}const zr=[`Use ptc_task_list to see the background tasks this session dispatched and their live status.`,`Use ptc_task_output to read a task's captured output (it is tail-truncated; the footer names the full-output file).`,`Use ptc_task_stop to ask a running task to stop; the dispatcher delivers the actual signal, so the task transitions through stopping to canceled.`,`These background-task tools stay callable when PTC mode is off — /ptc off only blocks new dispatches.`],Br=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Vr=x.Object({status:x.Optional(x.Array(Br,{description:`Only return tasks in these states. Omit for all six states (running, stopping, succeeded, failed, canceled, lost).`})),limit:x.Optional(x.Number({description:`Maximum number of tasks to return, newest first. Defaults to 100.`}))});function Hr(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,G(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${G(e.errorMessage)}`),t.join(` `)}function Ur(e){return g({name:`ptc_task_list`,label:`PTC Task List`,description:[`List the background tasks this session has dispatched (from pi.dispatch({ background: true })).`,`Returns each task's id, status, agent, depth, label and output size, newest first.`,`Filter with status (e.g. ["running"]); limit caps the row count (default 100).`].join(`
32
+ `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...zr],parameters:Vr,async execute(t,n){let r=await e.query({...n.status===void 0?{}:{status:n.status},limit:n.limit??100,orderBy:`createdAt-desc`});return{content:[{type:`text`,text:r.length===0?`(no background tasks)`:r.map(e=>Hr(e)).join(`
33
+ `)}],details:{tasks:r,count:r.length}}},...Rr(`task-list`)})}async function Wr(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}const Gr=x.Object({taskId:x.String({description:`The background task's id (as returned by ptc_task_list or the dispatch handle).`}),sinceBytes:x.Optional(x.Number({description:`Skip this many bytes of the stored output before returning it. Use for paging larger logs; defaults to 0.`}))});function Kr(e,t){return g({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
34
+ `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...zr],parameters:Gr,async execute(n,r){let i=r.taskId,a=await Wr(e,i,`ptc_task_output`),o=await t.readOutput(i)??``,s=Buffer.byteLength(o,`utf8`),c=r.sinceBytes??0;if(!Number.isInteger(c)||c<0)throw Error(`ptc_task_output: sinceBytes must be a non-negative integer, got ${String(r.sinceBytes)}`);if(c>s)throw Error(`ptc_task_output: sinceBytes ${c} exceeds the ${s}-byte output of task ${i}`);let l=Buffer.from(o,`utf8`);if(c<s&&((l[c]??0)&192)==128)throw Error(`ptc_task_output: sinceBytes ${c} splits a UTF-8 character in task ${i}; use a byte offset on a character boundary`);let u=gr(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath}};return{content:[{type:`text`,text:f.output.length>0?f.output:`(no output yet; task ${i} is ${a.status})`}],details:f}},...Rr(`task-output`)})}const qr=x.Object({taskId:x.String({description:`The running task's id (as returned by ptc_task_list or the dispatch handle).`}),reason:x.Optional(x.String({description:`Why the task is being stopped; recorded as the task's stopReason. Defaults to "model stop".`}))});function Jr(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return g({name:`ptc_task_stop`,label:`PTC Task Stop`,description:[`Ask a running background task to stop.`,`The task moves to "stopping"; the dispatcher sends the signal and records the terminal "canceled" state when the child exits.`,`The call is idempotent when the task is already stopping, and errors when the task is already terminal.`].join(`
35
+ `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...zr],parameters:qr,async execute(t,n){let i=n.taskId,a=await Wr(e,i,`ptc_task_stop`),o=a.spawnSource.callerId.length>0?a.spawnSource.callerId:`ptc_task_stop`,{record:s,fromStatus:c}=await e.transition({kind:`stop`,taskId:i,reason:n.reason??`model stop`},{clock:r,callerId:o}),l=s.stopReason===void 0?``:` reason=${G(s.stopReason)}`;return{content:[{type:`text`,text:`${s.id} ${s.status}${l}`}],details:{task:s,fromStatus:c??a.status}}},...Rr(`task-stop`)})}var Yr=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=L(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Ne(),r=new Rt({buildWorkerUrl:Vt,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:Lt({surface:e,env:n,limits:this.#e})});return this.#t.set(e,r),r}async drain(){let e=[...this.#t.values()];this.#t.clear(),await Promise.all(e.map(e=>e.drain()))}};const Xr={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var Zr=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??Xr,this.#r=[],this.#i=/* @__PURE__ */ new Map}async subscribe(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r!==null)return r;let i={subscriberId:e,taskId:t,cursor:n??`00000000000000000000`,status:`active`,createdAt:this.#t()};return await this.#e.saveSubscription(i),i}async drainPending(e,t){let n=await this.#o(e,t,`drainPending`);return this.#s(n)}async acknowledgeEvents(e,t,n){await this.#a(e,t,async()=>{let r=await this.#o(e,t,`acknowledgeEvents`);n<=r.cursor||await this.#e.saveSubscription({...r,cursor:n})})}#a(e,t,n){let r=`${e}-${t}`,i=(this.#i.get(r)??Promise.resolve()).then(n),a=i.then(()=>void 0,()=>void 0);return this.#i.set(r,a),a.then(()=>{this.#i.get(r)===a&&this.#i.delete(r)}),i}onIdleWake(e){this.#r.push(e)}async pendingCount(e,t){let n=await this.#o(e,t,`pendingCount`);return(await this.#s(n)).length}async notifyIdle(e,t){let n=await this.drainPending(e,t);if(n.length===0)return n;let r=this.#r.slice();for(let i of r)try{i(e,n)}catch(n){let r=n instanceof Error?n.message:String(n);this.#n.warn(`notifyIdle: idle-wake handler for subscriber ${e} / task ${t} threw: ${r}`)}return n}async#o(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r===null)throw Error(`${n}: unknown subscription for subscriber ${e} / task ${t}`);return r}async#s(e){let t=[];for await(let n of this.#e.loadEvents(e.subscriberId,e.cursor===`00000000000000000000`?void 0:e.cursor))n.taskId===e.taskId&&t.push(n);return t}};const Qr={mkdir:(e,t)=>de(e,t),readFile:(e,t)=>fe(e,t),writeFile:(e,t,n)=>ge(e,t,n),appendFile:(e,t,n)=>ue(e,t,n),rename:(e,t)=>me(e,t),unlink:e=>he(e),readdir:e=>pe(e)};function $r(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function ei(e){return e instanceof Error?e.message:String(e)}function ti(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var ni=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??Qr}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){M(e,`saveTask: record is required`),await this.#o(this.#f(e.id),e)}async deleteTask(e){let t=this.#f(e);if(!await this.#c(t))throw Error(`deleteTask: unknown taskId `+e);await this.#t.unlink(t)}async*listTasks(e){let t=this.#l();for(let n of(await this.#s(t)).sort()){if(!n.endsWith(`.json`))continue;let r=await this.#r(k(t,n));r!==null&&(e?.status===void 0||r.status===e.status)&&(e?.label===void 0||r.label===e.label)&&(yield r)}}async loadSubscription(e,t){return await this.#r(this.#p(e,t))}async saveSubscription(e){M(e,`saveSubscription: sub is required`),await this.#o(this.#p(e.subscriberId,e.taskId),e)}async appendEvents(e,t){if(t.length===0){if((await this.#n(e)).length===0)throw Error(`appendEvents: unknown subscriptionId `+e);return}let n=/* @__PURE__ */ new Map;for(let e of t){let t=n.get(e.taskId);t===void 0?n.set(e.taskId,[e]):t.push(e)}let r;for(let t of n.keys())if(await this.loadSubscription(e,t)===null){r=t;break}if(r!==void 0)throw(await this.#n(e)).length===0?Error(`appendEvents: unknown subscriptionId `+e):Error(`appendEvents: no subscription for subscriber `+e+` on task `+r);await this.#t.mkdir(this.#d(),{recursive:!0});for(let[t,r]of n){let n=(r.every((e,t)=>t===0||ti(r[t-1],e)<=0)?r:[...r].sort(ti)).map(e=>JSON.stringify(e)).join(`
34
36
  `)+`
35
- `;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(qr);for(let e of r)t!==void 0&&e.eventId<=t||(yield e)}async#n(e){let t=this.#u(),n=[];for(let r of await this.#s(t)){if(!r.endsWith(`.json`))continue;let i=await this.#r(k(t,r));i!==null&&i.subscriberId===e&&n.push(i)}return n}async#r(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if(Gr(e))return null;throw e}return this.#i(e,t)}#i(e,t){let n;try{n=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt JSON in `+e+`: `+Kr(t))}if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`FileTaskStorage: corrupt JSON in `+e+`: expected a JSON object`);return n}async#a(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if(Gr(e))return[];throw e}let n=[];for(let r of t.split(`
36
- `)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+Kr(t))}if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: expected a JSON object`);n.push(i)}return n}async#o(e,t){await this.#t.mkdir(O(e),{recursive:!0});let n=e+`.tmp-`+j();await this.#t.writeFile(n,JSON.stringify(t,null,2),{encoding:`utf8`}),await this.#t.rename(n,e)}async#s(e){try{return await this.#t.readdir(e)}catch(e){if(Gr(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(Gr(e))return!1;throw e}}#l(){return k(this.#e,`tasks`)}#u(){return k(this.#e,`subscriptions`)}#d(){return k(this.#e,`events`)}#f(e){return k(this.#l(),e+`.json`)}#p(e,t){return k(this.#u(),e+`-`+t+`.json`)}#m(e,t){return k(this.#d(),e+`-`+t+`.jsonl`)}};function Yr(e,t){return new Jr(e,t)}const Xr=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Zr=/* @__PURE__ */ new Set([`running`,`stopping`]),Qr=2**53-1,$r={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function Z(e){return e instanceof Error?e.message:String(e)}function ei(e){return e===void 0||e.length===0?`<in-memory>`:e}function ti(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var ni=class{#e;#t=/* @__PURE__ */ new Map;constructor(e){this.#e=e}setCurrent(e){this.#e=e}async transition(e,t){let n=e.kind===`spawn`?this.#e:this.#t.get(e.taskId)??this.#e,r=await n.transition(e,t);return e.kind===`spawn`&&this.#t.set(r.record.id,n),r}query(e){return this.#e.query(e)}get(e){return this.#e.get(e)}onTransition(e){return this.#e.onTransition(e)}reconcileLostTasks(){return this.#e.reconcileLostTasks()}},ri=class{#e;constructor(e){this.#e=e}setCurrent(e){this.#e=e}readOutput(e){return this.#e.readOutput(e)}writeOutput(e,t){return this.#e.writeOutput(e,t)}outputRef(e){return this.#e.outputRef(e)}},ii=class{#e;#t=[];constructor(e){this.#e=e}setCurrent(e){this.#e=e;for(let t of this.#t)e.onIdleWake(t)}current(){return this.#e}subscribe(e,t,n){return this.#e.subscribe(e,t,n)}drainPending(e,t){return this.#e.drainPending(e,t)}acknowledgeEvents(e,t,n){return this.#e.acknowledgeEvents(e,t,n)}onIdleWake(e){this.#t.push(e),this.#e.onIdleWake(e)}pendingCount(e,t){return this.#e.pendingCount(e,t)}notifyIdle(e,t){return this.#e.notifyIdle(e,t)}},ai=class{#e;#t=/* @__PURE__ */ new Set;#n=/* @__PURE__ */ new Map;constructor(e){this.#e=e}isLive(e){return this.#t.has(e)}trackReapCancel(e,t){this.#n.set(e,t)}spawn(e,t){let n=this.#e.spawn(e,t);return this.#t.add(n),n}kill(e,t){this.#e.kill(e,t)}events(e){return this.#e.events(e)}async exit(e){try{return await this.#e.exit(e)}finally{this.#t.delete(e);let t=this.#n.get(e);t!==void 0&&(this.#n.delete(e),t())}}stderr(e){return this.#e.stderr(e)}liveHandles(){return[...this.#t]}},oi=class{registry;outputStorage;pipeline;slots;lifecycle;dispatchDeps;clock;#e;#t;#n;#r;#i;#a=!1;constructor(e){this.clock=e.clock??(()=>Date.now()),this.#e=e.logger??$r,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??ze,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new Ge:Yr(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new ar:new sr(e));let t=new Ge,n=He(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new Ur(t,{now:this.clock,logger:this.#e});this.registry=new ni(n),this.outputStorage=new ri(new ar),this.pipeline=new ii(r),this.lifecycle=new ai((e.createLifecycle??(()=>new Ee({logger:this.#e})))()),this.slots=new Ke(e.concurrency??z.dispatchConcurrency),this.dispatchDeps={taskRegistry:this.registry,lifecycle:this.lifecycle,slots:this.slots,outputStorage:this.outputStorage,clock:this.clock,logger:this.#e},this.registry.onTransition(this.#o)}#o=(e,t)=>{this.#a||Xr.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+Z(t))})};async bindSession(e,t){let n,r;try{n=this.#t(e),r=this.#n(e)}catch(n){return this.#s(`background runtime: session storage for `+ei(e)+` is unavailable: `+Z(n),t),[]}let i=He(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new Ur(n,{now:this.clock,logger:this.#e});this.registry.setCurrent(i),this.outputStorage.setCurrent(r),this.pipeline.setCurrent(a),this.#a=!1;try{return await i.reconcileLostTasks()}catch(e){return this.#s(`background runtime: startup reconcile failed; stale running tasks were not all marked lost (reconcile is not per-record tolerant yet): `+Z(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:Qr})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+Z(t)),{items:[],acks:[]}}let n=[],r=[],i=this.pipeline.current();for(let a of t){if(a.spawnSource.callerId!==e)continue;let t;try{t=await i.drainPending(e,a.id)}catch(t){this.#e.warn(`drainNotifications: task `+a.id+` for subscriber `+e+`: `+Z(t));continue}for(let e of t)n.push({event:e,record:a});let o=t[t.length-1];o!==void 0&&r.push({subscriberId:e,taskId:a.id,cursor:o.eventId,sink:i})}return{items:n,acks:r}}async acknowledgeNotifications(e){for(let t of e)try{await t.sink.acknowledgeEvents(t.subscriberId,t.taskId,t.cursor)}catch(e){this.#e.warn(`acknowledgeNotifications: could not acknowledge task `+t.taskId+`: `+Z(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:Qr})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+Z(e)),t=[]}let n=[];for(let r of t)if(Zr.has(r.status)&&Re(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:ti(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+Z(e))}for(let e of this.lifecycle.liveHandles()){let t=tt(this.lifecycle,e,{isDone:()=>!this.lifecycle.isLive(e),unref:!0});this.lifecycle.trackReapCancel(e,t)}for(let e of n)this.slots.release(e.id);return n}#s(e,t){if(this.#e.warn(e),t!==void 0)try{t(e)}catch(e){this.#e.warn(`bindSession reporter threw: `+Z(e))}}};function si(e={}){return new oi(e)}const ci=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function li(e){return ci.has(e.status)}function ui(e,t){if(e.length===0)return``;let n=e.map(fi).join(`
37
- `);return`${`<bg-task-notifications batch-id="${Q(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function di(e,t=102400){let n=[],r=[],i=0,a=t-mi;for(let t of e){let e=pi(t);r.length>0&&i+1+e>a&&(n.push(r),r=[],i=0),r.length>0&&(i+=1),r.push(t),i+=e}return r.length>0&&n.push(r),n}function fi(e){let{event:t,record:n}=e,r=t.outputBytes??n.outputBytes,i=r??0,a=t.outputPreview??n.outputPreview,o=[` <bg-task-notification`,` id="${Q(t.type)}"`,` task-id="${Q(t.taskId)}"`,` subscription-id="${Q(t.subscriptionId)}"`,` status="${Q(t.status)}"`,` label="${Q(n.label)}"`,` agent-name="${Q(n.agentName)}"`,` depth="${n.depth}"`,` duration-ms="${n.durationMs??0}"`,` transition-at-ms="${t.transitionAtMs}">`,` <output-bytes>${i}</output-bytes>`];return n.outputRef!==void 0&&o.push(` <output-ref>${Q(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${Q(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
38
- `)}function Q(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
39
- `,`&#10;`).replaceAll(`\r`,`&#13;`)}function pi(e){return Buffer.byteLength(fi(e),`utf8`)}const mi=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),hi=[`ptc_run_code`,`ptc_workflow`],gi=[`read`,`bash`,`edit`,`write`],_i=`ptc-mode`,vi=`ptc-mode`,yi=`ptc.json`,bi=`builtins-only`;function xi(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function Si(e){let t=k(e,yi),n;try{n=T(t,`utf8`)}catch{return{defaultMode:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch(e){return{defaultMode:!0,source:`invalid`,error:`${t} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof r!=`object`||!r||Array.isArray(r))return{defaultMode:!0,source:`invalid`,error:`${t} must contain a JSON object`};let i=r.defaultMode;return i===void 0?{defaultMode:!0,source:`default`}:typeof i==`boolean`?{defaultMode:i,source:`file`}:{defaultMode:!0,source:`invalid`,error:`${t}: "defaultMode" must be a boolean, received ${typeof i}`}}function Ci(e){return[...new Set(e)]}function wi(e,t){if(e.length!==t.length)return!1;let n=[...e].sort(),r=[...t].sort();return n.every((e,t)=>e===r[t])}function Ti(e,t){let n=e=>hi.includes(e);if(t===`all-but-ptc`)return Ci(e.filter(n));let r=new Set(V);return Ci(e.filter(e=>n(e)||!r.has(e)))}function Ei(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:hi.some(e=>r.includes(e))?!i&&gi.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:Ci(r),loadout:Ti(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function Di(e,t){return e.enabled&&e.base!==void 0?e.base:t}function Oi(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!wi(e.ourLoadout,t)}function ki(e,t){let n=t.length>0&&t.every(e=>hi.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function Ai(e,t){let n=t===`all-but-ptc`?`Every built-in tool is hidden from you, and so are other extensions' tools.`:`The built-in tools (read, bash, edit, write, grep, find, ls) are hidden from you.`,r=e.map(e=>`tools.${e}(args)`),i=e.slice(0,2).map(e=>e===`read`?`await tools.read({ path: "src/index.ts" })`:e===`bash`?`await tools.bash({ command: "pnpm test" })`:`await tools.${e}({ /* … */ })`).join(`
37
+ `;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(ti);for(let e of r)t!==void 0&&e.eventId<=t||(yield e)}async#n(e){let t=this.#u(),n=[];for(let r of await this.#s(t)){if(!r.endsWith(`.json`))continue;let i=await this.#r(k(t,r));i!==null&&i.subscriberId===e&&n.push(i)}return n}async#r(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if($r(e))return null;throw e}return this.#i(e,t)}#i(e,t){let n;try{n=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt JSON in `+e+`: `+ei(t))}if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`FileTaskStorage: corrupt JSON in `+e+`: expected a JSON object`);return n}async#a(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if($r(e))return[];throw e}let n=[];for(let r of t.split(`
38
+ `)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+ei(t))}if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: expected a JSON object`);n.push(i)}return n}async#o(e,t){await this.#t.mkdir(O(e),{recursive:!0});let n=e+`.tmp-`+j();await this.#t.writeFile(n,JSON.stringify(t,null,2),{encoding:`utf8`}),await this.#t.rename(n,e)}async#s(e){try{return await this.#t.readdir(e)}catch(e){if($r(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if($r(e))return!1;throw e}}#l(){return k(this.#e,`tasks`)}#u(){return k(this.#e,`subscriptions`)}#d(){return k(this.#e,`events`)}#f(e){return k(this.#l(),e+`.json`)}#p(e,t){return k(this.#u(),e+`-`+t+`.json`)}#m(e,t){return k(this.#d(),e+`-`+t+`.jsonl`)}};function ri(e,t){return new ni(e,t)}const ii=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),ai=/* @__PURE__ */ new Set([`running`,`stopping`]),oi=2**53-1,si={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function X(e){return e instanceof Error?e.message:String(e)}function ci(e){return e===void 0||e.length===0?`<in-memory>`:e}function li(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var ui=class{#e;#t=/* @__PURE__ */ new Map;constructor(e){this.#e=e}setCurrent(e){this.#e=e}async transition(e,t){let n=e.kind===`spawn`?this.#e:this.#t.get(e.taskId)??this.#e,r=await n.transition(e,t);return e.kind===`spawn`&&this.#t.set(r.record.id,n),r}query(e){return this.#e.query(e)}get(e){return this.#e.get(e)}onTransition(e){return this.#e.onTransition(e)}reconcileLostTasks(){return this.#e.reconcileLostTasks()}},di=class{#e;constructor(e){this.#e=e}setCurrent(e){this.#e=e}readOutput(e){return this.#e.readOutput(e)}writeOutput(e,t){return this.#e.writeOutput(e,t)}outputRef(e){return this.#e.outputRef(e)}},fi=class{#e;#t=[];constructor(e){this.#e=e}setCurrent(e){this.#e=e;for(let t of this.#t)e.onIdleWake(t)}current(){return this.#e}subscribe(e,t,n){return this.#e.subscribe(e,t,n)}drainPending(e,t){return this.#e.drainPending(e,t)}acknowledgeEvents(e,t,n){return this.#e.acknowledgeEvents(e,t,n)}onIdleWake(e){this.#t.push(e),this.#e.onIdleWake(e)}pendingCount(e,t){return this.#e.pendingCount(e,t)}notifyIdle(e,t){return this.#e.notifyIdle(e,t)}},pi=class{#e;#t=/* @__PURE__ */ new Set;#n=/* @__PURE__ */ new Map;constructor(e){this.#e=e}isLive(e){return this.#t.has(e)}trackReapCancel(e,t){this.#n.set(e,t)}spawn(e,t){let n=this.#e.spawn(e,t);return this.#t.add(n),n}kill(e,t){this.#e.kill(e,t)}events(e){return this.#e.events(e)}async exit(e){try{return await this.#e.exit(e)}finally{this.#t.delete(e);let t=this.#n.get(e);t!==void 0&&(this.#n.delete(e),t())}}stderr(e){return this.#e.stderr(e)}liveHandles(){return[...this.#t]}},mi=class{registry;outputStorage;pipeline;slots;lifecycle;dispatchDeps;clock;#e;#t;#n;#r;#i;#a=!1;constructor(e){this.clock=e.clock??(()=>Date.now()),this.#e=e.logger??si,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??We,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new Xe:ri(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new pr:new hr(e));let t=(e.createInitialStorage??(()=>new Xe))(),n=qe(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new Zr(t,{now:this.clock,logger:this.#e});this.registry=new ui(n),this.outputStorage=new di(new pr),this.pipeline=new fi(r),this.lifecycle=new pi((e.createLifecycle??(()=>new je({logger:this.#e})))()),this.slots=new Ze(e.concurrency??I.dispatchConcurrency),this.dispatchDeps={taskRegistry:this.registry,lifecycle:this.lifecycle,slots:this.slots,outputStorage:this.outputStorage,clock:this.clock,logger:this.#e},this.registry.onTransition(this.#o)}#o=(e,t)=>{this.#a||ii.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+X(t))})};async bindSession(e,t){let n,r;try{n=this.#t(e),r=this.#n(e)}catch(n){return this.#s(`background runtime: session storage for `+ci(e)+` is unavailable: `+X(n),t),[]}let i=qe(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new Zr(n,{now:this.clock,logger:this.#e});this.registry.setCurrent(i),this.outputStorage.setCurrent(r),this.pipeline.setCurrent(a),this.#a=!1;try{return await i.reconcileLostTasks()}catch(e){return this.#s(`background runtime: startup reconcile failed; stale running tasks were not all marked lost (reconcile is not per-record tolerant yet): `+X(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:oi})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+X(t)),{items:[],acks:[]}}let n=[],r=[],i=this.pipeline.current();for(let a of t){if(a.spawnSource.callerId!==e)continue;let t;try{t=await i.drainPending(e,a.id)}catch(t){this.#e.warn(`drainNotifications: task `+a.id+` for subscriber `+e+`: `+X(t));continue}for(let e of t)n.push({event:e,record:a});let o=t[t.length-1];o!==void 0&&r.push({subscriberId:e,taskId:a.id,cursor:o.eventId,sink:i})}return{items:n,acks:r}}async acknowledgeNotifications(e){for(let t of e)try{await t.sink.acknowledgeEvents(t.subscriberId,t.taskId,t.cursor)}catch(e){this.#e.warn(`acknowledgeNotifications: could not acknowledge task `+t.taskId+`: `+X(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:oi})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+X(e)),t=[]}let n=[];for(let r of t)if(ai.has(r.status)&&Ue(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:li(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+X(e))}for(let e of this.lifecycle.liveHandles()){let t=z(this.lifecycle,e,{isDone:()=>!this.lifecycle.isLive(e),unref:!0});this.lifecycle.trackReapCancel(e,t)}for(let e of n)this.slots.release(e.id);return n}#s(e,t){if(this.#e.warn(e),t!==void 0)try{t(e)}catch(e){this.#e.warn(`bindSession reporter threw: `+X(e))}}};function hi(e={}){return new mi(e)}const gi=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function _i(e){return gi.has(e.status)}function vi(e,t){if(e.length===0)return``;let n=e.map(bi).join(`
39
+ `);return`${`<bg-task-notifications batch-id="${Z(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function yi(e,t=102400){let n=[],r=[],i=0,a=t-Si;for(let t of e){let e=xi(t);r.length>0&&i+1+e>a&&(n.push(r),r=[],i=0),r.length>0&&(i+=1),r.push(t),i+=e}return r.length>0&&n.push(r),n}function bi(e){let{event:t,record:n}=e,r=t.outputBytes??n.outputBytes,i=r??0,a=t.outputPreview??n.outputPreview,o=[` <bg-task-notification`,` id="${Z(t.type)}"`,` task-id="${Z(t.taskId)}"`,` subscription-id="${Z(t.subscriptionId)}"`,` status="${Z(t.status)}"`,` label="${Z(n.label)}"`,` agent-name="${Z(n.agentName)}"`,` depth="${n.depth}"`,` duration-ms="${n.durationMs??0}"`,` transition-at-ms="${t.transitionAtMs}">`,` <output-bytes>${i}</output-bytes>`];return n.outputRef!==void 0&&o.push(` <output-ref>${Z(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${Z(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
40
+ `)}function Z(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
41
+ `,`&#10;`).replaceAll(`\r`,`&#13;`)}function xi(e){return Buffer.byteLength(bi(e),`utf8`)}const Si=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),Ci=[`ptc_run_code`,`ptc_workflow`],wi=[`read`,`bash`,`edit`,`write`],Q=`ptc-mode`,Ti=`ptc-mode`,Ei=`ptc.json`,Di=`builtins-only`;function Oi(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function ki(e){let t=k(e,Ei),n;try{n=T(t,`utf8`)}catch{return{defaultMode:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch(e){return{defaultMode:!0,source:`invalid`,error:`${t} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof r!=`object`||!r||Array.isArray(r))return{defaultMode:!0,source:`invalid`,error:`${t} must contain a JSON object`};let i=r.defaultMode;return i===void 0?{defaultMode:!0,source:`default`}:typeof i==`boolean`?{defaultMode:i,source:`file`}:{defaultMode:!0,source:`invalid`,error:`${t}: "defaultMode" must be a boolean, received ${typeof i}`}}const Ai=[`off`,`subagents`,`full`];function ji(e){return e.present?`subagents`:`full`}function Mi(e=process.argv){let t=e[1];if(t===void 0||t===``)return{present:!1,how:`no-entry`};let n;try{n=ee(t)}catch{return{present:!1,how:`unresolvable-entry`}}let r=O(n);for(let e of Ni){let t=k(r,...e);try{if(E(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const Ni=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function Pi(e,t){let n=k(e,Ei),r=()=>{let e=t??Mi();return{surfaceMode:ji(e),codemode:e}},i;try{i=T(n,`utf8`)}catch{return{...r(),source:`default`}}let a;try{a=JSON.parse(i)}catch(e){return{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof a!=`object`||!a||Array.isArray(a))return{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n} must contain a JSON object`};let o=a.surfaceMode;return o===void 0?{...r(),source:`default`}:typeof o==`string`?Ai.includes(o)?{surfaceMode:o,source:`file`}:{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n}: "surfaceMode" must be one of ${Ai.join(` | `)}, received ${JSON.stringify(o)}`}:{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n}: "surfaceMode" must be a string, received ${typeof o}`}}function Fi(e){return[...new Set(e)]}function Ii(e,t){if(e.length!==t.length)return!1;let n=[...e].sort(),r=[...t].sort();return n.every((e,t)=>e===r[t])}function Li(e,t){let n=e=>Ci.includes(e);if(t===`all-but-ptc`)return Fi(e.filter(n));let r=new Set(B);return Fi(e.filter(e=>n(e)||!r.has(e)))}function Ri(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:Ci.some(e=>r.includes(e))?!i&&wi.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:Fi(r),loadout:Li(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function zi(e,t){return e.enabled&&e.base!==void 0?e.base:t}function Bi(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!Ii(e.ourLoadout,t)}function Vi(e,t){let n=t.length>0&&t.every(e=>Ci.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function Hi(e,t){let n=t===`all-but-ptc`?`Every built-in tool is hidden from you, and so are other extensions' tools.`:`The built-in tools (read, bash, edit, write, grep, find, ls) are hidden from you.`,r=e.map(e=>`tools.${e}(args)`),i=e.slice(0,2).map(e=>e===`read`?`await tools.read({ path: "src/index.ts" })`:e===`bash`?`await tools.bash({ command: "pnpm test" })`:`await tools.${e}({ /* … */ })`).join(`
40
42
  `);return[`[PTC MODE ACTIVE]`,`This session runs in PTC mode. `+n,``,`Work by writing one TypeScript program per task and running it:`,` - ptc_run_code for a plain program (its return value and console.log come back to you)`,` - ptc_workflow when the task has named phases and you want narration (log / phase /`,` parallel / pipeline are available there)`,``,`The program body is an async function. Available inside it: ${r.join(`, `)}, plus the`,'parallel binding `tools["pi.dispatch"](args)` — always bound, and its dot name needs string',"indexing (`tools.pi.dispatch` does not exist). The run's actual bound names are on the","`ptcBindings` global, so a program never has to guess what is bound this run.",i.length>0?`Examples:\n${i}`:``,``,`Batch a task's steps into ONE program instead of issuing many tool calls — gathering`,`intermediate output yourself and returning only what matters is the point of this mode.`,`Image-bearing tool results inside a program are attached to you after the run — never return`,`base64 image data as your program's value.`,`If the PTC surfaces cannot express what you need, say so and the user can run /ptc off.`].filter(e=>e.length>0).join(`
41
- `)}const ji=[`read`,`bash`],Mi=`Use the read tool to load a skill's file when the task matches its description.`,Ni=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function Pi(e){return!ji.some(t=>e.includes(t))}function Fi(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Mi)?n.replace(Mi,Ni):`${Ni}\n\n${n}`}const $=bi;function Ii(e,t){return[`PTC mode on — ${t===`all-but-ptc`?`all other tools`:`built-in tools (now reachable only as tools.<name> inside a program)`} hidden.`,`Bindings available inside a program: ${q(e).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
42
- `)}function Li(e,t={}){let n=xi(),r=!1,i=new Vr,a=()=>Di(n,e.getActiveTools()),o=on(),s=sn(),c=t.backgroundRuntime??si(),l=!1,u=e=>{console.warn(`[pi-ptc.background] `+e)},d=t=>{if(t.length!==0){if(l){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},f=async e=>{let{items:t,acks:n}=await c.drainNotifications(e),r=t.filter(e=>li(e.record));for(let e of di(r))d(ui(e,{batchId:ve(),deliveredAtMs:c.clock()}));await c.acknowledgeNotifications(n)},p=async()=>{let e=await c.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},m=async()=>{for(let e of await p())await f(e)},h=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await f(e)};c.pipeline.onIdleWake(e=>{f(e).catch(e=>{u(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})}),e.registerTool(Qn({getBindingSourceNames:a,getPool:()=>i.get(`run_code`),depth:o,...s===void 0?{}:{parentTaskId:s},getDispatchDeps:()=>c.dispatchDeps})),e.registerTool(ir({getBindingSourceNames:a,getPool:()=>i.get(`workflow`),depth:o,...s===void 0?{}:{parentTaskId:s},getDispatchDeps:()=>c.dispatchDeps})),e.registerTool(Fr(c.registry)),e.registerTool(Rr(c.registry,c.outputStorage)),e.registerTool(Br(c.registry,c.lifecycle,{clock:c.clock})),e.on(`turn_start`,async()=>{l=!0}),e.on(`agent_settled`,async()=>{l=!1;try{await m()}catch(e){u(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=i;i=new Vr,await e.drain()});let g=e=>{e.ui.setStatus(vi,n.enabled?e.ui.theme.fg(`accent`,`PTC`):void 0)},_=(t,i,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=i,e.setActiveTools([...i]),r=!0,e.appendEntry(_i,{enabled:!0,base:[...t]}),g(a),a.ui.notify(o,`info`)},v=(t,i)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,r=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(i.customType,{enabled:!1}),g(t),i.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},b=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode (built-in tools reachable only from inside a PTC program)`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}v(r,{announce:!0,customType:_i});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${q(n.base).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=Ei({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:$});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}_(a.base,a.loadout,r,Ii(a.base,$))}}),e.on(`session_start`,async(t,n)=>{l=!1;let r=await c.bindSession(n.sessionManager?.getSessionDir?.(),e=>n.ui.notify(e,`warning`));try{await h(r)}catch(e){u(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let i=Si(y());i.error!==void 0&&n.ui.notify(`pi-ptc-subagents: ${i.error}`,`warning`);let a=b(n),{base:o,restoreFirst:s}=ki(a,e.getActiveTools());s&&e.setActiveTools([...o]);let d=Ei({mode:n.mode,defaultMode:i.defaultMode,active:o,manual:!1,hide:$}),f=a?.enabled??d.enter;if(d.enter&&f){_(o,d.loadout,n,Ii(o,$));return}g(n),!d.enter&&d.reason!==`not-tui`&&a===void 0&&d.reason===`restricted-session`&&n.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{l=!1;try{await c.shutdown(`session_ended_while_running`)}catch(e){u(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let x=!1,S=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){x&&=(delete e.sections.skills,!1);return}let r=Fi(e.skills);r.length!==0&&(e.sections.skills=r,x=!0)};e.on(`before_agent_start`,async(t,i)=>{let a=t.systemPromptOptions;if(S(a,Pi(e.getActiveTools())),n.enabled){if(Oi(n,e.getActiveTools())){v(i,{announce:!1,customType:_i}),S(a,Pi(e.getActiveTools())),i.ui.notify(`PTC mode off — another extension changed the active tool set.`,`warning`);return}if(r)return r=!1,{message:{customType:`ptc-mode-briefing`,content:Ai(q(n.base),$),display:!1}}}})}export{V as BUILTIN_BINDING_NAMES,Et as DEFAULT_BINDING_NAMES,z as DEFAULT_CONFIG,bi as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,qt as MAX_LINE_CHARS,gi as MODE_REQUIRED_TOOL_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,yi as PTC_MODE_CONFIG_FILE,_i as PTC_MODE_ENTRY_TYPE,vi as PTC_MODE_STATUS_KEY,hi as PTC_MODE_TOOL_NAMES,Ni as PTC_SKILL_LOAD_INSTRUCTION,ji as SKILL_READING_TOOL_NAMES,Vr as TurnPools,De as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Mt as WorkerPool,Di as bindingSource,Ai as buildModeInstruction,Fi as buildPtcSkillsSection,kt as createBuiltinBindings,Oe as createWorkerEnv,Ei as decideModeEntry,Li as default,Oi as detectExternalLoadoutChange,Ae as effectiveTimeoutMs,xi as initialModeState,Ti as modeLoadout,Si as readDefaultModeConfig,an as renderModelValue,ki as resolveBaseOnStart,ke as resolveConfig,Ht as runPtcProgram,wi as sameToolSet,K as sanitizeText,Pi as skillsSectionDropped,Yt as stripAnsi};
43
+ `)}const Ui=[`read`,`bash`],Wi=`Use the read tool to load a skill's file when the task matches its description.`,Gi=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function Ki(e){return!Ui.some(t=>e.includes(t))}function qi(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Wi)?n.replace(Wi,Gi):`${Gi}\n\n${n}`}function Ji(e){let t=e.taskId;return typeof t==`string`?t:void 0}function Yi(e){return g({name:`ptc_subagent`,label:`PTC Subagent`,description:[`Start a fresh pi agent as a child process: it gets its own context, its own model and its own tools, and it cannot see or change this session except through what it returns. Use it for work that would otherwise flood this context: a survey, a second opinion, or a task that can run while you do something else.`].join(`
44
+ `),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:Nt,async execute(t,n){let r=await At(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=Ji(r),a=i===void 0?{taskId:void 0,status:r.status,exitCode:r.exitCode}:{taskId:i,status:`background`,exitCode:void 0};if(i!==void 0)return{content:[{type:`text`,text:`Started background task `+i}],details:a};if(r.status===`rejected`)throw Error(`ptc_subagent refused the call: `+r.errorMessage);return{content:[{type:`text`,text:r.text}],details:a}}})}const $=Di;function Xi(e,t){return[`PTC mode on — ${t===`all-but-ptc`?`all other tools`:`built-in tools (now reachable only as tools.<name> inside a program)`} hidden.`,`Bindings available inside a program: ${K(e).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
45
+ `)}function Zi(e,t={}){let n=Oi(),r=t.surfaceMode===void 0?Pi(y(),t.codemode):{surfaceMode:t.surfaceMode,source:`file`},i=!1,a=new Yr,o=()=>zi(n,e.getActiveTools()),s=mn(),c=hn();if(r.surfaceMode===`off`)return;let l=t.backgroundRuntime??hi({concurrency:L({}).dispatchConcurrency}),u=!1,d=e=>{console.warn(`[pi-ptc.background] `+e)},f=t=>{if(t.length!==0){if(u){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},p=async e=>{let{items:t,acks:n}=await l.drainNotifications(e),r=t.filter(e=>_i(e.record));for(let e of yi(r))f(vi(e,{batchId:Ce(),deliveredAtMs:l.clock()}));await l.acknowledgeNotifications(n)},m=async()=>{let e=await l.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},h=async()=>{for(let e of await m())await p(e)},g=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await p(e)};l.pipeline.onIdleWake(e=>{p(e).catch(e=>{d(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})}),r.surfaceMode===`full`&&(e.registerTool(or({getBindingSourceNames:o,getPool:()=>a.get(`run_code`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(fr({getBindingSourceNames:o,getPool:()=>a.get(`workflow`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps}))),r.surfaceMode===`subagents`&&e.registerTool(Yi({cwd:process.cwd(),depth:s,maxDispatchDepth:I.maxDispatchDepth,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(Ur(l.registry)),e.registerTool(Kr(l.registry,l.outputStorage)),e.registerTool(Jr(l.registry,l.lifecycle,{clock:l.clock})),e.on(`turn_start`,async()=>{u=!0}),e.on(`agent_settled`,async()=>{u=!1;try{await h()}catch(e){d(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new Yr,await e.drain()});let _=e=>{e.ui.setStatus(Ti,n.enabled?e.ui.theme.fg(`accent`,`PTC`):void 0)},v=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Q,{enabled:!0,base:[...t]}),_(a),a.ui.notify(o,`info`)},b=(t,r)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,i=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(r.customType,{enabled:!1}),_(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},x=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode (built-in tools reachable only from inside a PTC program)`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}b(r,{announce:!0,customType:Q});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${K(n.base).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=Ri({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:$});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}v(a.base,a.loadout,r,Xi(a.base,$))}}),e.on(`session_start`,async(t,n)=>{u=!1;let i=await l.bindSession(n.sessionManager?.getSessionDir?.(),e=>n.ui.notify(e,`warning`));try{await g(i)}catch(e){d(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let a=ki(y());a.error!==void 0&&n.ui.notify(`pi-ptc-subagents: ${a.error}`,`warning`),r.error!==void 0&&r.error!==a.error&&n.ui.notify(`pi-ptc-subagents: ${r.error}`,`warning`);let o=r.codemode;if(o!==void 0&&!o.present&&n.ui.notify(`pi-ptc-subagents: no surfaceMode is set, and the codemode probe reported `+o.how+`, so the surface defaults to full. That is the safe direction, not an error. If this pi really does ship pi's own codemode, set "surfaceMode" in ptc.json -- an explicit key always wins over detection.`,`info`),o!==void 0&&r.source!==`file`){let t=e.getAllTools().some(e=>e.name===`codemode`);!o.present&&t&&n.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+o.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Set an explicit "surfaceMode" in ptc.json to pick one.`,`warning`),o.present&&!t&&n.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions or --exclude-tools codemode), so the detected surface is "subagents" with no orchestrator. Set "surfaceMode" to "full" in ptc.json to use ptc_run_code instead.`,`warning`)}r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)&&n.ui.notify(`pi-ptc-subagents: surfaceMode is subagents, but codemode is not active in this session, so there is no orchestration tool. Add codemode to your pi tool list (the --tools flag or the default tools setting), or set surfaceMode to "full" to use ptc_run_code instead.`,`warning`);let s=x(n),{base:c,restoreFirst:f}=Vi(s,e.getActiveTools());f&&e.setActiveTools([...c]);let p=Ri({mode:n.mode,defaultMode:a.defaultMode,active:c,manual:!1,hide:$}),m=s?.enabled??p.enter;if(p.enter&&m){v(c,p.loadout,n,Xi(c,$));return}_(n),!p.enter&&p.reason!==`not-tui`&&s===void 0&&p.reason===`restricted-session`&&n.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{u=!1;try{await l.shutdown(`session_ended_while_running`)}catch(e){d(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let S=!1,C=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){S&&=(delete e.sections.skills,!1);return}let r=qi(e.skills);r.length!==0&&(e.sections.skills=r,S=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(C(a,Ki(e.getActiveTools())),n.enabled){if(Bi(n,e.getActiveTools())){b(r,{announce:!1,customType:Q}),C(a,Ki(e.getActiveTools())),r.ui.notify(`PTC mode off — another extension changed the active tool set.`,`warning`);return}if(i)return i=!1,{message:{customType:`ptc-mode-briefing`,content:Hi(K(n.base),$),display:!1}}}})}export{B as BUILTIN_BINDING_NAMES,jt as DEFAULT_BINDING_NAMES,I as DEFAULT_CONFIG,Di as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,tn as MAX_LINE_CHARS,wi as MODE_REQUIRED_TOOL_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Ei as PTC_MODE_CONFIG_FILE,Q as PTC_MODE_ENTRY_TYPE,Ti as PTC_MODE_STATUS_KEY,Ci as PTC_MODE_TOOL_NAMES,Gi as PTC_SKILL_LOAD_INSTRUCTION,Ui as SKILL_READING_TOOL_NAMES,Yr as TurnPools,Me as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Rt as WorkerPool,zi as bindingSource,Hi as buildModeInstruction,qi as buildPtcSkillsSection,Ft as createBuiltinBindings,Ne as createWorkerEnv,Ri as decideModeEntry,Zi as default,Bi as detectExternalLoadoutChange,Pe as effectiveTimeoutMs,Oi as initialModeState,Li as modeLoadout,ki as readDefaultModeConfig,Pi as readSurfaceModeConfig,pn as renderModelValue,Vi as resolveBaseOnStart,L as resolveConfig,qt as runPtcProgram,Ii as sameToolSet,G as sanitizeText,Ki as skillsSectionDropped,rn as stripAnsi};
43
46
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ptc-subagents",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "DSH PTC mode (ptc_run_code + ptc_workflow) for pi",
5
5
  "keywords": [
6
6
  "pi",