pi-ptc-subagents 3.3.3 → 4.0.0

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,116 @@ 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
+ ## [4.0.0] - 2026-10-19
9
+
10
+ ### Added
11
+
12
+ - **The `ptc_subagent` call row shows the dispatch, not its argument dump.** The tool had no
13
+ renderer, so pi fell back to its raw argument serialisation — one enormous
14
+ `ptc_subagent task="…\\n\\n…"` line of JSON-escaped prose (2026-10-19 field report). It now
15
+ registers a `renderCall`: collapsed it reads as a heading (agent, foreground/background and
16
+ read-only flags, and a pinned `model` when one was passed) with one task preview line and
17
+ `… 还有 N 行`; `ctrl+e` expands `label` / `why` rows and the task block — the first task line
18
+ plus up to the existing `MAX_LOG_LINES_EXPANDED` continuation lines, so no new cap is
19
+ introduced. Follows ADR-0013's "no escaped JSON in the call row" rule.
20
+ - **`whyEnabled`, a default-on switch for the dispatch `why` block.** `~/.pi/agent/ptc.json` takes a
21
+ boolean `whyEnabled`; when it is `false`, a `why` passed to `pi.dispatch` / `ptc_subagent` is
22
+ dropped instead of delivered, and both the foreground result and the background record say that a
23
+ suppression happened. **The switch fails on:** a non-boolean value, an unparseable file, or a file
24
+ that is not a JSON object all leave the feature ON — a broken value must never remove it. A broken
25
+ _key_ is reported once at `session_start` with the path, the key and the type that arrived; a broken
26
+ _file_ is already reported by the default-mode reader, so one typo produces one notice. The
27
+ `why` argument stays on the schema either way, so a running program is never rejected for passing
28
+ an argument whose value the switch drops. `DispatchResult.whySuppressed` and
29
+ `TaskRecord.whySuppressed` record **that a reason was withheld, never what it was** — a background
30
+ dispatch returns a handle rather than a result, so without the record it would have no way at all
31
+ to say so. See ADR-0043.
32
+ - **`/ptc why on|off`**, a session-scoped override for the switch above. It records one session entry
33
+ and never writes `ptc.json` — the difference is "about this conversation" against "about every
34
+ future one". A resumed session restores the last record; a new one starts from the file. Bare
35
+ `/ptc why` reports the value _and_ which of the two is in force, and an argument that is neither
36
+ `on` nor `off` warns and changes nothing. See ADR-0043.
37
+ - **A succeeded background task's completion notification now states its report channel.** The
38
+ `<bg-task-notification>` for a `succeeded` record gains a `<report-channel>` child —
39
+ `tool`, `prompt-json`, `none` or `opted-out`, the same **total** field ADR-0032 defines —
40
+ rendered between `<error-message>` and `<output-ref>`. Before this, a model that wanted to
41
+ know whether a finished child had honoured the report contract had to poll `ptc_task_output`;
42
+ the push it already receives now answers it, once per finished child. The element is absent from
43
+ every other event because only a `succeeded` close declares a channel: a running task has not
44
+ reported _yet_, and a `failed` / `lost` / `canceled` close has no report claim to state
45
+ (`none` and `opted-out` are claims about a finished child, not the absence of one). See
46
+ ADR-0022 §7 as amended (2026-10-19).
47
+
48
+ ### Changed
49
+
50
+ - **BREAKING — a dispatch's `goal` is now `why`.** `pi.dispatch` and `ptc_subagent` took an
51
+ optional `goal` since 3.4.0; that argument is now `why`, and the child's block is now
52
+ `<pi-ptc-why>` instead of `<pi-ptc-goal>`. A PTC program that passes `goal` must pass `why`.
53
+ The block's **wording is unchanged** — it still reads "This goal is context for doing it well" —
54
+ because that sentence was held constant across ADR-0042's 180 runs and renaming the tag does not
55
+ re-test the contrast; rewriting the sentence would change what was held still. See ADR-0043.
56
+ The rename is not cosmetic: in the agent ecosystem `goal` names an objective or a loop, a thing
57
+ worked toward over time, which is not what this argument holds — the reason one slice was cut out.
58
+ `background` was the other candidate and was unavailable, because the dispatch schema already
59
+ carries a `background` argument meaning "detach the child". No compatibility alias is kept: the
60
+ only consumer is a model reading the live schema each session, and a second name for one value
61
+ would cost exactly the comprehension this change buys back.
62
+ - **The background-dispatch guide now says which model a dispatched child runs, and that it is
63
+ not the caller's.** The child is a fresh `pi` subprocess, so its model resolves — first match
64
+ wins — as the dispatch's `model` argument, then the named agent definition's frontmatter
65
+ `model:`, then pi's own global default; the calling session's current model (and therefore a
66
+ provider switched to mid-session) is **not** inherited. Recorded after the 2026-10-19 field
67
+ report: the parent had switched provider, and the child it dispatched afterwards ran on pi's
68
+ default provider and hit a 429. No behaviour change — the resolution order is what the code
69
+ already did, and the guide states it so the failure is also preventable. See the background
70
+ dispatch guide, `docs/usage/bgdispatch.md`.
71
+ - **The TUI task panel now shows why a background task failed.** The `task-output` panel prints
72
+ the record's failure reason as an `error: …` line first in the output block — ahead of the
73
+ preview or the empty-output placeholder — and the `task-list` panel appends one to each
74
+ `failed` / `lost` row whose record carries an `errorMessage`, so a child that died before
75
+ writing output stays legible in the panel instead of as an empty preview, without a
76
+ `ptc_task_output` call. A `lost` record carries the sweep's reason
77
+ (`session_ended_while_running` / `lost_on_session_restart`) and gets the row too; a
78
+ `canceled` task carries no reason and does not. Both rows reuse the panel's existing
79
+ `MAX_ERROR_CHARS` bound (120, first non-blank line), so no new cap or number is added, and
80
+ neither annotation counts against the panel's row caps — see ADR-0022 §11. A settled
81
+ failure's empty-output placeholder also stops claiming `(no output yet)`: with a reason on the
82
+ record it reads `(no output)`, while a page with no recorded reason keeps the `yet` (this
83
+ payload carries no status to tell a live task from an unlabelled close).
84
+
85
+ ### Fixed
86
+
87
+ - **A background task that failed with an empty log now says why — on the notification, in
88
+ `ptc_task_output`, and in the host log.** A 2026-10-19 field report: a child was rate-limited
89
+ (429) before writing anything, its output log was 0 bytes, the `TaskRecord` carried the reason
90
+ in `errorMessage`, and the parent agent received only `status="failed"` — it read the empty
91
+ log as an infrastructure fault and could not act on the real one. Three surfaces now carry the
92
+ cause. A `<bg-task-notification>` whose record carries an `errorMessage` gains an optional
93
+ `<error-message>` (head-truncated to at most 1024 code points, an ellipsis marking the cut, and
94
+ XML-escaped; absent when the record has no such text), so the push that announces the failure
95
+ states it. `ptc_task_output`
96
+ renders the reason as an `error=…` line ahead of a failed/lost task's body and exposes the
97
+ record's `errorMessage` on the codemode projection as `error_message` (and on `details` as
98
+ `errorMessage`), so the pull after the push reads the same reason. The background pump logs a `logger.warn` with the
99
+ task id and the failure reason, so the host operator no longer sees only an empty child log. The
100
+ terminal empty-output fallback also stops saying "yet": a terminal task reads
101
+ `(no output; task <id> is <status>)`, while `running` / `stopping` keep
102
+ `(no output yet; …)`. See ADR-0022 §7 as amended (2026-10-19).
103
+
104
+ ## [3.4.0] - 2026-10-19
105
+
106
+ ### Added
107
+
108
+ - **`goal` on a dispatch.** `pi.dispatch` and `ptc_subagent` take an optional `goal`: the caller's
109
+ reason for this dispatch slice, not the conversation and not the user's original request. The
110
+ child receives it as its own `<pi-ptc-goal>` block after the host's policy block, and is told the
111
+ task remains the deliverable. Measured across five model configurations on twelve conflict
112
+ fixtures: 35 discordant pairs favoured the real goal, none favoured either control, and an
113
+ equal-length placebo passed 2 of 60 runs. See ADR-0042.
114
+ - `docs/research/wayfinder-208-negative-results.md` records two candidate features that were built,
115
+ measured, and dropped (the summary arms and the provenance fields), with the method notes that
116
+ make their negative results reusable.
117
+
8
118
  ## [3.3.3] - 2026-10-18
9
119
 
10
120
  ### Fixed
package/README.md CHANGED
@@ -169,6 +169,12 @@ per row, with the withheld amount stated in-band. A scalar is one line (`→ 47`
169
169
  bounds ([ADR-0012](./docs/adr/0012-model-facing-result-text.md)): a compact value under 100
170
170
  characters stays on one line, every line caps at 200. Nothing is ever printed as escaped JSON.
171
171
 
172
+ The `ptc_subagent` call row follows the same rule: it reads as a heading — agent, state flags, and
173
+ a pinned model when the caller set one — plus one task preview line and a withheld count, and
174
+ `ctrl+e` expands the `label` / `why` rows and the task block (the first task line plus up to
175
+ `MAX_LOG_LINES_EXPANDED` continuation lines). A dispatch's long prose is never dumped as its
176
+ JSON-escaped argument string.
177
+
172
178
  ## Images
173
179
 
174
180
  An image read _inside_ a program — `await tools.read({ path: "shot.png" })` — is attached to
@@ -186,6 +192,15 @@ and reaches `read` / `bash` / `edit` / `write` / `grep` / `find` / `ls` through
186
192
  …) stay directly callable. Turn it off for one session with `/ptc off` (also `/ptc on`, `/ptc`
187
193
  for status), permanently with `{ "defaultMode": false }` in `~/.pi/agent/ptc.json`.
188
194
 
195
+ A dispatch may also carry the caller's **reason** for the slice: an optional `why` on
196
+ `pi.dispatch` / `ptc_subagent`, which reaches the child as its own `<pi-ptc-why>` block after the
197
+ host's policy block, and never widens the task. It is on by default. Turn it off for one session
198
+ with `/ptc why off` (`/ptc why` reports the current value and whether it came from the session or
199
+ the file), or permanently with `{ "whyEnabled": false }` in `~/.pi/agent/ptc.json`. A value that is
200
+ not a boolean leaves the block **on** and says so at startup — a default-on switch that could turn
201
+ itself off on a typo is the wrong direction. A `why` that was dropped is reported on the dispatch
202
+ result (`whySuppressed`), never silently ([ADR-0043](./docs/adr/0043-a-why-switch-and-a-name.md)).
203
+
189
204
  Which model-facing tools this package registers is **detected, not configured** — there is no
190
205
  setting for it ([ADR-0034](./docs/adr/0034-surface-is-detected-not-set.md)). The short version:
191
206
  a pi whose `codemode` is loaded _and_ callable by the model gets the `subagents` surface
package/dist/index.d.ts CHANGED
@@ -291,6 +291,21 @@ interface TaskRecord {
291
291
  * tier was asked for, which is the same claim the foreground result's absent field makes.
292
292
  */
293
293
  readOnlyTier?: ReadOnlyTier;
294
+ /**
295
+ * ADR-0043: `true` when the caller passed a `why` and this session's switch dropped it, so the
296
+ * child's prompt carried no `<pi-ptc-why>` block. Written at SPAWN, alongside `readOnlyTier`,
297
+ * because it too is a fact about the request rather than about the child's output.
298
+ *
299
+ * **The dropped value is deliberately not here.** ADR-0042 declined to persist `why` on the
300
+ * TaskRecord because the value is a caller-held fact, not a host-measured one. That reasoning
301
+ * reaches the value and stops at the event: "a suppression happened" is observed by the host and
302
+ * is the only thing a background caller can otherwise not learn, since a background dispatch
303
+ * returns a handle and has no result to put it on.
304
+ *
305
+ * Absent means no `why` was passed, which is the same claim the foreground
306
+ * `DispatchResult.whySuppressed`'s absence makes — the two fronts state one fact, not two.
307
+ */
308
+ whySuppressed?: true;
294
309
  /**
295
310
  * Host-observed token usage for this child (ADR-0032's counter, moved to its own carrier).
296
311
  * Written on every terminal close for any child the host actually started — independent of
@@ -524,6 +539,23 @@ interface DispatchDeps {
524
539
  * can dereference the bytes (BG-07).
525
540
  */
526
541
  outputStorage?: OutputStorage;
542
+ /**
543
+ * ADR-0043: whether the caller may hand the child a `why`. Absent means ON, which is this
544
+ * package's default and the state ADR-0042's measurement was taken in — so every existing
545
+ * zero-argument call site keeps the behaviour it had before the switch existed.
546
+ *
547
+ * The FILE is read ONCE, at extension load, and carried here rather than consulted per call for
548
+ * the reason #73 already records for `optInBindings`: a switch read per call would let the third
549
+ * dispatch of a run see a different answer from the first, with nothing in the transcript
550
+ * recording that it changed.
551
+ *
552
+ * "Read once" is about this file, not about the value being frozen for the session — `/ptc why`
553
+ * overwrites this exact field mid-session by design (spec D8, ADR-0043), and the `whyConfig`
554
+ * JSDoc in `index.ts` carries that half. What keeps the two together is that the write is
555
+ * recorded: `/ptc why` appends a session entry, so a program that saw the value change knows
556
+ * from the transcript that a user changed it rather than finding it had moved underneath a run.
557
+ */
558
+ whyEnabled?: boolean;
527
559
  }
528
560
  /**
529
561
  * ADR-0041: the two read-only tiers. `strict` narrows what the child can be handed;
@@ -819,6 +851,43 @@ interface DefaultModeConfig {
819
851
  * on** — the caller should surface the problem rather than silently changing behavior.
820
852
  */
821
853
  export declare function readDefaultModeConfig(agentDir: string): DefaultModeConfig;
854
+ /** Result of reading the `why` switch, with enough detail to warn about a broken file. */
855
+ interface WhyEnabledConfig {
856
+ whyEnabled: boolean;
857
+ source: "file" | "default" | "invalid";
858
+ error?: string;
859
+ }
860
+ /**
861
+ * Read `whyEnabled` from the agent-dir config file — ADR-0043's switch for the dispatch caller's
862
+ * reason.
863
+ *
864
+ * The three outcomes are borrowed from {@link readDefaultModeConfig} rather than invented, because
865
+ * this package already decided what a broken boolean in this file means and a second answer for the
866
+ * same file would be a second failure vocabulary:
867
+ *
868
+ * - Absent file, absent key → **on**. This package is default-on (CONTEXT.md), and ADR-0042's
869
+ * measurement is why the block exists at all.
870
+ * - A non-boolean value, or a file that is not a JSON object, or unparseable JSON → reported as
871
+ * `invalid` **and still resolved to on**.
872
+ *
873
+ * That last line is the one worth stating plainly: a broken value must never be able to take the
874
+ * feature away. A switch whose parse failure silently removes a block the user never asked to
875
+ * remove is worse than one that ignores the typo and says so — the failure here is LOUD (a
876
+ * `session_start` warning naming the path and the key) and the behaviour is UNCHANGED.
877
+ *
878
+ * **A file too broken to parse is not this function's to report**, and an earlier draft got that
879
+ * wrong in a way `tests/extension.test.ts` caught: this reader raised its own "not valid JSON" and
880
+ * `readDefaultModeConfig` raised the identical sentence for the same file, so one typo produced
881
+ * two notices. Two identical warnings train a user to ignore warnings, which defeats the loudness
882
+ * the previous paragraph is buying. The file's parse belongs to the reader that owns
883
+ * `defaultMode`; this one reports only what is wrong with the `whyEnabled` KEY, exactly as
884
+ * `readOptInBindingsConfig` draws the same boundary for `optInBindings`.
885
+ *
886
+ * What this key does NOT do: it stays off the model-facing schema either way. The parameter keeps
887
+ * its place in `DISPATCH_PARAMETERS` so a running program is never rejected for passing an argument
888
+ * whose value this switch decides to drop.
889
+ */
890
+ export declare function readWhyEnabledConfig(agentDir: string): WhyEnabledConfig;
822
891
  /** Result of reading the opt-in binding config, with enough detail to warn about a broken file. */
823
892
  interface OptInBindingsConfig {
824
893
  optInBindings: readonly BuiltinBindingName[];
@@ -1736,6 +1805,19 @@ export interface PtcSubagentsOptions {
1736
1805
  codemodeActivation?: CodemodeActivationResolution;
1737
1806
  }
1738
1807
  export default function ptcSubagents(pi: ExtensionAPI, options?: PtcSubagentsOptions): void;
1808
+ /**
1809
+ * `customType` for this session's `why` record (`pi.appendEntry`).
1810
+ *
1811
+ * Separate from `PTC_MODE_ENTRY_TYPE` and it has to be: both readers scan the SAME entry list
1812
+ * backwards for their own type, so a shared one would let `/ptc why off` restore as a mode record
1813
+ * on the next `session_start` -- and `/ptc off` restore as a `why` decision. Two entry types, two
1814
+ * independent switches, and neither recoverable as the other.
1815
+ *
1816
+ * Declared here rather than beside `PTC_MODE_ENTRY_TYPE` in `src/mode/ptc-mode.ts` because that
1817
+ * module is PTC MODE's state machine; this switch has nothing to say about the loadout, and
1818
+ * everything it touches lives in this file.
1819
+ */
1820
+ export declare const PTC_WHY_ENTRY_TYPE = "ptc-why";
1739
1821
  //#endregion
1740
1822
  export type { Binding, BindingContext, BindingTable, CodemodePresence, CodemodeSwitch, CodemodeSwitchResolution, CodemodeSwitchSource, CreateBuiltinBindingsOptions, DefaultModeConfig, DetectedSurface, LegacySurfaceKey, ModeBlockReason, ModeEntryDecision, ModeEntryInput, ModeHideStrategy, OptInBindingName, OptInBindingsConfig, PersistedModeState, PtcConfig, PtcErrorKind, PtcErrorShape, PtcImage, PtcJsonValue, PtcModeState, PtcRunOutcome, PtcSurface, RunPtcProgramOptions, TurnPoolsOptions, WorkerPoolOptions, WorkerPoolStats, WorkerPoolWorkerOptions };
1741
1823
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,62 +1,67 @@
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 te,writeFileSync as ne}from"node:fs";import*as E from"node:os";import{homedir as D,tmpdir as O}from"node:os";import*as k from"node:path";import{basename as re,dirname as A,join as j,relative as ie,resolve as M,sep as ae}from"node:path";import{spawn as oe}from"node:child_process";import{randomBytes as se,randomUUID as ce}from"node:crypto";import{ok as N}from"node:assert/strict";import{MessageChannel as le,Worker as ue}from"node:worker_threads";import de from"node:diagnostics_channel";import{fileURLToPath as P,pathToFileURL as fe}from"node:url";import{truncateToWidth as F,visibleWidth as I}from"@earendil-works/pi-tui";import{appendFile as pe,mkdir as me,readFile as he,readdir as ge,rename as _e,unlink as ve,writeFile as ye}from"node:fs/promises";import{minimatch as be}from"minimatch";function L(e){return g(e)}const xe=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function Se(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(xe[n%32]??`0`)+t,n=Math.floor(n/32);return t}function Ce(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+=xe[n>>>r&31];return t.padEnd(16,`0`)}function we(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 Te(e){let t=e.randomBytes??(e=>new Uint8Array(se(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?we(r):t(10);return n=a,r=o,Se(a)+Ce(o)}}}const Ee=Te({now:()=>Date.now()});function De(){return Ee.next()}function Oe(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function ke(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function Ae(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function je(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 Me(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 Ne={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Pe(e){return e.length<=200?e:e.slice(0,200)+`…`}var Fe=class{#e;constructor(e={}){this.#e=e.logger??Ne}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=Me(e,t),r=n[0],i=n.slice(1),a=oe(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:De(),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=Oe(e);n?Ae(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=Oe(n);e?Ae(o,e):this.#t(s,n),o.lineBuffer=``}je(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
4
- `,o.exited||je(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;ke(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): `+Pe(t))}};const Ie=`ptc_child_report`,R=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}),Le=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Re(e=process.env){let t={};for(let n of Le){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function ze(e={}){let t={...R};for(let n of Object.keys(R)){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 Be(e,t=R){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Ve={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},He=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Ue=/* @__PURE__ */ new Set([`running`,`stopping`]);function We(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.stderrDiagnostic!==void 0)return t.stderrDiagnostic;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function Ge(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Ke(e){return typeof e==`string`&&e.length>0}const qe=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function Je(e){return typeof e==`string`&&qe.has(e)}function Ye(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Xe(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 Ze(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Qe=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??Xe,this.#a=Te({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 Ke(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())Ue.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=Ke(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(!Ge(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`&&!Je(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:We(n,e,i,r),usage:e.usage,...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!Ue.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};He.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.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.usage!==void 0&&(a.usage=r.usage),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=Ve[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(!Ke(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:Ze(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 $e(e,t){return new Qe(e,t)}function et(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function tt(e){for(let t=1;t<e.length;t++)if(et(e[t-1],e[t])>0)return!1;return!0}var nt=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){N(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){N(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=tt(t)?[...t]:[...t].sort(et),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(et),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 rt=new Fe;var it=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 at=new it(R.dispatchConcurrency);let ot;function st(e,t){return e.taskRegistry===void 0?(ot??=new Qe(new nt,{clock:t}),ot):e.taskRegistry}const ct={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},lt=[`read`,`grep`,`find`,`ls`];function z(e){return e===`strict`||e===`lenient`?e:void 0}function ut(e){return e==null||e===`strict`||e===`lenient`}function dt(e){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`invalid readOnly value: `+(typeof e==`object`&&e?JSON.stringify(e):String(e))+` (readOnly accepts "strict" or "lenient"; null and undefined ask for no tier)`}}function B(e,t){return t===void 0?e:{...e,readOnlyTier:t}}const ft=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function pt(e,t,n,r={}){let i=r.reportContract!==!1,a=z(r.readOnly),o=[`<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" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],...a===`lenient`?[`You were dispatched read-only: do not create, modify or delete files, and do not run commands that would. Your tools are otherwise all still available to you — this is an instruction, not a restriction, so a task that genuinely needs to write is worth saying so rather than failing quietly.`]:[],`</pi-ptc-context>`].join(`
5
- `);return e.length===0?o:e+`
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 E,statSync as D,writeFileSync as ee}from"node:fs";import*as O from"node:os";import{homedir as k,tmpdir as A}from"node:os";import*as j from"node:path";import{basename as te,dirname as M,join as N,relative as ne,resolve as P,sep as re}from"node:path";import{spawn as ie}from"node:child_process";import{randomBytes as ae,randomUUID as oe}from"node:crypto";import{ok as F}from"node:assert/strict";import{MessageChannel as se,Worker as ce}from"node:worker_threads";import le from"node:diagnostics_channel";import{fileURLToPath as ue,pathToFileURL as de}from"node:url";import{truncateToWidth as I,visibleWidth as L}from"@earendil-works/pi-tui";import{appendFile as fe,mkdir as pe,readFile as me,readdir as he,rename as ge,unlink as _e,writeFile as ve}from"node:fs/promises";import{minimatch as ye}from"minimatch";function R(e){return g(e)}const be=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function xe(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(be[n%32]??`0`)+t,n=Math.floor(n/32);return t}function Se(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+=be[n>>>r&31];return t.padEnd(16,`0`)}function Ce(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 we(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?Ce(r):t(10);return n=a,r=o,xe(a)+Se(o)}}}const Te=we({now:()=>Date.now()});function Ee(){return Te.next()}function De(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function Oe(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function ke(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function Ae(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 je(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 Me={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Ne(e){return e.length<=200?e:e.slice(0,200)+`…`}var Pe=class{#e;constructor(e={}){this.#e=e.logger??Me}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=je(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:Ee(),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=De(e);n?ke(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=De(n);e?ke(o,e):this.#t(s,n),o.lineBuffer=``}Ae(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
4
+ `,o.exited||Ae(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Oe(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): `+Ne(t))}};const Fe=`ptc_child_report`,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}),Ie=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Le(e=process.env){let t={};for(let n of Ie){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function Re(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 ze(e,t=z){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Be={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ve=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),He=/* @__PURE__ */ new Set([`running`,`stopping`]);function Ue(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.stderrDiagnostic!==void 0)return t.stderrDiagnostic;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function We(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Ge(e){return typeof e==`string`&&e.length>0}const Ke=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function qe(e){return typeof e==`string`&&Ke.has(e)}function Je(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Ye(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 Xe(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ze=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??Ye,this.#a=we({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 Ge(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())He.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=Ge(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(!We(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`&&!qe(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:Ue(n,e,i,r),usage:e.usage,...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!He.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};Ve.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.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.usage!==void 0&&(a.usage=r.usage),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=Be[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(!Ge(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:Xe(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 Ze(e,t)}function $e(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function et(e){for(let t=1;t<e.length;t++)if($e(e[t-1],e[t])>0)return!1;return!0}var tt=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){F(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){F(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=et(t)?[...t]:[...t].sort($e),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($e),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 nt=new Pe;var rt=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 it=new rt(z.dispatchConcurrency);let at;function ot(e,t){return e.taskRegistry===void 0?(at??=new Ze(new tt,{clock:t}),at):e.taskRegistry}const st={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},ct=[`read`,`grep`,`find`,`ls`];function B(e){return e===`strict`||e===`lenient`?e:void 0}function lt(e){return e==null||e===`strict`||e===`lenient`}function ut(e){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`invalid readOnly value: `+(typeof e==`object`&&e?JSON.stringify(e):String(e))+` (readOnly accepts "strict" or "lenient"; null and undefined ask for no tier)`}}function dt(e,t){return t===void 0?e:{...e,readOnlyTier:t}}function ft(e,t){let n=typeof e==`string`?e.trim():``;return n.length===0?{why:void 0,suppressed:!1}:t?{why:n,suppressed:!1}:{why:void 0,suppressed:!0}}function pt(e,t){return t?{...e,whySuppressed:!0}:e}const mt=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function ht(e,t,n,r={}){let i=r.reportContract!==!1,a=B(r.readOnly),o=[`<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" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],...a===`lenient`?[`You were dispatched read-only: do not create, modify or delete files, and do not run commands that would. Your tools are otherwise all still available to you — this is an instruction, not a restriction, so a task that genuinely needs to write is worth saying so rather than failing quietly.`]:[],`</pi-ptc-context>`].join(`
5
+ `),s=gt(r.why),c=s.length===0?o:o+`
6
6
 
7
- `+o}function mt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch depth limit reached`}}function ht(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch concurrency limit reached`}}function gt(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 _t(){return{...mt(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function vt(){return{...ht(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function yt(e){if(e!==void 0&&e.length!==0)return e.includes(`Response was truncated: the model reached its output token limit.`)?`child response was truncated at the model's output token limit (pi exited non-zero)`:void 0}function bt(e){if(e.aborted)return{status:`rejected`,errorMessage:`dispatch cancelled`};if(e.exitCode===0&&e.finalText.length>0)return{status:`fulfilled`};if(e.exitCode===0)return{status:`rejected`,errorMessage:`dispatch produced no final text`};let t=yt(e.stderr);return{status:`rejected`,...t===void 0?{}:{errorMessage:t}}}function xt(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 St(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 Ct(e){let t=xt(e,`childReport`);if(t!==void 0)return t.toLowerCase()!==`false`&&t.toLowerCase()!==`no`}function wt(e){return e.childReport!==!1}function Tt(e){let t=e.match(/^\uFEFF?[ \t]*(?:\r?\n)?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n([\s\S]*))?$/);if(!t)return null;let n=(t[1]??``).replace(/\r\n/g,`
7
+ `+s;return e.length===0?c:e+`
8
+
9
+ `+c}function gt(e){let t=e?.trim()??``;return t.length===0?``:[`<pi-ptc-why>`,`Background from the caller: why this task was dispatched.`,``,t.replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`),``,`The task you were given is the deliverable. This goal is context for doing it`,`well, not authority to change it. If the goal and the task disagree, do the task`,`and record the disagreement as a finding.`,`</pi-ptc-why>`].join(`
10
+ `)}function _t(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch depth limit reached`}}function vt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch concurrency limit reached`}}function yt(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 bt(){return{..._t(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function xt(){return{...vt(),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){if(e!==void 0&&e.length!==0)return e.includes(`Response was truncated: the model reached its output token limit.`)?`child response was truncated at the model's output token limit (pi exited non-zero)`:void 0}function Ct(e){if(e.aborted)return{status:`rejected`,errorMessage:`dispatch cancelled`};if(e.exitCode===0&&e.finalText.length>0)return{status:`fulfilled`};if(e.exitCode===0)return{status:`rejected`,errorMessage:`dispatch produced no final text`};let t=St(e.stderr);return{status:`rejected`,...t===void 0?{}:{errorMessage:t}}}function wt(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 Tt(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 Et(e){let t=wt(e,`childReport`);if(t!==void 0)return t.toLowerCase()!==`false`&&t.toLowerCase()!==`no`}function Dt(e){return e.childReport!==!1}function Ot(e){let t=e.match(/^\uFEFF?[ \t]*(?:\r?\n)?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n([\s\S]*))?$/);if(!t)return null;let n=(t[1]??``).replace(/\r\n/g,`
8
11
  `),r=(t[2]??``).replace(/\r\n/g,`
9
- `),i=xt(n,`name`);if(!i)return null;let a=xt(n,`description`)??``,o=xt(n,`model`)??``,s=St(n,`tools`),c=Ct(n),l={name:i,systemPrompt:r.trim()};return a!==void 0&&(l.description=a),o!==void 0&&(l.model=o),s!==void 0&&(l.tools=s),c!==void 0&&(l.childReport=c),l}function Et(e){let t=e.replace(/^\uFEFF/,``).split(/\r?\n/).find(e=>e.trim().length>0);if(t===void 0)return!1;let n=t.trim();return n===`---`||/^name[ \t]*:/.test(n)}function Dt(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=kt(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r,source:`user`}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i,source:`project`});let o=/* @__PURE__ */ new Map,s=[];for(let{dir:e,boundary:t,source:n}of a){let r;try{r=C.readdirSync(e)}catch(n){Pt(e,t,n)||s.push(`pi.dispatch: cannot read agent directory ${e} (${At(n)}); the agents registered there are not listed`);continue}r.sort();for(let t of r){if(!t.endsWith(`.md`))continue;let r=k.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);s.push(`pi.dispatch: cannot read agent file ${r}: ${t}; skipping it`);continue}let a=Tt(i);if(!a){Et(i)&&s.push(`pi.dispatch: agent file ${r} looks like an agent definition but its frontmatter did not parse (no usable \`name:\`); it is not listed and cannot be dispatched`);continue}let c=o.get(a.name);if(c){c.source===n&&s.push(`pi.dispatch: agent name "${a.name}" is declared by both ${c.filePath} and ${r}; using ${c.filePath} and shadowing the other (#205)`);continue}o.set(a.name,{name:a.name,description:(a.description??``).trim(),source:n,filePath:r,...a.model===void 0?{}:{model:a.model},...a.tools===void 0?{}:{tools:a.tools},...a.childReport===void 0?{}:{childReport:a.childReport},systemPrompt:a.systemPrompt})}}return{definitions:o,diagnostics:s}}function Ot(e,t,n,r){let{definitions:i}=Dt({cwd:t,agentScope:n,homeDir:r?.homeDir}),a=i.get(e);if(a===void 0)return null;let o={name:a.name,source:a.source,systemPrompt:a.systemPrompt};return a.model!==void 0&&(o.model=a.model),a.tools!==void 0&&(o.tools=a.tools),a.childReport!==void 0&&(o.childReport=a.childReport),o}function kt(e){let t=e.homeDir??E.homedir();return{userDir:k.join(t,`.pi`,`agent`,`agents`),projectDir:k.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function At(e){let t=e?.code;return typeof t==`string`?t:String(e)}function jt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function Mt(e,t){let n=k.resolve(e),r=k.resolve(t),i=e=>k.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(Nt(e))return!0;return!1}return a===r&&Nt(r)}function Nt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function Pt(e,t,n){let r=At(n);return r!==`ENOENT`&&r!==`ENOTDIR`||jt(e)?!1:!Mt(e,t)}function Ft(e){let{definitions:t,diagnostics:n}=Dt(e);for(let e of n)console.warn(e);return[...t.values()].map(e=>({name:e.name,description:e.description,source:e.source}))}function It(e){return Ft(e).map(e=>e.name).sort()}function Lt(e){let t=Ft(e),n="`agent` is optional: omit it for a fresh generalist pi with pi's own system prompt and its full toolset. Name a definition to NARROW the child instead.";if(t.length===0)return n+` None are registered here, so there is nothing to name.`;let r=t.map(e=>{let t=e.description.length>0?e.description:`(no description given)`;return`- ${e.name} (${e.source} scope): ${t}`});return n+"\nRegistered definitions — pass `agentScope` matching the scope shown, since it defaults "+`to "user" and does not see the others:
12
+ `),i=wt(n,`name`);if(!i)return null;let a=wt(n,`description`)??``,o=wt(n,`model`)??``,s=Tt(n,`tools`),c=Et(n),l={name:i,systemPrompt:r.trim()};return a!==void 0&&(l.description=a),o!==void 0&&(l.model=o),s!==void 0&&(l.tools=s),c!==void 0&&(l.childReport=c),l}function kt(e){let t=e.replace(/^\uFEFF/,``).split(/\r?\n/).find(e=>e.trim().length>0);if(t===void 0)return!1;let n=t.trim();return n===`---`||/^name[ \t]*:/.test(n)}function At(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=Mt(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r,source:`user`}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i,source:`project`});let o=/* @__PURE__ */ new Map,s=[];for(let{dir:e,boundary:t,source:n}of a){let r;try{r=C.readdirSync(e)}catch(n){Lt(e,t,n)||s.push(`pi.dispatch: cannot read agent directory ${e} (${Nt(n)}); the agents registered there are not listed`);continue}r.sort();for(let t of r){if(!t.endsWith(`.md`))continue;let r=j.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);s.push(`pi.dispatch: cannot read agent file ${r}: ${t}; skipping it`);continue}let a=Ot(i);if(!a){kt(i)&&s.push(`pi.dispatch: agent file ${r} looks like an agent definition but its frontmatter did not parse (no usable \`name:\`); it is not listed and cannot be dispatched`);continue}let c=o.get(a.name);if(c){c.source===n&&s.push(`pi.dispatch: agent name "${a.name}" is declared by both ${c.filePath} and ${r}; using ${c.filePath} and shadowing the other (#205)`);continue}o.set(a.name,{name:a.name,description:(a.description??``).trim(),source:n,filePath:r,...a.model===void 0?{}:{model:a.model},...a.tools===void 0?{}:{tools:a.tools},...a.childReport===void 0?{}:{childReport:a.childReport},systemPrompt:a.systemPrompt})}}return{definitions:o,diagnostics:s}}function jt(e,t,n,r){let{definitions:i}=At({cwd:t,agentScope:n,homeDir:r?.homeDir}),a=i.get(e);if(a===void 0)return null;let o={name:a.name,source:a.source,systemPrompt:a.systemPrompt};return a.model!==void 0&&(o.model=a.model),a.tools!==void 0&&(o.tools=a.tools),a.childReport!==void 0&&(o.childReport=a.childReport),o}function Mt(e){let t=e.homeDir??O.homedir();return{userDir:j.join(t,`.pi`,`agent`,`agents`),projectDir:j.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function Nt(e){let t=e?.code;return typeof t==`string`?t:String(e)}function Pt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function Ft(e,t){let n=j.resolve(e),r=j.resolve(t),i=e=>j.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(It(e))return!0;return!1}return a===r&&It(r)}function It(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function Lt(e,t,n){let r=Nt(n);return r!==`ENOENT`&&r!==`ENOTDIR`||Pt(e)?!1:!Ft(e,t)}function Rt(e){let{definitions:t,diagnostics:n}=At(e);for(let e of n)console.warn(e);return[...t.values()].map(e=>({name:e.name,description:e.description,source:e.source}))}function zt(e){return Rt(e).map(e=>e.name).sort()}function Bt(e){let t=Rt(e),n="`agent` is optional: omit it for a fresh generalist pi with pi's own system prompt and its full toolset. Name a definition to NARROW the child instead.";if(t.length===0)return n+` None are registered here, so there is nothing to name.`;let r=t.map(e=>{let t=e.description.length>0?e.description:`(no description given)`;return`- ${e.name} (${e.source} scope): ${t}`});return n+"\nRegistered definitions — pass `agentScope` matching the scope shown, since it defaults "+`to "user" and does not see the others:
10
13
  `+r.join(`
11
- `)}function Rt(e){let{userDir:t,projectDir:n}=kt(e),r=It(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t} (user scope) or ${n} (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body. the \`name:\` header IS the agent's name: naming the file after it is the convention, but the two are independent, so a definition is dispatchable under the name it declares even when the file is named otherwise`}function zt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:`agent, when given, must be a non-empty string — omit it entirely to dispatch a generalist child; `+Rt(e)}}function Bt(e){return e!==void 0&&(typeof e!=`string`||e.trim().length===0)}function Vt(e){return e===void 0}function Ht(e,t,n){if(Vt(e.agent))return{kind:`resolved`,agent:ft};let r=Ot(e.agent,t,n);return r?{kind:`resolved`,agent:r}:{kind:`unknown`,name:e.agent}}function Ut(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,reportChannel:`none`,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+Rt({cwd:n,agentScope:t})}}function Wt(e,t){if(z(t)===`strict`)return wt(e)?[...lt,Ie]:lt;let n=e.tools??[];if(!wt(e))return n.length>0?n:void 0;if(n.length!==0)return n.includes(`ptc_child_report`)?n:[...n,Ie]}function Gt(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`;r.push(`--thinking`,a);let o=Wt(t,e.readOnly);return o!==void 0&&r.push(`--tools`,o.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let Kt=qt;async function qt(e,t){let n=await C.promises.mkdtemp(k.join(E.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=k.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function Jt(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Yt(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 Xt(e,t){if(t.type!==`message_end`)return e;let n=t.message;if(n?.role!==`assistant`||n.usage===void 0)return e;let r=e??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};return r.input+=n.usage.input??0,r.output+=n.usage.output??0,r.cacheRead+=n.usage.cacheRead??0,r.cacheWrite+=n.usage.cacheWrite??0,r.cost+=n.usage.cost?.total??0,r.turns+=1,r}function Zt(e){let t=[],n;for(let r of e.split(`
14
+ `)}function Vt(e){let{userDir:t,projectDir:n}=Mt(e),r=zt(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t} (user scope) or ${n} (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body. the \`name:\` header IS the agent's name: naming the file after it is the convention, but the two are independent, so a definition is dispatchable under the name it declares even when the file is named otherwise`}function Ht(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:`agent, when given, must be a non-empty string — omit it entirely to dispatch a generalist child; `+Vt(e)}}function Ut(e){return e!==void 0&&(typeof e!=`string`||e.trim().length===0)}function Wt(e){return e===void 0}function Gt(e,t,n){if(Wt(e.agent))return{kind:`resolved`,agent:mt};let r=jt(e.agent,t,n);return r?{kind:`resolved`,agent:r}:{kind:`unknown`,name:e.agent}}function Kt(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,reportChannel:`none`,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+Vt({cwd:n,agentScope:t})}}function qt(e,t){if(B(t)===`strict`)return Dt(e)?[...ct,Fe]:ct;let n=e.tools??[];if(!Dt(e))return n.length>0?n:void 0;if(n.length!==0)return n.includes(`ptc_child_report`)?n:[...n,Fe]}function Jt(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`;r.push(`--thinking`,a);let o=qt(t,e.readOnly);return o!==void 0&&r.push(`--tools`,o.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let Yt=Xt;async function Xt(e,t){let n=await C.promises.mkdtemp(j.join(O.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=j.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function Zt(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Qt(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 $t(e,t){if(t.type!==`message_end`)return e;let n=t.message;if(n?.role!==`assistant`||n.usage===void 0)return e;let r=e??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};return r.input+=n.usage.input??0,r.output+=n.usage.output??0,r.cacheRead+=n.usage.cacheRead??0,r.cacheWrite+=n.usage.cacheWrite??0,r.cost+=n.usage.cost?.total??0,r.turns+=1,r}function en(e){let t=[],n;for(let r of e.split(`
12
15
  `)){let e=r.trim();if(n===void 0){let t=/^(`{3,}|~{3,})(.*)$/.exec(e);t&&(n={marker:(t[1]??``)[0],info:(t[2]??``).trim(),body:[]});continue}RegExp(`^`+n.marker+`{3,}\\s*$`).test(e)?(t.push({info:n.info,body:n.body.join(`
13
16
  `)}),n=void 0):n.body.push(r)}return n!==void 0&&t.push({info:n.info,body:n.body.join(`
14
- `)}),t}function Qt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $t(e){if(!Qt(e))return;let{summary:t,findings:n,files_touched:r}=e;if(typeof t!=`string`||!Array.isArray(n))return;let i=[];for(let e of n){if(!Qt(e)||typeof e.what!=`string`||typeof e.evidence!=`string`)return;i.push({what:e.what,evidence:e.evidence})}if(!Array.isArray(r))return;let a=[];for(let e of r){if(typeof e!=`string`)return;a.push(e)}return{summary:t,findings:i,files_touched:a}}function en(e){let t=Zt(e),n=t[t.length-1];if(n===void 0)return{reportChannel:`none`};let r;try{r=JSON.parse(n.body)}catch{return{reportChannel:`none`}}let i=$t(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function tn(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return $t(e.result?.structuredContent)}function nn(){return{prompt:{reportChannel:`none`},tool:void 0}}function rn(e,t){let n=tn(t);n!==void 0&&(e.tool=n)}function an(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function on(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 sn(e,t,n,r){let i=t.depth+1;if(i>t.maxDispatchDepth)return B(_t(),r);if(Bt(e.agent))return B(zt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`}),r);let a=De(),o=n.slots??at;if(!o.tryAcquire(a))return B(vt(),r);let s=n.clock??(()=>Date.now()),c=n.logger??ct,l=e.cwd??t.cwd,u=e.agentScope??`user`,d=n.lifecycle??rt,f=t.callerId??`dispatch:`+String(t.callId),p=st(n,s),m=n.outputStorage,h=Ht(e,l,u);if(h.kind===`unknown`)return o.release(a),B(Ut(h.name,u,l),r);let g=h.agent,_,v;try{let n=e.label??e.task.slice(0,64),u=wt(g),h=pt(g.systemPrompt,i,t.maxDispatchDepth,{reportContract:u,readOnly:e.readOnly}),y=await Kt(g.name,h);v=y;let b=Gt(e,g,y.filePath),x={cwd:l,env:{...process.env,PI_PTC_DEPTH:String(i),PI_PTC_TASK_ID:a},promptFile:y.filePath};t.sessionDir!==void 0&&(x.sessionDir=t.sessionDir,x.sessionId=a,x.sessionName=`bgdispatch:`+a),_=d.spawn([`pi`,...b],x);let S=_,C={kind:`ptc-program`,callerId:f};await p.transition({kind:`spawn`,handle:{taskId:a,label:n,status:`running`},record:{label:n,agentName:g.name,depth:i,startedAt:Math.max(0,Math.floor(s())),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:C,parentTaskId:t.parentTaskId,...r===void 0?{}:{readOnlyTier:r}}},{clock:s,callerId:f,logger:c});let w=!1,T,ee=p.onTransition((e,t)=>{e.id===a&&t.status===`stopping`&&(w||T!==void 0||(T=gt(d,S,{isDone:()=>w,unref:!0})))});return(async()=>{let e=``,t,n=nn(),r;try{for await(let i of d.events(S)){rn(n,i);let a=Yt(i);a!==void 0&&(e=a,n.prompt=en(a)),r=Xt(r,i);let o=on(i);o!==void 0&&(t=o)}w=!0,T?.();let i=(await d.exit(S)).code??-1,o=await d.stderr(S),l=i===0?void 0:yt(o),h=Buffer.byteLength(e,`utf8`),g=h<=2048?e:void 0,_;if(m!==void 0)try{await m.writeOutput(a,e),_=m.outputRef(a)}catch(e){let t=e instanceof Error?e.message:String(e);c.warn(`background dispatch output persistence for task `+a+` failed: `+t)}let v=u?an(n):{reportChannel:`opted-out`};await p.transition({kind:`resolve-exit`,taskId:a,exitCode:i,reportChannel:v.reportChannel,usage:r,...v.report===void 0?{}:{report:{...v.report,usage:{input:r?.input??0,output:r?.output??0,cost:r?.cost??0,turns:r?.turns??0}}},outputRef:_,outputBytes:h,outputPreview:g,childError:t,...l===void 0?{}:{stderrDiagnostic:l}},{clock:s,callerId:f,logger:c})}catch(t){let n=t instanceof Error?t.message:String(t);c.warn(`background dispatch pump for task `+a+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{ee(),T?.(),Jt(y),o.release(a)}})(),{taskId:a,label:n,status:`running`}}catch(e){let t=e instanceof Error?e.message:String(e);return _!==void 0&&gt(d,_,{unref:!0}),v!==void 0&&Jt(v),o.release(a),c.warn(`background dispatch failed for agent `+g.name+`: `+t),B({text:``,status:`rejected`,started:_!==void 0,agentName:g.name,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`background dispatch failed: `+t},r)}}async function cn(e,t,n={}){if(!ut(e.readOnly))return dt(e.readOnly);let r=z(e.readOnly);if(e.background===!0)return await sn(e,t,n,r);let i=t.depth+1;if(i>t.maxDispatchDepth)return B(mt(),r);let a=e.cwd??t.cwd,o=e.agentScope??`user`,s=Date.now();if(Bt(e.agent))return B(zt({cwd:a,agentScope:o}),r);let c=n.slots??at;if(!c.tryAcquire())return B(ht(),r);let l=Ht(e,a,o);if(l.kind===`unknown`)return c.release(),B(Ut(l.name,o,a,Date.now()-s),r);let u=l.agent,d=wt(u),f=pt(u.systemPrompt,i,t.maxDispatchDepth,{reportContract:d,readOnly:e.readOnly}),p,m=n.lifecycle??rt,h;try{p=await Kt(u.name,f),h=Gt(e,u,p.filePath)}catch(e){throw c.release(),e}return await new Promise(e=>{let o=``,l,f=nn(),g=-1,_=``,v=!1,y,b,x=!1,S=(i,a,h=!0)=>{if(v)return;v=!0,c.release(),b!==void 0&&m.exit(b).catch(e=>{(n.logger??ct).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),y?.(),t.signal&&t.signal.removeEventListener(`abort`,C),Jt(p);let x=d?an(f):{reportChannel:`opted-out`},S=B({text:o,status:i,started:h,agentName:u.name,durationMs:Date.now()-s,exitCode:g,reportChannel:x.reportChannel},r);x.report&&(S.report={...x.report,usage:{input:l?.input??0,output:l?.output??0,cost:l?.cost??0,turns:l?.turns??0}}),l&&(S.usage=l),_.length>0&&(S.stderr=_),a&&(S.errorMessage=a),e(S)},C=()=>{b&&!v&&(x=!0,y=gt(m,b,{isDone:()=>v}))};try{b=m.spawn([`pi`,...h],{cwd:a,env:{...process.env,PI_PTC_DEPTH:String(i)},promptFile:p.filePath})}catch(e){S(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?C():t.signal.addEventListener(`abort`,C,{once:!0})),(async()=>{if(!b)return;let e=b;try{for await(let t of m.events(e))if(rn(f,t),t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(l=Xt(l,t),Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(o=t.text,f.prompt=en(t.text))}let t=await rt.exit(e);g=t.code??-1,_=await rt.stderr(e);let n=_.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){S(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:r,errorMessage:i}=bt({exitCode:g,finalText:o,aborted:x,stderr:_});S(r,i)}catch(e){let t=e instanceof Error?e.message:String(e);S(`rejected`,`dispatch internal error: `+t)}})()})}const V=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],H=`pi.dispatch`,ln=[`bash`];function un(e){return ln.includes(e)}function dn(e){if(e===void 0)return[];let t=new Set(e);for(let e of t)if(!un(e))throw TypeError(`unknown PTC opt-in binding "${e}"; opt-in bindings: ${ln.join(`, `)}`);return V.filter(e=>t.has(e))}const fn=V.filter(e=>!un(e)),pn={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},mn=x.Object({agent:x.Optional(x.String({minLength:1,description:`Optional. Name a registered agent definition to narrow the child, or omit it entirely for a fresh generalist pi with pi's own prompt and its full toolset. A name with no definition behind it is refused; an empty string is refused.`})),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)],{description:`Which agent directories to search: "user" (~/.pi/agent/agents, the default), "project" (<cwd>/.pi/agents), or "both". Defaults to "user", which cannot see project agents.`})),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String()),readOnly:x.Optional(x.Union([x.Literal(`strict`),x.Literal(`lenient`)],{description:`Ask for a read-only child. "strict": its tools are narrowed to the read set, so it cannot write anything. "lenient": its tools are left exactly as they would have been and it is only told to work without modifying anything. Omit for today’s behaviour.`}))}),hn={name:H,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:mn};function gn(e){return z(e?.readOnly)}function _n(e,t){let n=t.trim();return n.length===0?`${e} reported a failure with no message`:`${e} failed: ${n.length<=2e3?n:`…${n.slice(-2e3)}`}`}function vn(e){let t=new Set(dn(e.optIns)),n=e.names??V.filter(e=>fn.includes(e)||t.has(e)),r=e.includeDispatch??e.names===void 0,i=/* @__PURE__ */ new Map;for(let t of n){let n=pn[t];if(!n)throw TypeError(`unknown PTC binding "${t}"; known bindings: ${V.join(`, `)}`);let r=n(e.cwd);i.set(t,{name:t,execute:async(e,t)=>{let n=`ptc:${t.callId}`,i={type:`toolCall`,id:n,name:r.name,arguments:e},a=S(r,i),o;try{o=await r.execute(n,a,t.signal,void 0)}catch(e){throw Error(_n(r.name,e instanceof Error?e.message:String(e)))}if(o.isError===!0)throw Error(_n(r.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
15
- `)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return r&&i.set(H,{name:H,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:H,arguments:t},i;try{i=S(hn,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return Bt(i)?B(zt({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}),gn(r)):B({text:``,status:`rejected`,started:!1,agentName:typeof i==`string`?i:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:n instanceof Error?n.message:String(n)},gn(r))}return cn(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)}}),i}function yn(){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 bn(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 xn={acquireLatency:de.channel(`ptc:pool:acquire-latency`),resetTime:de.channel(`ptc:worker:reset-time`),imageBytes:de.channel(`ptc:image:hoist-bytes`)};function Sn(e,t){e.publish(t)}var Cn=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(),Sn(xn.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),Sn(xn.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),Sn(xn.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 ue(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 wn(e){Sn(xn.imageBytes,{byteLength:e})}function Tn(e){Sn(xn.resetTime,{durationMs:e})}function En(){let e=A(P(import.meta.url)),t=[M(e,`worker.js`),M(e,`worker-entry.ts`)];for(let e of t)if(w(e))return fe(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function Dn(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 U(e){return e instanceof Error?e.message:String(e)}function On(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(`
16
- `);return e===-1?t:t.slice(0,e)}}}}function kn(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function An(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 jn(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>kn(t)?null:t)??``,`utf8`),n=0;return An(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function Mn(e){let i=ze(e.config),s=Re(),c=e.runId??ce(),l=Be(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 ue(En(),bn({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: ${U(e)}`}}}return await new Promise(s=>{let m=new le,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=yn(),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 it(i.dispatchConcurrency),te=0,ne=[],E=e.depth??0,D,O,k=[],re=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`,j=e=>e===`timeout`?n.timeout:n.abort,ie=t=>{if(v)return;v=!0,D&&clearTimeout(D),O&&clearTimeout(O),e.signal?.removeEventListener(`abort`,I),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},M=(e,t,n)=>{ie({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},ae=e=>{if(!v){if(!r(e)){M(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},oe=()=>{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)){M(n.protocol,`internal error: malformed init frame`);return}let a=jn(t);if(a>i.maxMessageBytes){M(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}ae(t)},se=(e,t)=>(T+=e,T<=i.maxOutputBytes||(M(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(te<i.maxParallelSubCalls){te+=1;return}await new Promise(e=>{ne.push(e)})},N=()=>{let e=ne.shift();if(e){e();return}--te},ue=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`}),M(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}de(e).finally(()=>{--w})},de=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)`)}),P({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;if(!a&&(await ce(),v)){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),N();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:E,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=re(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=jn(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),M(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(P(u))for(let e of l)k.push(e),wn(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?Dn(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:On(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:U(e)}):x.recordEnd(t.callId,`error`,{errorMessage:U(e)}),P({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:U(e)})}finally{a||N()}},P=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: ${U(t)}`})}catch{M(n.protocol,`binding result is not transferable`)}return!1}},fe=e=>S?{logs:u,narrations:d,phases:f,error:{kind:j(S),message:A(S)}}:e,F=r=>{if(v)return;if(!a(r)){M(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:jn(r);if(!Number.isFinite(o)){M(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){M(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&&Tn(Date.now()-t)}if(!C&&(C=!0,S)){pe(S);return}oe();return;case t.call:ue(r);return;case t.log:se(o,`console output`)&&u.push(r.text);return;case t.narration:se(o,`workflow narration`)&&d.push(r.message);return;case t.phase:se(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!se(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...k.length>0?{images:k}:{}};ie(fe(r.value===void 0?e:{...e,value:r.value}));return}case t.error:ie(fe({logs:u,narrations:d,phases:f,error:r.error}));return;default:M(n.protocol,`unknown worker frame`)}};function I(){me(`abort`)}let pe=e=>{O&&clearTimeout(O),O=setTimeout(()=>{M(j(e),A(e))},i.graceMs)};function me(e){if(!v){if(S){M(j(S),A(S));return}S=e,_.abort(),ae({kind:o.cancel,reason:e}),pe(e)}}p.on(`error`,e=>{M(n.workerExit,`worker failed: ${U(e)}`)}),p.on(`exit`,e=>{M(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,F),h.on(`messageerror`,()=>{M(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,I,{once:!0}),D=setTimeout(()=>{me(`timeout`)},l);let he={kind:o.connect,port:g};r(he)?p.postMessage(he,[g]):M(n.protocol,`internal error: malformed connect frame`)})}const Nn=["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.`],Pn=/* @__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`."],[H,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),Fn=[Nn.join(`
17
- `),`Exceptions: `+[...Pn.values()].join(` `)].join(`
18
- `),In=`pi-ptc-output-`;function Ln(e,t=In){let n=j(O(),`${t}${ce()}.txt`);return ne(n,e,`utf8`),n}function Rn(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 zn(e,t=In,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Ln(n.fullText??e,t);return{text:`${r.content}\n\n${Rn(r,i)}`,truncated:!0,fullPath:i}}const Bn=200,Vn=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 Hn(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(Vn,``)}function W(e){let t=Hn(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 Un=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Wn(e){return Un.test(e)?e:JSON.stringify(e)}function Gn(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=W(e);return t.includes(`
19
- `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=Gn(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=Gn(e[r]??null);if(t===void 0)return;n.push(`${Wn(r)}: ${t}`)}return`{${n.join(`, `)}}`}function Kn(e){let t=Gn(e);if(t!==void 0)return t.length<=100?t:void 0}function qn(e){return e===null?`null`:typeof e==`string`?W(e):String(e)}function Jn(e,t){if(typeof e!=`object`||!e)return[`${t}${qn(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=Kn(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...Yn(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=Kn(n);if(a!==void 0){r.push(`${i}${Wn(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${Wn(t)}:`);for(let e of W(n).split(`
20
- `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=Jn(n,i);r.push(`${i}${Wn(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function Yn(e,t){return typeof e==`string`?W(e).split(`
21
- `):typeof e!=`object`||!e?[String(e)]:Jn(e,t)}function Xn(e){return e.split(`
17
+ `)}),t}function tn(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function nn(e){if(!tn(e))return;let{summary:t,findings:n,files_touched:r}=e;if(typeof t!=`string`||!Array.isArray(n))return;let i=[];for(let e of n){if(!tn(e)||typeof e.what!=`string`||typeof e.evidence!=`string`)return;i.push({what:e.what,evidence:e.evidence})}if(!Array.isArray(r))return;let a=[];for(let e of r){if(typeof e!=`string`)return;a.push(e)}return{summary:t,findings:i,files_touched:a}}function rn(e){let t=en(e),n=t[t.length-1];if(n===void 0)return{reportChannel:`none`};let r;try{r=JSON.parse(n.body)}catch{return{reportChannel:`none`}}let i=nn(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function an(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return nn(e.result?.structuredContent)}function on(){return{prompt:{reportChannel:`none`},tool:void 0}}function sn(e,t){let n=an(t);n!==void 0&&(e.tool=n)}function cn(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function ln(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 un(e,t,n,r){let i=ft(e.why,n.whyEnabled!==!1),a=e=>pt(dt(e,r),i.suppressed),o=t.depth+1;if(o>t.maxDispatchDepth)return a(bt());if(Ut(e.agent))return a(Ht({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`}));let s=Ee(),c=n.slots??it;if(!c.tryAcquire(s))return a(xt());let l=n.clock??(()=>Date.now()),u=n.logger??st,d=e.cwd??t.cwd,f=e.agentScope??`user`,p=n.lifecycle??nt,m=t.callerId??`dispatch:`+String(t.callId),h=ot(n,l),g=n.outputStorage,_=Gt(e,d,f);if(_.kind===`unknown`)return c.release(s),a(Kt(_.name,f,d));let v=_.agent,y,b;try{let n=e.label??e.task.slice(0,64),a=Dt(v),f=ht(v.systemPrompt,o,t.maxDispatchDepth,{reportContract:a,readOnly:e.readOnly,why:i.why}),_=await Yt(v.name,f);b=_;let x=Jt(e,v,_.filePath),S={cwd:d,env:{...process.env,PI_PTC_DEPTH:String(o),PI_PTC_TASK_ID:s},promptFile:_.filePath};t.sessionDir!==void 0&&(S.sessionDir=t.sessionDir,S.sessionId=s,S.sessionName=`bgdispatch:`+s),y=p.spawn([`pi`,...x],S);let C=y,w={kind:`ptc-program`,callerId:m};await h.transition({kind:`spawn`,handle:{taskId:s,label:n,status:`running`},record:{label:n,agentName:v.name,depth:o,startedAt:Math.max(0,Math.floor(l())),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:w,parentTaskId:t.parentTaskId,...r===void 0?{}:{readOnlyTier:r},...i.suppressed?{whySuppressed:!0}:{}}},{clock:l,callerId:m,logger:u});let T=!1,E,D=h.onTransition((e,t)=>{e.id===s&&t.status===`stopping`&&(T||E!==void 0||(E=yt(p,C,{isDone:()=>T,unref:!0})))});return(async()=>{let e=``,t,n=on(),r;try{for await(let i of p.events(C)){sn(n,i);let a=Qt(i);a!==void 0&&(e=a,n.prompt=rn(a)),r=$t(r,i);let o=ln(i);o!==void 0&&(t=o)}T=!0,E?.();let i=(await p.exit(C)).code??-1,o=await p.stderr(C),c=i===0?void 0:St(o),d=Buffer.byteLength(e,`utf8`),f=d<=2048?e:void 0,_;if(g!==void 0)try{await g.writeOutput(s,e),_=g.outputRef(s)}catch(e){let t=e instanceof Error?e.message:String(e);u.warn(`background dispatch output persistence for task `+s+` failed: `+t)}let v=a?cn(n):{reportChannel:`opted-out`},y=await h.transition({kind:`resolve-exit`,taskId:s,exitCode:i,reportChannel:v.reportChannel,usage:r,...v.report===void 0?{}:{report:{...v.report,usage:{input:r?.input??0,output:r?.output??0,cost:r?.cost??0,turns:r?.turns??0}}},outputRef:_,outputBytes:d,outputPreview:f,childError:t,...c===void 0?{}:{stderrDiagnostic:c}},{clock:l,callerId:m,logger:u});y.record.status===`failed`&&y.record.errorMessage!==void 0&&u.warn(`background dispatch task `+s+` failed: `+y.record.errorMessage)}catch(t){let n=t instanceof Error?t.message:String(t);u.warn(`background dispatch pump for task `+s+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{D(),E?.(),Zt(_),c.release(s)}})(),{taskId:s,label:n,status:`running`}}catch(e){let t=e instanceof Error?e.message:String(e);return y!==void 0&&yt(p,y,{unref:!0}),b!==void 0&&Zt(b),c.release(s),u.warn(`background dispatch failed for agent `+v.name+`: `+t),a({text:``,status:`rejected`,started:y!==void 0,agentName:v.name,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`background dispatch failed: `+t})}}async function dn(e,t,n={}){let r=ft(e.why,n.whyEnabled!==!1),i=B(e.readOnly),a=e=>pt(dt(e,i),r.suppressed);if(!lt(e.readOnly))return a(ut(e.readOnly));if(e.background===!0)return await un(e,t,n,i);let o=t.depth+1;if(o>t.maxDispatchDepth)return a(_t());let s=e.cwd??t.cwd,c=e.agentScope??`user`,l=Date.now();if(Ut(e.agent))return a(Ht({cwd:s,agentScope:c}));let u=n.slots??it;if(!u.tryAcquire())return a(vt());let d=Gt(e,s,c);if(d.kind===`unknown`)return u.release(),a(Kt(d.name,c,s,Date.now()-l));let f=d.agent,p=Dt(f),m=ht(f.systemPrompt,o,t.maxDispatchDepth,{reportContract:p,readOnly:e.readOnly,why:r.why}),h,g=n.lifecycle??nt,_;try{h=await Yt(f.name,m),_=Jt(e,f,h.filePath)}catch(e){throw u.release(),e}return await new Promise(e=>{let r=``,i,c=on(),d=-1,m=``,v=!1,y,b,x=!1,S=(o,s,_=!0)=>{if(v)return;v=!0,u.release(),b!==void 0&&g.exit(b).catch(e=>{(n.logger??st).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),y?.(),t.signal&&t.signal.removeEventListener(`abort`,C),Zt(h);let x=p?cn(c):{reportChannel:`opted-out`},S=a({text:r,status:o,started:_,agentName:f.name,durationMs:Date.now()-l,exitCode:d,reportChannel:x.reportChannel});x.report&&(S.report={...x.report,usage:{input:i?.input??0,output:i?.output??0,cost:i?.cost??0,turns:i?.turns??0}}),i&&(S.usage=i),m.length>0&&(S.stderr=m),s&&(S.errorMessage=s),e(S)},C=()=>{b&&!v&&(x=!0,y=yt(g,b,{isDone:()=>v}))};try{b=g.spawn([`pi`,..._],{cwd:s,env:{...process.env,PI_PTC_DEPTH:String(o)},promptFile:h.filePath})}catch(e){S(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?C():t.signal.addEventListener(`abort`,C,{once:!0})),(async()=>{if(!b)return;let e=b;try{for await(let t of g.events(e))if(sn(c,t),t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(i=$t(i,t),Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(r=t.text,c.prompt=rn(t.text))}let t=await nt.exit(e);d=t.code??-1,m=await nt.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){S(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:a,errorMessage:o}=Ct({exitCode:d,finalText:r,aborted:x,stderr:m});S(a,o)}catch(e){let t=e instanceof Error?e.message:String(e);S(`rejected`,`dispatch internal error: `+t)}})()})}const V=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],H=`pi.dispatch`,fn=[`bash`];function pn(e){return fn.includes(e)}function mn(e){if(e===void 0)return[];let t=new Set(e);for(let e of t)if(!pn(e))throw TypeError(`unknown PTC opt-in binding "${e}"; opt-in bindings: ${fn.join(`, `)}`);return V.filter(e=>t.has(e))}const hn=V.filter(e=>!pn(e)),gn={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},_n=x.Object({agent:x.Optional(x.String({minLength:1,description:`Optional. Name a registered agent definition to narrow the child, or omit it entirely for a fresh generalist pi with pi's own prompt and its full toolset. A name with no definition behind it is refused; an empty string is refused.`})),task:x.String({minLength:1}),why:x.Optional(x.String({description:`Why this dispatch slice exists, in your own words: the intent behind cutting this task out, not the whole conversation and not the user's original request. Pass it when the task involves judgment or trade-offs, so the child can resolve ambiguities the task text leaves open instead of inventing context. Omit it for a fully specified task.`})),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)],{description:`Which agent directories to search: "user" (~/.pi/agent/agents, the default), "project" (<cwd>/.pi/agents), or "both". Defaults to "user", which cannot see project agents.`})),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String()),readOnly:x.Optional(x.Union([x.Literal(`strict`),x.Literal(`lenient`)],{description:`Ask for a read-only child. "strict": its tools are narrowed to the read set, so it cannot write anything. "lenient": its tools are left exactly as they would have been and it is only told to work without modifying anything. Omit for today’s behaviour.`}))}),vn={name:H,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:_n};function yn(e){return B(e?.readOnly)}function bn(e,t){return ft(e?.why,t).suppressed}function xn(e,t){let n=t.trim();return n.length===0?`${e} reported a failure with no message`:`${e} failed: ${n.length<=2e3?n:`…${n.slice(-2e3)}`}`}function Sn(e){let t=new Set(mn(e.optIns)),n=e.names??V.filter(e=>hn.includes(e)||t.has(e)),r=e.includeDispatch??e.names===void 0,i=/* @__PURE__ */ new Map;for(let t of n){let n=gn[t];if(!n)throw TypeError(`unknown PTC binding "${t}"; known bindings: ${V.join(`, `)}`);let r=n(e.cwd);i.set(t,{name:t,execute:async(e,t)=>{let n=`ptc:${t.callId}`,i={type:`toolCall`,id:n,name:r.name,arguments:e},a=S(r,i),o;try{o=await r.execute(n,a,t.signal,void 0)}catch(e){throw Error(xn(r.name,e instanceof Error?e.message:String(e)))}if(o.isError===!0)throw Error(xn(r.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
18
+ `)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return r&&i.set(H,{name:H,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:H,arguments:t},i;try{i=S(vn,r)}catch(r){let i=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,a=i?.agent,o=i?.agentScope,s=bn(i,n.dispatchDeps?.whyEnabled!==!1);return Ut(a)?pt(dt(Ht({cwd:e.cwd,agentScope:o===`user`||o===`project`||o===`both`?o:`user`}),yn(i)),s):pt(dt({text:``,status:`rejected`,started:!1,agentName:typeof a==`string`?a:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:r instanceof Error?r.message:String(r)},yn(i)),s)}return dn(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)}}),i}function Cn(){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 wn(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:le.channel(`ptc:pool:acquire-latency`),resetTime:le.channel(`ptc:worker:reset-time`),imageBytes:le.channel(`ptc:image:hoist-bytes`)};function Tn(e,t){e.publish(t)}var En=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(),Tn(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),Tn(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),Tn(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 ce(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 Dn(e){Tn(U.imageBytes,{byteLength:e})}function On(e){Tn(U.resetTime,{durationMs:e})}function kn(){let e=M(ue(import.meta.url)),t=[P(e,`worker.js`),P(e,`worker-entry.ts`)];for(let e of t)if(w(e))return de(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function An(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 jn(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(`
19
+ `);return e===-1?t:t.slice(0,e)}}}}function Mn(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Nn(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 Pn(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>Mn(t)?null:t)??``,`utf8`),n=0;return Nn(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function Fn(e){let i=Re(e.config),s=Le(),c=e.runId??oe(),l=ze(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 ce(kn(),wn({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 se,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=Cn(),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,E=new rt(i.dispatchConcurrency),D=0,ee=[],O=e.depth??0,k,A,j=[],te=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},M=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,N=e=>e===`timeout`?n.timeout:n.abort,ne=t=>{if(v)return;v=!0,k&&clearTimeout(k),A&&clearTimeout(A),e.signal?.removeEventListener(`abort`,L),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},P=(e,t,n)=>{ne({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},re=e=>{if(!v){if(!r(e)){P(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},ie=()=>{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)){P(n.protocol,`internal error: malformed init frame`);return}let a=Pn(t);if(a>i.maxMessageBytes){P(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}re(t)},ae=(e,t)=>(T+=e,T<=i.maxOutputBytes||(P(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),oe=async()=>{if(D<i.maxParallelSubCalls){D+=1;return}await new Promise(e=>{ee.push(e)})},F=()=>{let e=ee.shift();if(e){e();return}--D},ce=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`}),P(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}le(e).finally(()=>{--w})},le=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===H;if(!a&&(await oe(),v)){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),F();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:O,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??E}}),l=te(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Pn(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),P(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(ue(u))for(let e of l)j.push(e),Dn(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?An(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:jn(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||F()}},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{P(n.protocol,`binding result is not transferable`)}return!1}},de=e=>S?{logs:u,narrations:d,phases:f,error:{kind:N(S),message:M(S)}}:e,I=r=>{if(v)return;if(!a(r)){P(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Pn(r);if(!Number.isFinite(o)){P(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){P(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&&On(Date.now()-t)}if(!C&&(C=!0,S)){fe(S);return}ie();return;case t.call:ce(r);return;case t.log:ae(o,`console output`)&&u.push(r.text);return;case t.narration:ae(o,`workflow narration`)&&d.push(r.message);return;case t.phase:ae(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!ae(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...j.length>0?{images:j}:{}};ne(de(r.value===void 0?e:{...e,value:r.value}));return}case t.error:ne(de({logs:u,narrations:d,phases:f,error:r.error}));return;default:P(n.protocol,`unknown worker frame`)}};function L(){pe(`abort`)}let fe=e=>{A&&clearTimeout(A),A=setTimeout(()=>{P(N(e),M(e))},i.graceMs)};function pe(e){if(!v){if(S){P(N(S),M(S));return}S=e,_.abort(),re({kind:o.cancel,reason:e}),fe(e)}}p.on(`error`,e=>{P(n.workerExit,`worker failed: ${W(e)}`)}),p.on(`exit`,e=>{P(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,I),h.on(`messageerror`,()=>{P(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,L,{once:!0}),k=setTimeout(()=>{pe(`timeout`)},l);let me={kind:o.connect,port:g};r(me)?p.postMessage(me,[g]):P(n.protocol,`internal error: malformed connect frame`)})}const In=["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.`],Ln=/* @__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`."],[H,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),Rn=[In.join(`
20
+ `),`Exceptions: `+[...Ln.values()].join(` `)].join(`
21
+ `),zn=`pi-ptc-output-`;function Bn(e,t=zn){let n=N(A(),`${t}${oe()}.txt`);return ee(n,e,`utf8`),n}function Vn(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 Hn(e,t=zn,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Bn(n.fullText??e,t);return{text:`${r.content}\n\n${Vn(r,i)}`,truncated:!0,fullPath:i}}const Un=200,Wn=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 Gn(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(Wn,``)}function G(e){let t=Gn(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 Kn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function qn(e){return Kn.test(e)?e:JSON.stringify(e)}function Jn(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(`
22
+ `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=Jn(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=Jn(e[r]??null);if(t===void 0)return;n.push(`${qn(r)}: ${t}`)}return`{${n.join(`, `)}}`}function Yn(e){let t=Jn(e);if(t!==void 0)return t.length<=100?t:void 0}function Xn(e){return e===null?`null`:typeof e==`string`?G(e):String(e)}function Zn(e,t){if(typeof e!=`object`||!e)return[`${t}${Xn(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=Yn(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...Qn(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=Yn(n);if(a!==void 0){r.push(`${i}${qn(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${qn(t)}:`);for(let e of G(n).split(`
23
+ `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=Zn(n,i);r.push(`${i}${qn(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function Qn(e,t){return typeof e==`string`?G(e).split(`
24
+ `):typeof e!=`object`||!e?[String(e)]:Zn(e,t)}function $n(e){return e.split(`
22
25
  `).map(e=>e.length>200?`${e.slice(0,199)}…`:e).join(`
23
- `)}function Zn(e){if(typeof e==`string`)return Xn(W(e));if(typeof e!=`object`||!e)return String(e);let t=Kn(e);return Xn((t===void 0?Yn(e,``):[t]).join(`
24
- `))}function Qn(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function $n(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 er(e,t){let n=e===void 0?void 0:new Set(e),r=new Set(dn(t));return V.filter(e=>(n===void 0||n.has(e))&&(fn.includes(e)||r.has(e)))}const tr=["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.`],nr="A `codemode` script cannot call the parallel binding directly: `pi.dispatch` is never in that script's own tool table, on any surface. A script reaches it by calling `ptc_run_code` or `ptc_workflow` and using the binding inside the program.",rr={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function ir(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function ar(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 or(e){return[...e.phases.map(e=>`[phase] ${W(e)}`),...e.narrations.map(e=>`[log] ${W(e)}`),...e.logs.map(e=>W(e))]}function sr(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=or(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
25
- `)}`,i=Error(W(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function cr(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=>W(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>W(e)).join(`
26
- `)),t.logs.length>0&&a.push(t.logs.map(e=>W(e)).join(`
27
- `)),t.value!==void 0&&a.push(Zn(t.value));for(let e of r)a.push(`Warning: ${W(e)}`);let o=zn(a.length>0?a.join(`
28
- `):`(${rr[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 lr=`└─ `;function ur(e){return e===void 0?``:`read-only tier (${e})\n${lr}${e===`strict`?`the child's tool list was narrowed to the read set, so it was never offered a write tool`:`the child's tool list is UNCHANGED — it was told to work without modifying anything, and nothing here prevents it from doing so`}`}const dr=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function fr(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function pr(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 mr(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=pr(e,n):(n+=1,r+=1);return n}function hr(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:gr(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 gr(e,t,n){return e.map(e=>{let r=fr(e),i=dr.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=mr(e,s),l=mr(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 _r={run_code:`PTC`,workflow:`PTC workflow`},vr=`├─ `,yr=`│ `;var br=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>xr(e,t))}};function xr(e,t){let{left:n,right:r}=e;if(r===void 0)return F(n,t,`…`);let i=I(r);if(i>=t)return F(r,t,`…`);let a=F(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-I(a));return a+` `.repeat(o)+r}function G(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Sr(e){return G((W(e).split(`
29
- `).find(e=>e.trim().length>0)??``).trim(),120)}function Cr(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function wr(e,t){return`${e} ${t}${e===1?``:`s`}`}function Tr(e){for(let t of e.split(`
30
- `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return G(e.replace(/\s*\/\/.*$/,``),120)}}function Er(e){if(e===void 0)return;if(typeof e==`string`){let t=W(e).split(`
31
- `),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:G(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=Zn(e);if(!t.includes(`
32
- `)&&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 Dr(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,wr(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,wr(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,wr(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,wr(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Cr(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Or(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 kr(e,t,n){let r=` `+(t?lr:vr),i=` `+(t?` `:yr),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 Ar(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const jr=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Mr(e){return jr.test(e)?e:JSON.stringify(e)}function Nr(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=W(e);if(n.length===0)return`""`;if(n.includes(`
33
- `)){let e=G(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(G(n,Math.max(2,t-5)))+`…`}return`?`}function Pr(e){return typeof e!=`object`||!e}function Fr(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Pr))return;let n=`[`+e.map(e=>Nr(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(Pr))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Mr(n)+`: `+Nr(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Ir(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(K(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(K(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(K(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-I(l)-t.length);c.push(K(l+t+Nr(e,n),o));return}let d=Fr(e,Math.max(0,o-I(l)-t.length));if(d!==void 0){c.push(K(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(K(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;Ir(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];Ir(e[l]??null,Mr(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(K(u+`└─ …+`+(p-h)+` more `+e,o))}}function K(e,t){if(I(e)<=t)return e;let n=e.match(/^([\s│├└─]*)/),r=n&&n[1]?n[1]:``,i=I(r),a=Math.max(0,t-i-1),o=``,s=0;for(let t of e.slice(r.length)){let e=I(t);if(s+e>a)break;o+=t,s+=e}return r+o+`…`}function Lr(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Ar(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Nr(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;Ir(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];Ir(e[d]??null,Mr(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}const Rr=`child report`;function zr(e){return e===0?`[]`:`Array(${e})`}function Br(e){let t=W(e).split(`
34
- `).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:G(t,200)}function Vr(e){let t=Number(e.cost.toFixed(4));return`in ${e.input} · out ${e.output} · cost ${t} · ${wr(e.turns,`turn`)}`}function Hr(e,t,n){let r=W(n).replace(/\n/g,` `).trim();return r.length<=150?`${e}${t}evidence: ${r}`:`${e}${t}evidence: ${r.slice(0,150)}… (truncated at 150 chars)`}function Ur(e,t){let n=[];return e.forEach((r,i)=>{let a=i===e.length-1&&t===0,o=`[${i}]`;n.push(`${a?`└─ `:`├─ `}${o} ${W(r.what).trim()}`.trimEnd()),n.push(Hr(a?` `:`│ `,` `.repeat(o.length+2),r.evidence))}),t>0&&n.push(`└─ …+${t} more findings withheld (a report renders at most 20)`),n}function Wr(e,t){let n=e.map((n,r)=>`${r===e.length-1&&t===0?`└─ `:`├─ `}[${r}] `+`${W(n).trim()}`.trimEnd());return t>0&&n.push(`└─ …+${t} more files withheld (a report renders at most 20)`),n}function Gr(e,t){let n=e.label.length>=8?`${e.label} `:e.label.padEnd(8);return K(`${t?lr:vr}${n}${e.head}`,200)}function Kr(e,t){let n=e===`none`?`no child report was returned — the child did not comply with the contract, so its prose below is unbacked by a report`:e===`opted-out`?`this agent opts out of the report contract, so none was asked for — the prose below is the whole of what it produced, and nothing is missing`:`the ${e} channel was announced but no report reached the host; the child's prose below is everything it produced`,r=`${Rr} (channel: ${e})`;return t===void 0?`${r}\n${lr}${n}`:`${r}\n${vr}${n}\n${Gr({label:`usage`,head:Vr(t),rows:[]},!0)}`}function qr(e,t,n){if(e===void 0)return Kr(t,n);let r=e.findings.slice(0,20),i=e.findings.length-r.length,a=e.files_touched.slice(0,20),o=e.files_touched.length-a.length,s=[{label:`summary`,head:Br(e.summary),rows:[]},{label:`findings`,head:zr(e.findings.length),rows:Ur(r,i)},{label:`files`,head:zr(e.files_touched.length),rows:Wr(a,o)},{label:`usage`,head:Vr(n??e.usage),rows:[]}],c=[`${Rr} (channel: ${t})`];return s.forEach((e,t)=>{let n=t===s.length-1;c.push(Gr(e,n));let r=n?` `:yr;for(let t of e.rows)c.push(K(`${r}${t}`,200))}),c.join(`
35
- `)}function Jr(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Tr(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return hr(new br([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(_r[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??Yr,state:r.state??{}})}function Yr(){}function Xr(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Sr(t?.text??``)||`failed`}function Zr(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t){let e=t.agent;return typeof e==`string`&&e.trim().length>0?`→ ${e}`:e===void 0?`→ (generalist)`:`→ ${JSON.stringify(e)}`}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 Qr={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Cr(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 $r(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=Zr(e.name,e.args),l=Qr[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 ei(e,t,n,r=!1,i=!1){let a=Dr(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${Xr(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(Ar(s))return Lr(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=Er(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function ti(e,t,n,r={}){let i=Or(e.details),a=[...ei({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...$r(i.subCalls,n)),new br(a)}function ni(e,t,n,r,i={}){let a=Or(e.details);if(n){let t=[...ei({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...$r(a.subCalls,r));let n=W(e.content?.find(e=>e.type===`text`)?.text??Xr(e));for(let e of n.split(`
36
- `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new br(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
37
- `).map(e=>G(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=>W(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=>W(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=>W(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=ei({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...$r(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...kr(o[e]??{label:``,lines:[]},t,r))}return new br(u)}function ri(e){return{renderCall(t,n,r){return Jr(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?ni(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):ti(e,r?.isError===!0,n,{isPartial:i})}}}const ii=["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" })`.',`The bound names are this session's active built-in tools, less any binding the install has not`,`explicitly opted in — this surface is narrower than the session's tool list on purpose;`,"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.`,``,nr,``,Fn,``,"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(`
38
- `),ai=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 ${R.timeoutMs/1e3} s; anything above ${R.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 oi(e={}){return L({name:`ptc_run_code`,label:`PTC Run Code`,exposure:e.exposure,description:ii,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:[...tr],parameters:ai,async execute(t,n,r,i,a){let o=ir(a),s=er(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=ar({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await Mn({code:n.code,surface:`run_code`,cwd:o,bindings:vn({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 sr(p);return cr({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...ri(`run_code`)})}const si=[`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",`are this session's enabled built-ins less any binding the install has not opted in. 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.",``,nr,``,Fn,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
39
- `),ci=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 li(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=ui(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function ui(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=ui(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=ui(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function di(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 fi(e={}){return L({name:`ptc_workflow`,label:`PTC Workflow`,exposure:e.exposure,description:si,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...tr],parameters:ci,async execute(t,n,r,i,a){li(n.args);let o=ir(a),s=er(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=ar({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await Mn({code:n.script,surface:`workflow`,cwd:o,bindings:vn({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 sr(p);let m=n.meta.phases?.map(e=>e.name);return cr({outcome:p,surface:`workflow`,warnings:di(p,m),durationMs:Date.now()-c})},...ri(`workflow`)})}var pi=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 mi(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var hi=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await he(this.#t(e),`utf8`)}catch(e){if(mi(e))return null;throw e}}async writeOutput(e,t){let n=j(this.#e,`tasks`,e);await me(n,{recursive:!0}),await ye(j(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return j(this.#e,`tasks`,e,`output.log`)}};function gi(e,t){return zn(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const _i={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},vi={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var q=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>yi(e,t))}};function yi(e,t){let{left:n,right:r}=e;if(r===void 0)return F(n,t,`…`);let i=I(r);if(i>=t)return F(r,t,`…`);let a=F(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-I(a));return a+` `.repeat(o)+r}function bi(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function xi(e){return bi((W(e).split(`
40
- `).find(e=>e.trim().length>0)??``).trim(),120)}function Si(e){return typeof e==`object`&&e?e:{}}function Ci(e){return e===`running`||e===`stopping`}function wi(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 Ti(e,t){if(Ci(e.status))return wi(t-e.createdAt);if(e.durationMs!==void 0)return wi(e.durationMs);if(e.finishedAt!==void 0)return wi(e.finishedAt-e.createdAt)}function Ei(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 Di(){}function Oi(e,t,n){return new q([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function ki(e,t,n){let r=Si(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 Oi(`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 Oi(`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=${W(r.reason)}`:``;return Oi(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Ai(e,t,n,r){let i=_i[e.status]??`muted`,a=n.fg(i,vi[e.status]??`?`),o=bi(W(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,W(e.agentName))],c=Ti(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 ji(e,t){let n=Si(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Ei(new q([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>Ci(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>Ai(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Ei(new q(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Mi(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 Ni(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Pi(e,t){let n=Si(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=Mi(i,a,t.theme),c=[];if(r.length>0){let e=W(r).split(`
41
- `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,bi(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:Ni(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:Ni(o,t.theme),...s===void 0?{}:{right:s}});return new q(c)}function Fi(e,t){let n=Si(e),r=n.task;if(typeof r!=`object`||!r)return new q([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=_i[r.status]??`muted`,a=t.theme.fg(i,vi[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`,W(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${W(r.stopReason)}`)),new q([{left:` ${c.join(` `)}`}])}function Ii(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=xi(n?.text??``)||`failed`;return new q([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Li(e,t,n){switch(e){case`task-list`:return ji(t.details,n);case`task-output`:return Pi(t.details,n);case`task-stop`:return Fi(t.details,n)}}function Ri(e){return{renderCall(t,n){return ki(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Ii(t,r):Li(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Di,state:i?.state??{},now:Date.now()})}}}const zi=[`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). A succeeded task's child report is rendered there, ahead of the prose.`,`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.`],Bi=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Vi=x.Object({status:x.Optional(x.Array(Bi,{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.`}))}),Hi=x.Object({tasks:x.Array(x.Object({id:x.String({description:`The task's ULID — the id ptc_task_output and ptc_task_stop take.`}),status:x.String({description:`One of running, stopping, succeeded, failed, canceled, lost (ADR-0022 §2).`}),agent:x.String({description:`The agent the task was dispatched with (the record's agentName).`}),depth:x.Number({description:`0 for a direct child of the session, 1 for a grandchild, and so on (ADR-0016).`}),label:x.String({description:`The label the task was dispatched with.`}),output_bytes:x.Optional(x.Number({description:`Captured output size; absent while the task has flushed no output.`})),error_message:x.Optional(x.String({description:`Failure text; absent unless the record carries an error.`}))}),{description:`One row per task, newest first — the same order as details.tasks.`}),count:x.Number({description:"Number of rows in `tasks`."})});function Ui(e){return{id:e.id,status:e.status,agent:e.agentName,depth:e.depth,label:e.label,...e.outputBytes===void 0?{}:{output_bytes:e.outputBytes},...e.errorMessage===void 0?{}:{error_message:e.errorMessage}}}function Wi(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,W(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${W(e.errorMessage)}`),t.join(` `)}function Gi(e){return L({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(`
42
- `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...zi],parameters:Vi,outputSchema:Hi,async execute(t,n){let r=await e.query({...n.status===void 0?{}:{status:n.status},limit:n.limit??100,orderBy:`createdAt-desc`}),i=r.length===0?`(no background tasks)`:r.map(e=>Wi(e)).join(`
43
- `),a={tasks:r.map(e=>Ui(e)),count:r.length};return{content:[{type:`text`,text:i}],details:{tasks:r,count:r.length},structuredContent:a}},...Ri(`task-list`)})}async function Ki(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}function qi(e){return{input:e.input,output:e.output,cost:e.cost,turns:e.turns}}function Ji(e){return`usage: input=${String(e.input)} output=${String(e.output)} cost=${String(e.cost)} turns=${String(e.turns)}`}function Yi(e,t,n){let r=`<child-report channel="${e}">${t}`;return n===void 0?`${r}</child-report>`:`${r}\n${Ji(n)}\n</child-report>`}function Xi(e){let t=e.reportChannel;if(t===void 0)return;let n=e.usage===void 0?void 0:qi(e.usage);if(t===`none`)return Yi(t,`the child produced no report; it did not comply with the report contract. What follows is its prose, unbacked by a report.`,n);if(t===`opted-out`)return Yi(t,`this agent opts out of the report contract, so none was asked for; the prose below is the whole of what it produced, and nothing is missing.`,n);let r=e.report;if(r===void 0)return Yi(t,`the record names channel ${t} but carries no report.`,n);let i=[`<child-report channel="${t}">`,`summary: ${r.summary}`],a=r.findings.slice(0,20),o=r.findings.length-a.length;i.push(`findings (${String(r.findings.length)}):`);for(let[e,t]of a.entries())i.push(` ${String(e+1)}. ${t.what} — evidence: ${t.evidence}`);return o>0&&i.push(` …+${String(o)} more findings not shown`),i.push(r.files_touched.length===0?`files_touched: (none)`:`files_touched: ${r.files_touched.join(`, `)}`),i.push(Ji(r.usage)),i.push(`</child-report>`),i.join(`
44
- `)}const Zi=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.`}))}),Qi=x.Object({task_id:x.String({description:`The background task id that was asked for.`}),status:x.String({description:`The task's status at read time (ADR-0022 §2's six states), so a polling script does not need a second ptc_task_list call.`}),output:x.String({description:`The page the model reads: the stored output's tail, ADR-0015-truncated.`}),output_bytes:x.Number({description:`Total bytes stored for the task, regardless of sinceBytes or ADR-0015 truncation.`}),output_preview:x.Optional(x.String({description:`The complete stored output; present only at or below the 2048-byte preview ceiling (ADR-0022 §7).`})),output_truncated:x.Boolean({description:"Whether ADR-0015 cut anything out of `output`."}),output_full_path:x.Optional(x.String({description:"A file holding the complete output; present only when `output_truncated` is true (ADR-0015 §2)."})),report_channel:x.Optional(x.String({description:"Which channel delivered the child's report: `tool`, `prompt-json`, or `none` when the child ignored the contract (ADR-0032). Absent until the task succeeds — a running or failed task carries no report claim at all."})),read_only_tier:x.Optional(x.String({description:"The read-only tier the dispatch resolved to: `strict` or `lenient` (ADR-0041). Absent when the dispatch asked for no tier. Present from spawn onwards, including for a task that later failed — a failed read-only child was still dispatched read-only."})),report:x.Optional(x.Object({summary:x.String({description:`The child's own one-line summary.`}),findings:x.Array(x.Object({what:x.String({description:`The claim the child makes.`}),evidence:x.String({description:`The evidence that claim rests on.`})}),{description:`One entry per claim the child made.`}),files_touched:x.Array(x.String(),{description:`Paths the child says it touched.`}),usage:x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})},{description:"The host's own count for this child, in the same four fields `report.usage` carries (ADR-0032, issue #199). ABSENT when no top-level count was recorded: a `running` / `stopping` task has not closed yet, a `lost` record was never observed closing, and a record written before the field existed carries none — a pre-change record that has a report still renders the report's own host-stamped numbers. Present on every close outcome including `failed` and `canceled`, and independent of `report_channel` — so a child that reported nothing still accounts for what it cost. The text block states the same four numbers on the `usage: …` line."}))});function $i(e,t){return L({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`A succeeded task also renders its child report (summary, findings, files touched, usage) ahead of the prose, and says which channel delivered it; a channel of "none" means the child ignored the report contract.`,`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(`
45
- `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...zi],parameters:Zi,outputSchema:Qi,async execute(n,r){let i=r.taskId,a=await Ki(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=gi(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f=Xi(a),p=a.usage===void 0?void 0:qi(a.usage),m={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath},...a.report===void 0?{}:{report:a.report},...a.reportChannel===void 0?{}:{reportChannel:a.reportChannel},...a.readOnlyTier===void 0?{}:{readOnlyTier:a.readOnlyTier}},h=m.output.length>0?m.output:`(no output yet; task ${i} is ${a.status})`,g=f??(p===void 0?void 0:Ji(p)),_=g===void 0?h:`${g}\n${h}`,v=ur(a.readOnlyTier),y=v.length===0?_:`${v}\n${_}`,b={task_id:i,status:a.status,output:u.text,output_bytes:s,...d===void 0?{}:{output_preview:d},output_truncated:u.truncated,...u.fullPath===void 0?{}:{output_full_path:u.fullPath},...a.reportChannel===void 0?{}:{report_channel:a.reportChannel},...a.readOnlyTier===void 0?{}:{read_only_tier:a.readOnlyTier},...a.report===void 0?{}:{report:a.report},...p===void 0?{}:{usage:p}};return{content:[{type:`text`,text:y}],details:m,structuredContent:b}},...Ri(`task-output`)})}const ea=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".`}))}),ta=x.Object({task_id:x.String({description:`The background task id that was asked to stop.`}),status:x.String({description:"The task's status AFTER the stop command — `stopping`, not the terminal `canceled`; the dispatcher pump owns the latter (ADR-0022 §8)."}),from_status:x.String({description:"The status observed before the stop: `running` for a fresh stop, `stopping` for the idempotent late-arrival path (ADR-0022 §8)."}),stop_reason:x.Optional(x.String({description:`The reason recorded as the task's stopReason; absent when the record carries none.`}))});function na(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return L({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(`
46
- `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...zi],parameters:ea,outputSchema:ta,async execute(t,n){let i=n.taskId,a=await Ki(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=${W(s.stopReason)}`,u=c??a.status,d={task_id:i,status:s.status,from_status:u,...s.stopReason===void 0?{}:{stop_reason:s.stopReason}};return{content:[{type:`text`,text:`${s.id} ${s.status}${l}`}],details:{task:s,fromStatus:u},structuredContent:d}},...Ri(`task-stop`)})}var ra=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=ze(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Re(),r=new Cn({buildWorkerUrl:En,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:bn({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 ia={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var aa=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??ia,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 oa={mkdir:(e,t)=>me(e,t),readFile:(e,t)=>he(e,t),writeFile:(e,t,n)=>ye(e,t,n),appendFile:(e,t,n)=>pe(e,t,n),rename:(e,t)=>_e(e,t),unlink:e=>ve(e),readdir:e=>ge(e)};function sa(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function ca(e){return e instanceof Error?e.message:String(e)}function la(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var ua=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??oa}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){N(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(j(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){N(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||la(r[t-1],e)<=0)?r:[...r].sort(la)).map(e=>JSON.stringify(e)).join(`
26
+ `)}function er(e){if(typeof e==`string`)return $n(G(e));if(typeof e!=`object`||!e)return String(e);let t=Yn(e);return $n((t===void 0?Qn(e,``):[t]).join(`
27
+ `))}function tr(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function nr(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 rr(e,t){let n=e===void 0?void 0:new Set(e),r=new Set(mn(t));return V.filter(e=>(n===void 0||n.has(e))&&(hn.includes(e)||r.has(e)))}const ir=["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.`],ar="A `codemode` script cannot call the parallel binding directly: `pi.dispatch` is never in that script's own tool table, on any surface. A script reaches it by calling `ptc_run_code` or `ptc_workflow` and using the binding inside the program.",or={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function sr(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function cr(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 lr(e){return[...e.phases.map(e=>`[phase] ${G(e)}`),...e.narrations.map(e=>`[log] ${G(e)}`),...e.logs.map(e=>G(e))]}function ur(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=lr(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
28
+ `)}`,i=Error(G(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function dr(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(`
29
+ `)),t.logs.length>0&&a.push(t.logs.map(e=>G(e)).join(`
30
+ `)),t.value!==void 0&&a.push(er(t.value));for(let e of r)a.push(`Warning: ${G(e)}`);let o=Hn(a.length>0?a.join(`
31
+ `):`(${or[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 fr=`└─ `;function pr(e){return e===void 0?``:`read-only tier (${e})\n${fr}${e===`strict`?`the child's tool list was narrowed to the read set, so it was never offered a write tool`:`the child's tool list is UNCHANGED — it was told to work without modifying anything, and nothing here prevents it from doing so`}`}const mr=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function hr(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function gr(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 _r(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=gr(e,n):(n+=1,r+=1);return n}function vr(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:yr(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 yr(e,t,n){return e.map(e=>{let r=hr(e),i=mr.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=_r(e,s),l=_r(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 br={run_code:`PTC`,workflow:`PTC workflow`},xr=`└─ `,Sr=`├─ `,Cr=`│ `;var wr=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>Tr(e,t))}};function Tr(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 K(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Er(e){return K((G(e).split(`
32
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function Dr(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function Or(e,t){return`${e} ${t}${e===1?``:`s`}`}function kr(e){for(let t of e.split(`
33
+ `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return K(e.replace(/\s*\/\/.*$/,``),120)}}function Ar(e){if(e===void 0)return;if(typeof e==`string`){let t=G(e).split(`
34
+ `),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:K(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=er(e);if(!t.includes(`
35
+ `)&&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 jr(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,Or(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,Or(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,Or(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,Or(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Dr(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Mr(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 Nr(e,t,n){let r=` `+(t?fr:Sr),i=` `+(t?` `:Cr),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 Pr(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const Fr=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Ir(e){return Fr.test(e)?e:JSON.stringify(e)}function Lr(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(`
36
+ `)){let e=K(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(K(n,Math.max(2,t-5)))+`…`}return`?`}function Rr(e){return typeof e!=`object`||!e}function zr(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Rr))return;let n=`[`+e.map(e=>Lr(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(Rr))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Ir(n)+`: `+Lr(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Br(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(q(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(q(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(q(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-L(l)-t.length);c.push(q(l+t+Lr(e,n),o));return}let d=zr(e,Math.max(0,o-L(l)-t.length));if(d!==void 0){c.push(q(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(q(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;Br(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];Br(e[l]??null,Ir(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(q(u+`└─ …+`+(p-h)+` more `+e,o))}}function q(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 Vr(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Pr(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Lr(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;Br(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];Br(e[d]??null,Ir(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}const Hr=`child report`;function Ur(e){return e===0?`[]`:`Array(${e})`}function Wr(e){let t=G(e).split(`
37
+ `).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:K(t,200)}function Gr(e){let t=Number(e.cost.toFixed(4));return`in ${e.input} · out ${e.output} · cost ${t} · ${Or(e.turns,`turn`)}`}function Kr(e,t,n){let r=G(n).replace(/\n/g,` `).trim();return r.length<=150?`${e}${t}evidence: ${r}`:`${e}${t}evidence: ${r.slice(0,150)}… (truncated at 150 chars)`}function qr(e,t){let n=[];return e.forEach((r,i)=>{let a=i===e.length-1&&t===0,o=`[${i}]`;n.push(`${a?`└─ `:`├─ `}${o} ${G(r.what).trim()}`.trimEnd()),n.push(Kr(a?` `:`│ `,` `.repeat(o.length+2),r.evidence))}),t>0&&n.push(`└─ …+${t} more findings withheld (a report renders at most 20)`),n}function Jr(e,t){let n=e.map((n,r)=>`${r===e.length-1&&t===0?`└─ `:`├─ `}[${r}] `+`${G(n).trim()}`.trimEnd());return t>0&&n.push(`└─ …+${t} more files withheld (a report renders at most 20)`),n}function Yr(e,t){let n=e.label.length>=8?`${e.label} `:e.label.padEnd(8);return q(`${t?fr:Sr}${n}${e.head}`,200)}function Xr(e,t){let n=e===`none`?`no child report was returned — the child did not comply with the contract, so its prose below is unbacked by a report`:e===`opted-out`?`this agent opts out of the report contract, so none was asked for — the prose below is the whole of what it produced, and nothing is missing`:`the ${e} channel was announced but no report reached the host; the child's prose below is everything it produced`,r=`${Hr} (channel: ${e})`;return t===void 0?`${r}\n${fr}${n}`:`${r}\n${Sr}${n}\n${Yr({label:`usage`,head:Gr(t),rows:[]},!0)}`}function Zr(e,t,n){if(e===void 0)return Xr(t,n);let r=e.findings.slice(0,20),i=e.findings.length-r.length,a=e.files_touched.slice(0,20),o=e.files_touched.length-a.length,s=[{label:`summary`,head:Wr(e.summary),rows:[]},{label:`findings`,head:Ur(e.findings.length),rows:qr(r,i)},{label:`files`,head:Ur(e.files_touched.length),rows:Jr(a,o)},{label:`usage`,head:Gr(n??e.usage),rows:[]}],c=[`${Hr} (channel: ${t})`];return s.forEach((e,t)=>{let n=t===s.length-1;c.push(Yr(e,n));let r=n?` `:Cr;for(let t of e.rows)c.push(q(`${r}${t}`,200))}),c.join(`
38
+ `)}function Qr(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=kr(e.code??e.script??``),o=i.length>0?i:a??`(no description)`,s=`${t.fg(`toolTitle`,t.bold(br[n]))} ${t.fg(`accent`,o)}`;return vr(new wr([{left:`${xr}${s}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??ei,state:r.state??{}})}function $r(e,t,n={}){let r=(typeof e.task==`string`?G(e.task):``).split(`
39
+ `).map(e=>e.trim()).filter(e=>e.length>0),i=typeof e.agent==`string`&&e.agent.trim().length>0?e.agent.trim():`(generalist)`,a=[e.background===!0?`background`:`foreground`];e.readOnly!==void 0&&a.push(`read-only:`+e.readOnly),typeof e.model==`string`&&e.model.trim().length>0&&a.push(`model=`+e.model.trim()),e.agentScope!==void 0&&a.push(`scope=`+e.agentScope);let o=[{left:`${xr}${t.fg(`toolTitle`,t.bold(`subagent`))} ${t.fg(`accent`,`→ `+i)}`,right:t.fg(`dim`,a.join(` · `))}];if(n.expanded!==!0){let e=r[0];if(e!==void 0){o.push({left:` ${t.fg(`dim`,`│ `+e)}`});let n=r.length-1;n>0&&o.push({left:` ${t.fg(`dim`,` … 还有 `+n+` 行(ctrl+e 展开)`)}`})}}else{let n=e=>t.fg(`dim`,e.padEnd(8)),i=[];if(typeof e.label==`string`){let t=Er(G(e.label));t.length>0&&i.push([`label`,t])}if(typeof e.why==`string`){let t=Er(G(e.why));t.length>0&&i.push([`why`,t])}for(let[e,t]of i)o.push({left:` ${Sr}${n(e)}${t}`});let a=r[0]??`(empty)`;o.push({left:` ${fr}${n(`task`)}${a}${r.length>1?` (`+String(r.length)+` 行)`:``}`});let s=r.slice(1,13),c=` `;for(let e of s)o.push({left:`${c}${t.fg(`dim`,e)}`});let l=r.length-1-s.length;l>0&&o.push({left:`${c}${t.fg(`dim`,`… +`+String(l)+` 行(ctrl+e 收起)`)}`})}return vr(new wr(o),{intervalMs:150,isPartial:n.isPartial??!1,theme:t,requestInvalidate:n.requestInvalidate??ei,state:n.state??{}})}function ei(){}function ti(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Er(t?.text??``)||`failed`}function ni(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t){let e=t.agent;return typeof e==`string`&&e.trim().length>0?`→ ${e}`:e===void 0?`→ (generalist)`:`→ ${JSON.stringify(e)}`}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 ri={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Dr(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 ii(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=ni(e.name,e.args),l=ri[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 ai(e,t,n,r=!1,i=!1){let a=jr(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${ti(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(Pr(s))return Vr(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=Ar(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function oi(e,t,n,r={}){let i=Mr(e.details),a=[...ai({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...ii(i.subCalls,n)),new wr(a)}function si(e,t,n,r,i={}){let a=Mr(e.details);if(n){let t=[...ai({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...ii(a.subCalls,r));let n=G(e.content?.find(e=>e.type===`text`)?.text??ti(e));for(let e of n.split(`
40
+ `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new wr(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
41
+ `).map(e=>K(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=ai({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...ii(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...Nr(o[e]??{label:``,lines:[]},t,r))}return new wr(u)}function ci(e){return{renderCall(t,n,r){return Qr(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?si(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):oi(e,r?.isError===!0,n,{isPartial:i})}}}const li=["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" })`.',`The bound names are this session's active built-in tools, less any binding the install has not`,`explicitly opted in — this surface is narrower than the session's tool list on purpose;`,"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.`,``,ar,``,Rn,``,"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(`
42
+ `),ui=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 di(e={}){return R({name:`ptc_run_code`,label:`PTC Run Code`,exposure:e.exposure,description:li,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:[...ir],parameters:ui,async execute(t,n,r,i,a){let o=sr(a),s=rr(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=cr({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await Fn({code:n.code,surface:`run_code`,cwd:o,bindings:Sn({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 ur(p);return dr({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...ci(`run_code`)})}const fi=[`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",`are this session's enabled built-ins less any binding the install has not opted in. 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.",``,ar,``,Rn,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
43
+ `),pi=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 mi(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=hi(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function hi(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=hi(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=hi(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function gi(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 _i(e={}){return R({name:`ptc_workflow`,label:`PTC Workflow`,exposure:e.exposure,description:fi,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...ir],parameters:pi,async execute(t,n,r,i,a){mi(n.args);let o=sr(a),s=rr(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=cr({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await Fn({code:n.script,surface:`workflow`,cwd:o,bindings:Sn({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 ur(p);let m=n.meta.phases?.map(e=>e.name);return dr({outcome:p,surface:`workflow`,warnings:gi(p,m),durationMs:Date.now()-c})},...ci(`workflow`)})}var vi=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 yi(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var bi=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await me(this.#t(e),`utf8`)}catch(e){if(yi(e))return null;throw e}}async writeOutput(e,t){let n=N(this.#e,`tasks`,e);await pe(n,{recursive:!0}),await ve(N(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return N(this.#e,`tasks`,e,`output.log`)}};function xi(e,t){return Hn(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}function Si(e){return e===!0?"why suppressed\n└─ you passed a `why` and this session's `whyEnabled` switch is off, so the child's prompt carried no <pi-ptc-why> block. The child was never told your reason — it was not ignoring it. The value itself is not recorded anywhere.":``}const Ci={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},wi={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var J=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>Ti(e,t))}};function Ti(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 Ei(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Di(e){return Ei((G(e).split(`
44
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function Oi(e){if(typeof e!=`string`||e.length===0)return;let t=Di(e);return t.length===0?void 0:t}function ki(e){return typeof e==`object`&&e?e:{}}function Ai(e){return e===`running`||e===`stopping`}function ji(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 Mi(e,t){if(Ai(e.status))return ji(t-e.createdAt);if(e.durationMs!==void 0)return ji(e.durationMs);if(e.finishedAt!==void 0)return ji(e.finishedAt-e.createdAt)}function Ni(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 Pi(){}function Fi(e,t,n){return new J([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function Ii(e,t,n){let r=ki(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 Fi(`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 Fi(`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 Fi(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Li(e,t,n,r){let i=Ci[e.status]??`muted`,a=n.fg(i,wi[e.status]??`?`),o=Ei(G(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,G(e.agentName))],c=Mi(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 Ri(e){if(e.status===`failed`||e.status===`lost`)return Oi(e.errorMessage)}function zi(e,t){let n=ki(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Ni(new J([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>Ai(e.status)),a=r.slice(0,32),o=r.length-a.length,s=[];return a.forEach((e,n)=>{s.push(Li(e,n===a.length-1&&o===0,t.theme,t.now));let r=Ri(e);r!==void 0&&s.push({left:` ${t.theme.fg(`error`,`error: ${r}`)}`})}),o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Ni(new J(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Bi(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 Vi(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Hi(e,t){let n=ki(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=Bi(i,a,t.theme),c=[],l=Oi(n.errorMessage);if(l!==void 0&&c.push({left:` ${t.theme.fg(`error`,`error: ${l}`)}`}),r.length>0){let e=G(r).split(`
45
+ `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,Ei(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:Vi(o,t.theme)})}else if(o!==void 0)c.push({left:Vi(o,t.theme),...s===void 0?{}:{right:s}});else{let e=l===void 0?`(no output yet)`:`(no output)`;c.push({left:` ${t.theme.fg(`muted`,e)}`,...s===void 0?{}:{right:s}})}return new J(c)}function Ui(e,t){let n=ki(e),r=n.task;if(typeof r!=`object`||!r)return new J([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=Ci[r.status]??`muted`,a=t.theme.fg(i,wi[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 J([{left:` ${c.join(` `)}`}])}function Wi(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=Di(n?.text??``)||`failed`;return new J([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Gi(e,t,n){switch(e){case`task-list`:return zi(t.details,n);case`task-output`:return Hi(t.details,n);case`task-stop`:return Ui(t.details,n)}}function Ki(e){return{renderCall(t,n){return Ii(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Wi(t,r):Gi(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Pi,state:i?.state??{},now:Date.now()})}}}const qi=[`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). A succeeded task's child report is rendered there, ahead of the prose.`,`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.`],Ji=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Yi=x.Object({status:x.Optional(x.Array(Ji,{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.`}))}),Xi=x.Object({tasks:x.Array(x.Object({id:x.String({description:`The task's ULID — the id ptc_task_output and ptc_task_stop take.`}),status:x.String({description:`One of running, stopping, succeeded, failed, canceled, lost (ADR-0022 §2).`}),agent:x.String({description:`The agent the task was dispatched with (the record's agentName).`}),depth:x.Number({description:`0 for a direct child of the session, 1 for a grandchild, and so on (ADR-0016).`}),label:x.String({description:`The label the task was dispatched with.`}),output_bytes:x.Optional(x.Number({description:`Captured output size; absent while the task has flushed no output.`})),error_message:x.Optional(x.String({description:`Failure text; absent unless the record carries an error.`}))}),{description:`One row per task, newest first — the same order as details.tasks.`}),count:x.Number({description:"Number of rows in `tasks`."})});function Zi(e){return{id:e.id,status:e.status,agent:e.agentName,depth:e.depth,label:e.label,...e.outputBytes===void 0?{}:{output_bytes:e.outputBytes},...e.errorMessage===void 0?{}:{error_message:e.errorMessage}}}function Qi(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 $i(e){return R({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(`
46
+ `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...qi],parameters:Yi,outputSchema:Xi,async execute(t,n){let r=await e.query({...n.status===void 0?{}:{status:n.status},limit:n.limit??100,orderBy:`createdAt-desc`}),i=r.length===0?`(no background tasks)`:r.map(e=>Qi(e)).join(`
47
+ `),a={tasks:r.map(e=>Zi(e)),count:r.length};return{content:[{type:`text`,text:i}],details:{tasks:r,count:r.length},structuredContent:a}},...Ki(`task-list`)})}async function ea(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}function ta(e){return{input:e.input,output:e.output,cost:e.cost,turns:e.turns}}function na(e){return`usage: input=${String(e.input)} output=${String(e.output)} cost=${String(e.cost)} turns=${String(e.turns)}`}function ra(e,t,n){let r=`<child-report channel="${e}">${t}`;return n===void 0?`${r}</child-report>`:`${r}\n${na(n)}\n</child-report>`}function ia(e){let t=e.reportChannel;if(t===void 0)return;let n=e.usage===void 0?void 0:ta(e.usage);if(t===`none`)return ra(t,`the child produced no report; it did not comply with the report contract. What follows is its prose, unbacked by a report.`,n);if(t===`opted-out`)return ra(t,`this agent opts out of the report contract, so none was asked for; the prose below is the whole of what it produced, and nothing is missing.`,n);let r=e.report;if(r===void 0)return ra(t,`the record names channel ${t} but carries no report.`,n);let i=[`<child-report channel="${t}">`,`summary: ${r.summary}`],a=r.findings.slice(0,20),o=r.findings.length-a.length;i.push(`findings (${String(r.findings.length)}):`);for(let[e,t]of a.entries())i.push(` ${String(e+1)}. ${t.what} — evidence: ${t.evidence}`);return o>0&&i.push(` …+${String(o)} more findings not shown`),i.push(r.files_touched.length===0?`files_touched: (none)`:`files_touched: ${r.files_touched.join(`, `)}`),i.push(na(r.usage)),i.push(`</child-report>`),i.join(`
48
+ `)}const aa=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.`}))}),oa=x.Object({task_id:x.String({description:`The background task id that was asked for.`}),status:x.String({description:`The task's status at read time (ADR-0022 §2's six states), so a polling script does not need a second ptc_task_list call.`}),error_message:x.Optional(x.String({description:"The record's raw reason for a `failed` or `lost` task (ADR-0022 §2 / issue #70) — the string the text block prints as `error=…` after sanitizing it for display, and the same field `ptc_task_list` projects as `error_message`. Absent unless the record carries an error: a running task has no failure yet, and a `succeeded` or `canceled` close records no reason of its own."})),output:x.String({description:`The page the model reads: the stored output's tail, ADR-0015-truncated.`}),output_bytes:x.Number({description:`Total bytes stored for the task, regardless of sinceBytes or ADR-0015 truncation.`}),output_preview:x.Optional(x.String({description:`The complete stored output; present only at or below the 2048-byte preview ceiling (ADR-0022 §7).`})),output_truncated:x.Boolean({description:"Whether ADR-0015 cut anything out of `output`."}),output_full_path:x.Optional(x.String({description:"A file holding the complete output; present only when `output_truncated` is true (ADR-0015 §2)."})),report_channel:x.Optional(x.String({description:"Which channel delivered the child's report: `tool`, `prompt-json`, or `none` when the child ignored the contract (ADR-0032). Absent until the task succeeds — a running or failed task carries no report claim at all."})),read_only_tier:x.Optional(x.String({description:"The read-only tier the dispatch resolved to: `strict` or `lenient` (ADR-0041). Absent when the dispatch asked for no tier. Present from spawn onwards, including for a task that later failed — a failed read-only child was still dispatched read-only."})),why_suppressed:x.Optional(x.Boolean({description:"`true` when you passed a `why` and this session's `whyEnabled` switch was off, so the child's prompt carried no <pi-ptc-why> block (ADR-0043). ABSENT means no `why` was passed — that is the distinction the key exists to make. The child was never told your reason; it did not ignore one. The dropped value is not stored."})),report:x.Optional(x.Object({summary:x.String({description:`The child's own one-line summary.`}),findings:x.Array(x.Object({what:x.String({description:`The claim the child makes.`}),evidence:x.String({description:`The evidence that claim rests on.`})}),{description:`One entry per claim the child made.`}),files_touched:x.Array(x.String(),{description:`Paths the child says it touched.`}),usage:x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})},{description:"The host's own count for this child, in the same four fields `report.usage` carries (ADR-0032, issue #199). ABSENT when no top-level count was recorded: a `running` / `stopping` task has not closed yet, a `lost` record was never observed closing, and a record written before the field existed carries none — a pre-change record that has a report still renders the report's own host-stamped numbers. Present on every close outcome including `failed` and `canceled`, and independent of `report_channel` — so a child that reported nothing still accounts for what it cost. The text block states the same four numbers on the `usage: …` line."}))});function sa(e,t){return R({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`A succeeded task also renders its child report (summary, findings, files touched, usage) ahead of the prose, and says which channel delivered it; a channel of "none" means the child ignored the report contract.`,`A failed or lost task also states the record's error message — the reason it did not succeed — ahead of the output, so an empty output.log is not mistaken for an infrastructure fault.`,`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(`
49
+ `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...qi],parameters:aa,outputSchema:oa,async execute(n,r){let i=r.taskId,a=await ea(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=xi(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f=ia(a),p=a.usage===void 0?void 0:ta(a.usage),m={taskId:i,output:u.text,outputBytes:s,...a.errorMessage===void 0?{}:{errorMessage:a.errorMessage},...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath},...a.report===void 0?{}:{report:a.report},...a.reportChannel===void 0?{}:{reportChannel:a.reportChannel},...a.readOnlyTier===void 0?{}:{readOnlyTier:a.readOnlyTier},...a.whySuppressed===void 0?{}:{whySuppressed:a.whySuppressed}},h=m.output.length>0?m.output:a.status===`running`||a.status===`stopping`?`(no output yet; task ${i} is ${a.status})`:`(no output; task ${i} is ${a.status})`,g=[f,a.errorMessage===void 0?void 0:`error=${G(a.errorMessage)}`,f===void 0&&p!==void 0?na(p):void 0].filter(e=>e!==void 0),_=g.length===0?void 0:g.join(`
50
+ `),v=_===void 0?h:`${_}\n${h}`,y=pr(a.readOnlyTier),b=y.length===0?v:`${y}\n${v}`,x=Si(a.whySuppressed),S=x.length===0?b:`${x}\n${b}`,C={task_id:i,status:a.status,...a.errorMessage===void 0?{}:{error_message:a.errorMessage},output:u.text,output_bytes:s,...d===void 0?{}:{output_preview:d},output_truncated:u.truncated,...u.fullPath===void 0?{}:{output_full_path:u.fullPath},...a.reportChannel===void 0?{}:{report_channel:a.reportChannel},...a.readOnlyTier===void 0?{}:{read_only_tier:a.readOnlyTier},...a.whySuppressed===void 0?{}:{why_suppressed:a.whySuppressed},...a.report===void 0?{}:{report:a.report},...p===void 0?{}:{usage:p}};return{content:[{type:`text`,text:S}],details:m,structuredContent:C}},...Ki(`task-output`)})}const ca=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".`}))}),la=x.Object({task_id:x.String({description:`The background task id that was asked to stop.`}),status:x.String({description:"The task's status AFTER the stop command — `stopping`, not the terminal `canceled`; the dispatcher pump owns the latter (ADR-0022 §8)."}),from_status:x.String({description:"The status observed before the stop: `running` for a fresh stop, `stopping` for the idempotent late-arrival path (ADR-0022 §8)."}),stop_reason:x.Optional(x.String({description:`The reason recorded as the task's stopReason; absent when the record carries none.`}))});function ua(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return R({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(`
51
+ `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...qi],parameters:ca,outputSchema:la,async execute(t,n){let i=n.taskId,a=await ea(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)}`,u=c??a.status,d={task_id:i,status:s.status,from_status:u,...s.stopReason===void 0?{}:{stop_reason:s.stopReason}};return{content:[{type:`text`,text:`${s.id} ${s.status}${l}`}],details:{task:s,fromStatus:u},structuredContent:d}},...Ki(`task-stop`)})}var da=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=Re(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Le(),r=new En({buildWorkerUrl:kn,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:wn({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 fa={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var pa=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??fa,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 ma={mkdir:(e,t)=>pe(e,t),readFile:(e,t)=>me(e,t),writeFile:(e,t,n)=>ve(e,t,n),appendFile:(e,t,n)=>fe(e,t,n),rename:(e,t)=>ge(e,t),unlink:e=>_e(e),readdir:e=>he(e)};function ha(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function ga(e){return e instanceof Error?e.message:String(e)}function _a(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var va=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??ma}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){F(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(N(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){F(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||_a(r[t-1],e)<=0)?r:[...r].sort(_a)).map(e=>JSON.stringify(e)).join(`
47
52
  `)+`
48
- `;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(la);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(j(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(sa(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+`: `+ca(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(sa(e))return[];throw e}let n=[];for(let r of t.split(`
49
- `)){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+`: `+ca(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(A(e),{recursive:!0});let n=e+`.tmp-`+ce();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(sa(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(sa(e))return!1;throw e}}#l(){return j(this.#e,`tasks`)}#u(){return j(this.#e,`subscriptions`)}#d(){return j(this.#e,`events`)}#f(e){return j(this.#l(),e+`.json`)}#p(e,t){return j(this.#u(),e+`-`+t+`.json`)}#m(e,t){return j(this.#d(),e+`-`+t+`.jsonl`)}};function da(e,t){return new ua(e,t)}const fa=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),pa=/* @__PURE__ */ new Set([`running`,`stopping`]),ma=2**53-1,ha={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function J(e){return e instanceof Error?e.message:String(e)}function ga(e){return e===void 0||e.length===0?`<in-memory>`:e}function _a(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var va=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()}},ya=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)}},ba=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)}},xa=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]}},Sa=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??ha,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??Xe,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new nt:da(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new pi:new hi(e));let t=(e.createInitialStorage??(()=>new nt))(),n=$e(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new aa(t,{now:this.clock,logger:this.#e});this.registry=new va(n),this.outputStorage=new ya(new pi),this.pipeline=new ba(r),this.lifecycle=new xa((e.createLifecycle??(()=>new Fe({logger:this.#e})))()),this.slots=new it(e.concurrency??R.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||fa.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+J(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 `+ga(e)+` is unavailable: `+J(n),t),[]}let i=$e(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new aa(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): `+J(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:ma})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+J(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+`: `+J(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+`: `+J(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:ma})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+J(e)),t=[]}let n=[];for(let r of t)if(pa.has(r.status)&&Ye(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:_a(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+J(e))}for(let e of this.lifecycle.liveHandles()){let t=gt(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: `+J(e))}}};function Ca(e={}){return new Sa(e)}const wa=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function Ta(e){return wa.has(e.status)}function Ea(e,t){if(e.length===0)return``;let n=e.map(Oa).join(`
50
- `);return`${`<bg-task-notifications batch-id="${Y(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function Da(e,t=102400){let n=[],r=[],i=0,a=t-Aa;for(let t of e){let e=ka(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 Oa(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="${Y(t.type)}"`,` task-id="${Y(t.taskId)}"`,` subscription-id="${Y(t.subscriptionId)}"`,` status="${Y(t.status)}"`,` label="${Y(n.label)}"`,` agent-name="${Y(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>${Y(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${Y(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
51
- `)}function Y(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
52
- `,`&#10;`).replaceAll(`\r`,`&#13;`)}function ka(e){return Buffer.byteLength(Oa(e),`utf8`)}const Aa=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),ja=[`ptc_run_code`,`ptc_workflow`],Ma=[`read`,`bash`,`edit`,`write`],Na=`ptc-mode`,Pa=`ptc-mode`,Fa=`ptc.json`,Ia=`builtins-only`;function La(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function Ra(e){let t=j(e,Fa),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 za(e){let t=j(e,Fa),n;try{n=T(t,`utf8`)}catch{return{optInBindings:[],source:`default`}}let r;try{r=JSON.parse(n)}catch{return{optInBindings:[],source:`default`}}if(typeof r!=`object`||!r||Array.isArray(r))return{optInBindings:[],source:`default`};let i=r.optInBindings;if(i===void 0)return{optInBindings:[],source:`default`};if(!Array.isArray(i))return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" must be an array of binding names, received ${typeof i}`};let a=i.find(e=>typeof e!=`string`);if(a!==void 0)return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" entries must be strings, received ${typeof a}`};try{return{optInBindings:dn(i),source:`file`}}catch(e){return{optInBindings:[],source:`invalid`,error:`${t}: ${e instanceof Error?e.message:String(e)}`}}}const X=`builtin:codemode`;function Z(e){return e.split(ae).join(`/`)}function Ba(e){return e===`~`?D():e.startsWith(`~/`)?j(D(),e.slice(2)):e.startsWith(`file://`)?P(e):e}function Va(e){return Z(Ba(e.startsWith(`./`)||e.startsWith(`.\\`)?e.slice(2):e))}function Ha(e,t,n){let r=Z(ie(n,e)),i=re(e),a=Z(e);return t.some(e=>{let t=Z(Ba(e));return be(r,t)||be(i,t)||be(a,t)})}function Ua(e,t,n){if(t.length===0)return!1;let r=Z(ie(n,e)),i=Z(e);return t.some(e=>{let t=Va(e);return t===r||t===i})}function Wa(e){let t=[];for(let n of e){if(typeof n!=`string`)continue;let e=n[0];(e===`+`||e===`-`||e===`!`)&&t.push({sign:e,target:n.slice(1)})}return t}function Ga(e,t){if(!Array.isArray(e))return;let n;for(let{sign:r,target:i}of Wa(e)){let e=r!==`-`&&r!==`!`;(r===`+`||r===`-`?Ua(X,[i],t):Ha(X,[i],t))&&(n=e?`enabled`:`disabled`)}return n}function Ka(e,t){if(!Array.isArray(e))return;let n=Wa(e),r=e=>n.filter(t=>t.sign===e).map(e=>e.target),i=r(`!`),a=r(`+`),o=r(`-`),s;return Ha(X,i,t)&&(s=`disabled`),Ua(X,a,t)&&(s=`enabled`),Ua(X,o,t)&&(s=`disabled`),s}function qa(e){for(let t=0;t<e.length;t+=1){let n=e[t];if((n===`-e`||n===`--extension`)&&e[t+1]===X)return!0}return!1}function Ja(e){let t;try{t=T(e,`utf8`)}catch{return{value:void 0}}try{let n=JSON.parse(t);return typeof n!=`object`||!n||Array.isArray(n)?{value:void 0,error:`${e} must contain a JSON object`}:{value:n}}catch(t){return{value:void 0,error:`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`}}}function Ya(e,t,n,r={project:process.cwd(),user:process.cwd()}){let i=e.slice(1);if(qa(i))return{switch:`enabled`,source:`cli`};if(i.some(e=>e===`-ne`||e===`--no-extensions`))return{switch:`disabled`,source:`cli`};let a=t?.extensions,o=Ga(a,r.project);if(o!==void 0)return{switch:o,source:`project`};let s=n?.extensions,c=Ka(s,r.user);return c===void 0?{switch:`absent`,source:`default`}:{switch:c,source:`user`}}function Xa(e,t,n=process.argv){let r=Ja(j(t,`.pi`,`settings.json`)),i=Ja(j(e,`settings.json`)),a=Ya(n,r.value,i.value,{project:j(t,`.pi`),user:e}),o=r.error??i.error;return o===void 0?a:{...a,source:`invalid`,error:o}}function Za(e){return{activation:e.includes(`codemode`)?`active`:`inactive`,source:`loadout`}}function Qa(e,t,n){return fo(Za(n),uo(e,t))}const $a=[`codemode`,`deferred`,`direct`,`hidden`],eo={"codemode-deferred":`codemode`},to=/^[A-Za-z0-9_-]+$/;function no(e){return typeof e==`string`?eo[e]??e:e}function ro(e){return typeof e==`string`&&$a.includes(e)}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function io(e){return Q(e)&&Object.values(e).every(e=>typeof e==`string`)}function ao(e){return URL.canParse(e)?/^https?:$/.test(new URL(e).protocol):!1}function oo(e,t){if(!to.test(e)||!Q(t))return;let n=no(t.exposure),r=Q(t.toolExposure)?Object.fromEntries(Object.entries(t.toolExposure).map(([e,t])=>[e,no(t)])):t.toolExposure;if(n!==void 0&&!ro(n)||r!==void 0&&(!Q(r)||!Object.values(r).every(e=>ro(e)))||t.enabled!==void 0&&typeof t.enabled!=`boolean`||t.description!==void 0&&typeof t.description!=`string`||t.timeout!==void 0&&(typeof t.timeout!=`number`||!(t.timeout>0))||t.type===`sse`)return;let i={enabled:t.enabled,exposure:n,toolExposure:r},a=t.type;if(typeof t.url==`string`&&(a===void 0||a===`http`||a===`streamable-http`))return!ao(t.url)||t.headers!==void 0&&!io(t.headers)?void 0:i;if(typeof t.command==`string`&&(a===void 0||a===`stdio`))return t.args!==void 0&&!(Array.isArray(t.args)&&t.args.every(e=>typeof e==`string`))||t.env!==void 0&&!io(t.env)||t.cwd!==void 0&&typeof t.cwd!=`string`?void 0:i}function so(e,t){e.error=e.error===void 0?t:`${e.error}; ${t}`}function co(e,t,n,r,i){if(t===void 0){n!==void 0&&so(i,n);return}let a;try{a=JSON.parse(t)}catch(t){so(i,`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`);return}if(!Q(a)||a.mcpServers!==void 0&&!Q(a.mcpServers)){so(i,`${e} must contain a JSON object with an "mcpServers" object`);return}typeof a.autoEnableCodemode==`boolean`?i.autoEnableCodemode=a.autoEnableCodemode:a.autoEnableCodemode!==void 0&&so(i,`${e}: autoEnableCodemode must be a boolean`);for(let[e,t]of Object.entries(a.mcpServers??{})){let n=oo(e,t);if(n===void 0||r===`project`&&Q(t)&&`url`in t&&t.auth)continue;let a=`mcp__${e.replace(/-/g,`_`)}`;[...i.servers.entries()].some(([t,n])=>t!==e&&n.namespace===a)||i.servers.set(e,{namespace:a,server:n})}}function lo(e,t){let n={autoEnableCodemode:void 0,servers:/* @__PURE__ */ new Map,error:void 0};co(e.path,e.raw,e.readError,`global`,n),co(t.path,t.raw,t.readError,`project`,n);let r=[...n.servers.values()].some(({server:e})=>e.enabled!==!1&&(/* @__PURE__ */ new Set([e.exposure??`codemode`,...Object.values(e.toolExposure??{})])).has(`codemode`));return{autoEnablesCodemode:n.autoEnableCodemode!==!1&&r,...n.error===void 0?{}:{error:n.error}}}function uo(e,t){let n=e=>{try{return{path:e,raw:T(e,`utf8`)}}catch(t){return t.code===`ENOENT`?{path:e,raw:void 0}:{path:e,raw:void 0,readError:`${e} could not be read (${t instanceof Error?t.message:String(t)})`}}};return lo(n(j(e,`mcp.json`)),n(j(t,`.pi`,`mcp.json`)))}function fo(e,t){let n=t.error===void 0?e:{...e,mcpError:t.error};return e.activation===`active`||!t.autoEnablesCodemode?n:{...e,activation:`active`,source:`mcp`,...t.error===void 0?{}:{mcpError:t.error}}}function po(e,t,n){return!e.present||t===`disabled`||n!==`active`?`full`:`subagents`}function mo(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=A(n);for(let e of ho){let t=j(r,...e);try{if(te(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const ho=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function go(e,t,n,r,i,a=process.cwd()){let o=n??mo(),s=r??Xa(e,a),c=i??Qa(e,a,t);return{surfaceMode:po(o,s.switch,c.activation),codemode:o,codemodeSwitch:s,codemodeActivation:c}}function _o(e){let t=j(e,Fa),n;try{n=T(t,`utf8`)}catch{return}let r;try{r=JSON.parse(n)}catch{return}if(typeof r!=`object`||!r||Array.isArray(r))return;let i=r.surfaceMode;return i===void 0?void 0:{path:t,value:i}}function vo(e){return[...new Set(e)]}function yo(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 bo(e,t){let n=e=>ja.includes(e);if(t===`all-but-ptc`)return vo(e.filter(n));let r=new Set(V);return vo(e.filter(e=>n(e)||!r.has(e)))}function xo(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:ja.some(e=>r.includes(e))?!i&&Ma.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:vo(r),loadout:bo(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function So(e,t){return e.enabled&&e.base!==void 0?e.base:t}function Co(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!yo(e.ourLoadout,t)}function wo(e,t){let n=t.length>0&&t.every(e=>ja.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function To(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(`
53
+ `;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(_a);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(N(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(ha(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+`: `+ga(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(ha(e))return[];throw e}let n=[];for(let r of t.split(`
54
+ `)){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+`: `+ga(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(M(e),{recursive:!0});let n=e+`.tmp-`+oe();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(ha(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(ha(e))return!1;throw e}}#l(){return N(this.#e,`tasks`)}#u(){return N(this.#e,`subscriptions`)}#d(){return N(this.#e,`events`)}#f(e){return N(this.#l(),e+`.json`)}#p(e,t){return N(this.#u(),e+`-`+t+`.json`)}#m(e,t){return N(this.#d(),e+`-`+t+`.jsonl`)}};function ya(e,t){return new va(e,t)}const ba=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),xa=/* @__PURE__ */ new Set([`running`,`stopping`]),Sa=2**53-1,Ca={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function Y(e){return e instanceof Error?e.message:String(e)}function wa(e){return e===void 0||e.length===0?`<in-memory>`:e}function Ta(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var Ea=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()}},Da=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)}},Oa=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)}},ka=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]}},Aa=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??Ca,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??Ye,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new tt:ya(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new vi:new bi(e));let t=(e.createInitialStorage??(()=>new tt))(),n=Qe(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new pa(t,{now:this.clock,logger:this.#e});this.registry=new Ea(n),this.outputStorage=new Da(new vi),this.pipeline=new Oa(r),this.lifecycle=new ka((e.createLifecycle??(()=>new Pe({logger:this.#e})))()),this.slots=new rt(e.concurrency??z.dispatchConcurrency),this.dispatchDeps={taskRegistry:this.registry,lifecycle:this.lifecycle,slots:this.slots,outputStorage:this.outputStorage,clock:this.clock,logger:this.#e,...e.whyEnabled===void 0?{}:{whyEnabled:e.whyEnabled}},this.registry.onTransition(this.#o)}#o=(e,t)=>{this.#a||ba.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+Y(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 `+wa(e)+` is unavailable: `+Y(n),t),[]}let i=Qe(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new pa(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): `+Y(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:Sa})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+Y(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+`: `+Y(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+`: `+Y(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:Sa})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+Y(e)),t=[]}let n=[];for(let r of t)if(xa.has(r.status)&&Je(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:Ta(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+Y(e))}for(let e of this.lifecycle.liveHandles()){let t=yt(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: `+Y(e))}}};function ja(e={}){return new Aa(e)}const Ma=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function Na(e){return Ma.has(e.status)}function Pa(e,t){if(e.length===0)return``;let n=e.map(La).join(`
55
+ `);return`${`<bg-task-notifications batch-id="${X(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function Fa(e,t=102400){let n=[],r=[],i=0,a=t-za;for(let t of e){let e=Ra(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 Ia(e){let t=Array.from(e);return t.length<=1024?e:t.slice(0,1023).join(``)+`…`}function La(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="${X(t.type)}"`,` task-id="${X(t.taskId)}"`,` subscription-id="${X(t.subscriptionId)}"`,` status="${X(t.status)}"`,` label="${X(n.label)}"`,` agent-name="${X(n.agentName)}"`,` depth="${n.depth}"`,` duration-ms="${n.durationMs??0}"`,` transition-at-ms="${t.transitionAtMs}">`,` <output-bytes>${i}</output-bytes>`];return n.errorMessage!==void 0&&o.push(` <error-message>${X(Ia(n.errorMessage))}</error-message>`),n.reportChannel!==void 0&&o.push(` <report-channel>${X(n.reportChannel)}</report-channel>`),n.outputRef!==void 0&&o.push(` <output-ref>${X(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${X(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
56
+ `)}function X(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
57
+ `,`&#10;`).replaceAll(`\r`,`&#13;`)}function Ra(e){return Buffer.byteLength(La(e),`utf8`)}const za=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),Ba=[`ptc_run_code`,`ptc_workflow`],Va=[`read`,`bash`,`edit`,`write`],Ha=`ptc-mode`,Ua=`ptc-mode`,Wa=`ptc.json`,Ga=`builtins-only`;function Ka(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function qa(e){let t=N(e,Wa),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 Ja(e){let t=N(e,Wa),n;try{n=T(t,`utf8`)}catch{return{whyEnabled:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch{return{whyEnabled:!0,source:`default`}}if(typeof r!=`object`||!r||Array.isArray(r))return{whyEnabled:!0,source:`default`};let i=r.whyEnabled;return i===void 0?{whyEnabled:!0,source:`default`}:typeof i==`boolean`?{whyEnabled:i,source:`file`}:{whyEnabled:!0,source:`invalid`,error:`${t}: "whyEnabled" must be a boolean, received ${typeof i}`}}function Ya(e){let t=N(e,Wa),n;try{n=T(t,`utf8`)}catch{return{optInBindings:[],source:`default`}}let r;try{r=JSON.parse(n)}catch{return{optInBindings:[],source:`default`}}if(typeof r!=`object`||!r||Array.isArray(r))return{optInBindings:[],source:`default`};let i=r.optInBindings;if(i===void 0)return{optInBindings:[],source:`default`};if(!Array.isArray(i))return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" must be an array of binding names, received ${typeof i}`};let a=i.find(e=>typeof e!=`string`);if(a!==void 0)return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" entries must be strings, received ${typeof a}`};try{return{optInBindings:mn(i),source:`file`}}catch(e){return{optInBindings:[],source:`invalid`,error:`${t}: ${e instanceof Error?e.message:String(e)}`}}}const Z=`builtin:codemode`;function Q(e){return e.split(re).join(`/`)}function Xa(e){return e===`~`?k():e.startsWith(`~/`)?N(k(),e.slice(2)):e.startsWith(`file://`)?ue(e):e}function Za(e){return Q(Xa(e.startsWith(`./`)||e.startsWith(`.\\`)?e.slice(2):e))}function Qa(e,t,n){let r=Q(ne(n,e)),i=te(e),a=Q(e);return t.some(e=>{let t=Q(Xa(e));return ye(r,t)||ye(i,t)||ye(a,t)})}function $a(e,t,n){if(t.length===0)return!1;let r=Q(ne(n,e)),i=Q(e);return t.some(e=>{let t=Za(e);return t===r||t===i})}function eo(e){let t=[];for(let n of e){if(typeof n!=`string`)continue;let e=n[0];(e===`+`||e===`-`||e===`!`)&&t.push({sign:e,target:n.slice(1)})}return t}function to(e,t){if(!Array.isArray(e))return;let n;for(let{sign:r,target:i}of eo(e)){let e=r!==`-`&&r!==`!`;(r===`+`||r===`-`?$a(Z,[i],t):Qa(Z,[i],t))&&(n=e?`enabled`:`disabled`)}return n}function no(e,t){if(!Array.isArray(e))return;let n=eo(e),r=e=>n.filter(t=>t.sign===e).map(e=>e.target),i=r(`!`),a=r(`+`),o=r(`-`),s;return Qa(Z,i,t)&&(s=`disabled`),$a(Z,a,t)&&(s=`enabled`),$a(Z,o,t)&&(s=`disabled`),s}function ro(e){for(let t=0;t<e.length;t+=1){let n=e[t];if((n===`-e`||n===`--extension`)&&e[t+1]===Z)return!0}return!1}function io(e){let t;try{t=T(e,`utf8`)}catch{return{value:void 0}}try{let n=JSON.parse(t);return typeof n!=`object`||!n||Array.isArray(n)?{value:void 0,error:`${e} must contain a JSON object`}:{value:n}}catch(t){return{value:void 0,error:`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`}}}function ao(e,t,n,r={project:process.cwd(),user:process.cwd()}){let i=e.slice(1);if(ro(i))return{switch:`enabled`,source:`cli`};if(i.some(e=>e===`-ne`||e===`--no-extensions`))return{switch:`disabled`,source:`cli`};let a=t?.extensions,o=to(a,r.project);if(o!==void 0)return{switch:o,source:`project`};let s=n?.extensions,c=no(s,r.user);return c===void 0?{switch:`absent`,source:`default`}:{switch:c,source:`user`}}function oo(e,t,n=process.argv){let r=io(N(t,`.pi`,`settings.json`)),i=io(N(e,`settings.json`)),a=ao(n,r.value,i.value,{project:N(t,`.pi`),user:e}),o=r.error??i.error;return o===void 0?a:{...a,source:`invalid`,error:o}}function so(e){return{activation:e.includes(`codemode`)?`active`:`inactive`,source:`loadout`}}function co(e,t,n){return So(so(n),xo(e,t))}const lo=[`codemode`,`deferred`,`direct`,`hidden`],uo={"codemode-deferred":`codemode`},fo=/^[A-Za-z0-9_-]+$/;function po(e){return typeof e==`string`?uo[e]??e:e}function mo(e){return typeof e==`string`&&lo.includes(e)}function $(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ho(e){return $(e)&&Object.values(e).every(e=>typeof e==`string`)}function go(e){return URL.canParse(e)?/^https?:$/.test(new URL(e).protocol):!1}function _o(e,t){if(!fo.test(e)||!$(t))return;let n=po(t.exposure),r=$(t.toolExposure)?Object.fromEntries(Object.entries(t.toolExposure).map(([e,t])=>[e,po(t)])):t.toolExposure;if(n!==void 0&&!mo(n)||r!==void 0&&(!$(r)||!Object.values(r).every(e=>mo(e)))||t.enabled!==void 0&&typeof t.enabled!=`boolean`||t.description!==void 0&&typeof t.description!=`string`||t.timeout!==void 0&&(typeof t.timeout!=`number`||!(t.timeout>0))||t.type===`sse`)return;let i={enabled:t.enabled,exposure:n,toolExposure:r},a=t.type;if(typeof t.url==`string`&&(a===void 0||a===`http`||a===`streamable-http`))return!go(t.url)||t.headers!==void 0&&!ho(t.headers)?void 0:i;if(typeof t.command==`string`&&(a===void 0||a===`stdio`))return t.args!==void 0&&!(Array.isArray(t.args)&&t.args.every(e=>typeof e==`string`))||t.env!==void 0&&!ho(t.env)||t.cwd!==void 0&&typeof t.cwd!=`string`?void 0:i}function vo(e,t){e.error=e.error===void 0?t:`${e.error}; ${t}`}function yo(e,t,n,r,i){if(t===void 0){n!==void 0&&vo(i,n);return}let a;try{a=JSON.parse(t)}catch(t){vo(i,`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`);return}if(!$(a)||a.mcpServers!==void 0&&!$(a.mcpServers)){vo(i,`${e} must contain a JSON object with an "mcpServers" object`);return}typeof a.autoEnableCodemode==`boolean`?i.autoEnableCodemode=a.autoEnableCodemode:a.autoEnableCodemode!==void 0&&vo(i,`${e}: autoEnableCodemode must be a boolean`);for(let[e,t]of Object.entries(a.mcpServers??{})){let n=_o(e,t);if(n===void 0||r===`project`&&$(t)&&`url`in t&&t.auth)continue;let a=`mcp__${e.replace(/-/g,`_`)}`;[...i.servers.entries()].some(([t,n])=>t!==e&&n.namespace===a)||i.servers.set(e,{namespace:a,server:n})}}function bo(e,t){let n={autoEnableCodemode:void 0,servers:/* @__PURE__ */ new Map,error:void 0};yo(e.path,e.raw,e.readError,`global`,n),yo(t.path,t.raw,t.readError,`project`,n);let r=[...n.servers.values()].some(({server:e})=>e.enabled!==!1&&(/* @__PURE__ */ new Set([e.exposure??`codemode`,...Object.values(e.toolExposure??{})])).has(`codemode`));return{autoEnablesCodemode:n.autoEnableCodemode!==!1&&r,...n.error===void 0?{}:{error:n.error}}}function xo(e,t){let n=e=>{try{return{path:e,raw:T(e,`utf8`)}}catch(t){return t.code===`ENOENT`?{path:e,raw:void 0}:{path:e,raw:void 0,readError:`${e} could not be read (${t instanceof Error?t.message:String(t)})`}}};return bo(n(N(e,`mcp.json`)),n(N(t,`.pi`,`mcp.json`)))}function So(e,t){let n=t.error===void 0?e:{...e,mcpError:t.error};return e.activation===`active`||!t.autoEnablesCodemode?n:{...e,activation:`active`,source:`mcp`,...t.error===void 0?{}:{mcpError:t.error}}}function Co(e,t,n){return!e.present||t===`disabled`||n!==`active`?`full`:`subagents`}function wo(e=process.argv){let t=e[1];if(t===void 0||t===``)return{present:!1,how:`no-entry`};let n;try{n=E(t)}catch{return{present:!1,how:`unresolvable-entry`}}let r=M(n);for(let e of To){let t=N(r,...e);try{if(D(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const To=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function Eo(e,t,n,r,i,a=process.cwd()){let o=n??wo(),s=r??oo(e,a),c=i??co(e,a,t);return{surfaceMode:Co(o,s.switch,c.activation),codemode:o,codemodeSwitch:s,codemodeActivation:c}}function Do(e){let t=N(e,Wa),n;try{n=T(t,`utf8`)}catch{return}let r;try{r=JSON.parse(n)}catch{return}if(typeof r!=`object`||!r||Array.isArray(r))return;let i=r.surfaceMode;return i===void 0?void 0:{path:t,value:i}}function Oo(e){return[...new Set(e)]}function ko(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 Ao(e,t){let n=e=>Ba.includes(e);if(t===`all-but-ptc`)return Oo(e.filter(n));let r=new Set(V);return Oo(e.filter(e=>n(e)||!r.has(e)))}function jo(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:Ba.some(e=>r.includes(e))?!i&&Va.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:Oo(r),loadout:Ao(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function Mo(e,t){return e.enabled&&e.base!==void 0?e.base:t}function No(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!ko(e.ourLoadout,t)}function Po(e,t){let n=t.length>0&&t.every(e=>Ba.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function Fo(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(`
53
58
  `);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(`
54
- `)}const Eo=[`read`,`bash`],Do=`Use the read tool to load a skill's file when the task matches its description.`,Oo=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function ko(e){return!Eo.some(t=>e.includes(t))}function Ao(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Do)?n.replace(Do,Oo):`${Oo}\n\n${n}`}const jo=x.Object({task_id:x.Optional(x.String({description:`Id of the background task to poll with ptc_task_output. Present ONLY for a background call; absent once the call has already finished.`})),status:x.String({description:`"background" when this call returned a handle to poll, otherwise the dispatcher's own outcome status ("fulfilled").`}),report_channel:x.String({description:'Which channel delivered the child report: "prompt-json" (a fenced JSON block on the child\'s final message), "tool" (the child called the report tool), "none" (no report arrived — either the child did not comply with the contract, or this is a background handle that has not finished), or "opted-out" (the agent\'s frontmatter set `childReport: false`, so it was never asked). ALWAYS present, so an absent `report` key is never ambiguous — "none" and "opted-out" are different claims about the child.'}),exit_code:x.Optional(x.Number({description:`The child's exit code. Present ONLY for a call that already finished.`})),read_only_tier:x.Optional(x.String({description:`The read-only tier the dispatch resolved to: "strict" or "lenient" (ADR-0041). Absent when no tier was asked for, so an absent key means "no tier" rather than "tier unknown".`})),report:x.Optional(x.Object({summary:x.String({description:`One line, in the child's own words, of what it concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim.`})})),files_touched:x.Array(x.String({description:`A path the child created or modified.`})),usage:x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})},{description:"The host's own count for this child: the same four fields `report.usage` carries, projected from the `DispatchResult.usage` accumulator (ADR-0032, issue #199). ABSENT for a background handle, which has measured nothing yet, and for a child that emitted no usage block. Present on every settled call REGARDLESS of `report_channel`, so a child that reported nothing still accounts for what it cost — the text render states the same four numbers on its `usage` row."}))});function Mo(e){let t=e.taskId;return typeof t==`string`?t:void 0}function No(e){return L({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.`,"`agent` is optional — omit it and the child is a fresh generalist pi, with pi's own system prompt and pi's full toolset. Name one to narrow the child instead: an agent is a markdown file in ~/.pi/agent/agents/ for your machine, or <project>/.pi/agents/ for one project, and naming one can restrict the child's tools, pin its model, or append a role. A name with no definition behind it is refused; the refusal lists what IS registered and how to write one.",Lt({cwd:e.cwd,agentScope:e.agentRosterScope??`both`,...e.homeDir===void 0?{}:{homeDir:e.homeDir}})].join(`
55
- `),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:mn,outputSchema:jo,async execute(t,n){let r=await cn(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=Mo(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){let e=z(n.readOnly),t={task_id:i,status:a.status,report_channel:`none`,...e===void 0?{}:{read_only_tier:e}};return{content:[{type:`text`,text:[`Started background task `+i,ur(e)].filter(e=>e.length>0).join(`
59
+ `)}const Io=[`read`,`bash`],Lo=`Use the read tool to load a skill's file when the task matches its description.`,Ro=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function zo(e){return!Io.some(t=>e.includes(t))}function Bo(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Lo)?n.replace(Lo,Ro):`${Ro}\n\n${n}`}const Vo=x.Object({task_id:x.Optional(x.String({description:`Id of the background task to poll with ptc_task_output. Present ONLY for a background call; absent once the call has already finished.`})),status:x.String({description:`"background" when this call returned a handle to poll, otherwise the dispatcher's own outcome status ("fulfilled").`}),report_channel:x.String({description:'Which channel delivered the child report: "prompt-json" (a fenced JSON block on the child\'s final message), "tool" (the child called the report tool), "none" (no report arrived — either the child did not comply with the contract, or this is a background handle that has not finished), or "opted-out" (the agent\'s frontmatter set `childReport: false`, so it was never asked). ALWAYS present, so an absent `report` key is never ambiguous — "none" and "opted-out" are different claims about the child.'}),exit_code:x.Optional(x.Number({description:`The child's exit code. Present ONLY for a call that already finished.`})),read_only_tier:x.Optional(x.String({description:`The read-only tier the dispatch resolved to: "strict" or "lenient" (ADR-0041). Absent when no tier was asked for, so an absent key means "no tier" rather than "tier unknown".`})),why_suppressed:x.Optional(x.Boolean({description:"`true` when you passed a `why` and this session's `whyEnabled` switch was off, so the child's prompt carried no <pi-ptc-why> block (ADR-0043). ABSENT means no `why` was passed — that is the distinction the key exists to make. The child was never told your reason; it did not ignore one. A background call returns a handle and does not carry this key; read it from `ptc_task_output` instead."})),report:x.Optional(x.Object({summary:x.String({description:`One line, in the child's own words, of what it concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim.`})})),files_touched:x.Array(x.String({description:`A path the child created or modified.`})),usage:x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})},{description:"The host's own count for this child: the same four fields `report.usage` carries, projected from the `DispatchResult.usage` accumulator (ADR-0032, issue #199). ABSENT for a background handle, which has measured nothing yet, and for a child that emitted no usage block. Present on every settled call REGARDLESS of `report_channel`, so a child that reported nothing still accounts for what it cost — the text render states the same four numbers on its `usage` row."}))});function Ho(e){let t=e.taskId;return typeof t==`string`?t:void 0}function Uo(e){return R({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.`,"`agent` is optional — omit it and the child is a fresh generalist pi, with pi's own system prompt and pi's full toolset. Name one to narrow the child instead: an agent is a markdown file in ~/.pi/agent/agents/ for your machine, or <project>/.pi/agents/ for one project, and naming one can restrict the child's tools, pin its model, or append a role. A name with no definition behind it is refused; the refusal lists what IS registered and how to write one.",Bt({cwd:e.cwd,agentScope:e.agentRosterScope??`both`,...e.homeDir===void 0?{}:{homeDir:e.homeDir}})].join(`
60
+ `),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:_n,outputSchema:Vo,async execute(t,n){let r=await dn(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=Ho(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){let e=B(n.readOnly),t={task_id:i,status:a.status,report_channel:`none`,...e===void 0?{}:{read_only_tier:e}};return{content:[{type:`text`,text:[`Started background task `+i,pr(e)].filter(e=>e.length>0).join(`
56
61
 
57
- `)}],details:a,structuredContent:t}}if(r.status===`rejected`)throw Error(`ptc_subagent refused the call: `+r.errorMessage);let o=r.report,s=r.readOnlyTier===void 0?{}:{read_only_tier:r.readOnlyTier},c=r.usage===void 0?{}:{usage:{input:r.usage.input,output:r.usage.output,cost:r.usage.cost,turns:r.usage.turns}},l=a.exitCode===void 0?{status:a.status,report_channel:r.reportChannel,...s,...c}:o===void 0?{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel,...s,...c}:{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel,report:o,...s,...c},u=qr(o,r.reportChannel,r.usage);return{content:[{type:`text`,text:[ur(r.readOnlyTier),u,r.text].filter(e=>e.length>0).join(`
62
+ `)}],details:a,structuredContent:t}}if(r.status===`rejected`)throw Error(`ptc_subagent refused the call: `+r.errorMessage);let o=r.report,s=r.readOnlyTier===void 0?{}:{read_only_tier:r.readOnlyTier},c=r.whySuppressed===void 0?{}:{why_suppressed:r.whySuppressed},l=r.usage===void 0?{}:{usage:{input:r.usage.input,output:r.usage.output,cost:r.usage.cost,turns:r.usage.turns}},u=a.exitCode===void 0?{status:a.status,report_channel:r.reportChannel,...s,...c,...l}:o===void 0?{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel,...s,...c,...l}:{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel,report:o,...s,...c,...l},d=Zr(o,r.reportChannel,r.usage);return{content:[{type:`text`,text:[pr(r.readOnlyTier),Si(r.whySuppressed),d,r.text].filter(e=>e.length>0).join(`
58
63
 
59
- `)}],details:a,structuredContent:l}}})}function Po(e){return e.length<=200?e:`…`+e.slice(-199)}const Fo=x.Object({summary:x.String({description:`One line, in your own words, of what you concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim — what you read, ran or checked. Not the claim restated.`})})),files_touched:x.Array(x.String({description:`A path you created or modified. Empty if you touched nothing.`}))}),Io=[`Hand the host a child report: what you did in this run, in the shape it can read without parsing English.`,`Call it once, at the end. The exact shape is stated in your instructions, which also tell you what to do if this tool is unavailable to you.`,`Evidence is the point of a finding. Put in the independent thing you read, ran or checked — the claim restated is not evidence, and a finding with none is worse than no finding.`,`files_touched lists only paths you actually created or modified; leave it empty rather than guessing.`,`Your prose answer is kept alongside this report and is never replaced by it, so still answer in words.`,`Do not report usage or token counts — those are measured by the host, and anything you send under them is discarded.`].join(`
60
- `);function Lo(e){return L({name:Ie,label:`Child Report`,description:Io,promptSnippet:`Hand the host a child report when you finish`,promptGuidelines:[`Call ptc_child_report once before you finish, even when the answer is "I changed nothing": a child that reports an empty result is a different thing from a child that never reported, and only the first one says so.`],parameters:Fo,outputSchema:Fo,defaultActive:e,renderCall(e,t){let n=e,r=typeof n?.summary==`string`?n.summary:``;return new q([{left:t.fg(`toolTitle`,t.bold(`Child report`))+(r===``?``:` `+t.fg(`dim`,Po(r)))}])},renderResult(){return new q([{left:`child report recorded`}])},async execute(e,t){let n={summary:t.summary,findings:t.findings.map(e=>({what:e.what,evidence:e.evidence})),files_touched:[...t.files_touched]};return{content:[{type:`text`,text:`child report recorded (`+String(n.findings.length)+` findings)`}],details:void 0,structuredContent:n}}})}const $=Ia;function Ro(e,t,n){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: ${er(e,n).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
61
- `)}function zo(e,t={}){let n=La(),r,i=!1,a=new ra,o=()=>So(n,e.getActiveTools()),s=za(y()),c=s.optInBindings,l=()=>c,u=Qn(),d=$n(),f=t.backgroundRuntime??Ca({concurrency:ze({}).dispatchConcurrency}),p=!1,m=e=>{console.warn(`[pi-ptc.background] `+e)},h=t=>{if(t.length!==0){if(p){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},g=async e=>{let{items:t,acks:n}=await f.drainNotifications(e),r=t.filter(e=>Ta(e.record));for(let e of Da(r))h(Ea(e,{batchId:De(),deliveredAtMs:f.clock()}));await f.acknowledgeNotifications(n)},_=async()=>{let e=await f.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]},v=async()=>{for(let e of await _())await g(e)},b=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 g(e)};f.pipeline.onIdleWake(e=>{g(e).catch(e=>{m(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})});function x(t){if(t.surfaceMode===`full`||t.surfaceMode===`subagents`){let n=t.surfaceMode===`full`?`direct`:`codemode`;e.registerTool(oi({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`run_code`),depth:u,exposure:n,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps})),e.registerTool(fi({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`workflow`),depth:u,exposure:n,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps}))}t.surfaceMode===`subagents`&&e.registerTool(No({cwd:process.cwd(),depth:u,maxDispatchDepth:R.maxDispatchDepth,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps})),e.registerTool(Gi(f.registry)),e.registerTool($i(f.registry,f.outputStorage)),e.registerTool(na(f.registry,f.lifecycle,{clock:f.clock})),e.registerTool(Lo(u>0))}let S=!1,C=t=>{S||r.codemodeActivation.activation===`inactive`&&e.getActiveTools().includes(`codemode`)&&(S=!0,t.ui.notify(`pi-ptc-subagents: pi's codemode is active in this session, but nothing this package reads predicted it — no tool list names it and no readable mcp.json auto-enables it — so the surface defaulted to full, and your model is being offered two orchestration tools. pi activates codemode at runtime in ways no settings file records (its MCP extension is one). Run pi with codemode active (-t codemode, or add it to defaultTools) to get the subagents surface instead.`,`warning`))};e.on(`turn_start`,async(e,t)=>{p=!0,C(t)}),e.on(`agent_settled`,async()=>{p=!1;try{await v()}catch(e){m(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new ra,await e.drain()});let w=e=>{let t=[];n.enabled&&t.push(e.ui.theme.fg(`accent`,`PTC`)),e.ui.setStatus(Pa,t.length>0?t.join(` `):void 0)},T=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Na,{enabled:!0,base:[...t]}),w(a),a.ui.notify(o,`info`)},ee=(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}),w(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},te=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`,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}ee(r,{announce:!0,customType:Na});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${er(n.base,c).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=xo({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}T(a.base,a.loadout,r,Ro(a.base,$,c))}}),e.on(`session_start`,async(n,i)=>{r=go(y(),e.getActiveTools(),t.codemode,t.codemodeSwitch,t.codemodeActivation),x(r),p=!1;let a=await f.bindSession(i.sessionManager?.getSessionDir?.(),e=>i.ui.notify(e,`warning`));try{await b(a)}catch(e){m(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let o=Ra(y());o.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${o.error}`,`warning`),s.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${s.error}. No opt-in binding was granted, so the PTC surface stays narrowed. Opt-in bindings: ${ln.join(`, `)}.`,`warning`);let l=_o(y());l!==void 0&&i.ui.notify(`pi-ptc-subagents: `+l.path+` still has a "surfaceMode" key (`+JSON.stringify(l.value)+"), and it is no longer read: the surface is detected from what pi is, and no key pins it. To keep this package out of your sessions entirely, turn it off in pi -- run `pi config` and disable this package's extensions there (its `extensions` entry set to [] stops pi loading it at all). To silence this notice, delete the key.",`warning`);let u=r.codemode;u.present||i.ui.notify(`pi-ptc-subagents: the codemode probe reported `+u.how+`, so the surface is full. That is the safe direction, not an error.`,`info`),r.codemodeSwitch?.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.codemodeActivation?.mcpError!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeActivation.mcpError}`,`warning`);{let t=e.getAllTools().some(e=>e.name===`codemode`);!u.present&&t&&i.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+u.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Enable codemode for real (-t codemode) to get the subagents surface instead.`,`warning`),u.present&&!t&&i.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions), so the surface is `+JSON.stringify(r.surfaceMode)+(r.surfaceMode===`subagents`?` with no orchestrator: ptc_run_code and ptc_workflow are reachable only from codemode, and this session has none. Launch with codemode active (pi -t codemode), or turn this package off with pi config.`:`.`),`warning`)}if(r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)){let t=e.getActiveTools();t.includes(`ptc_run_code`)||t.includes(`ptc_workflow`)||i.ui.notify(`pi-ptc-subagents: the detected surface 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 turn this package off with pi config.`,`warning`)}C(i);let d=te(i),{base:h,restoreFirst:g}=wo(d,e.getActiveTools());g&&e.setActiveTools([...h]);let _=xo({mode:i.mode,defaultMode:o.defaultMode,active:h,manual:!1,hide:$}),v=d?.enabled??_.enter;if(_.enter&&v){T(h,_.loadout,i,Ro(h,$,c));return}w(i),!_.enter&&_.reason!==`not-tui`&&d===void 0&&_.reason===`restricted-session`&&i.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{p=!1;try{await f.shutdown(`session_ended_while_running`)}catch(e){m(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let ne=!1,E=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){ne&&=(delete e.sections.skills,!1);return}let r=Ao(e.skills);r.length!==0&&(e.sections.skills=r,ne=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(E(a,ko(e.getActiveTools())),n.enabled){if(Co(n,e.getActiveTools())){ee(r,{announce:!1,customType:Na}),E(a,ko(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:To(er(n.base,c),$),display:!1}}}})}export{V as BUILTIN_BINDING_NAMES,fn as DEFAULT_BINDING_NAMES,R as DEFAULT_CONFIG,Ia as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,Bn as MAX_LINE_CHARS,Ma as MODE_REQUIRED_TOOL_NAMES,ln as OPT_IN_BINDING_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Fa as PTC_MODE_CONFIG_FILE,Na as PTC_MODE_ENTRY_TYPE,Pa as PTC_MODE_STATUS_KEY,ja as PTC_MODE_TOOL_NAMES,Oo as PTC_SKILL_LOAD_INSTRUCTION,Eo as SKILL_READING_TOOL_NAMES,ra as TurnPools,Le as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Cn as WorkerPool,So as bindingSource,To as buildModeInstruction,Ao as buildPtcSkillsSection,vn as createBuiltinBindings,Re as createWorkerEnv,xo as decideModeEntry,zo as default,Co as detectExternalLoadoutChange,go as detectSurfaceMode,po as detectedSurfaceMode,Be as effectiveTimeoutMs,La as initialModeState,un as isOptInBindingName,bo as modeLoadout,mo as probeCodemodePresence,Xa as readCodemodeSwitch,Ra as readDefaultModeConfig,_o as readLegacySurfaceKey,za as readOptInBindingsConfig,Zn as renderModelValue,wo as resolveBaseOnStart,Za as resolveCodemodeActivation,Ya as resolveCodemodeSwitch,ze as resolveConfig,dn as resolveOptInBindingNames,Mn as runPtcProgram,yo as sameToolSet,W as sanitizeText,ko as skillsSectionDropped,Hn as stripAnsi};
64
+ `)}],details:a,structuredContent:u}},renderCall(e,t,n){return $r(e,t,{...n?.invalidate===void 0?{}:{requestInvalidate:n.invalidate},...n?.isPartial===void 0?{}:{isPartial:n.isPartial},...n?.state===void 0?{}:{state:n.state},...n?.expanded===!0?{expanded:!0}:{}})}})}function Wo(e){return e.length<=200?e:`…`+e.slice(-199)}const Go=x.Object({summary:x.String({description:`One line, in your own words, of what you concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim — what you read, ran or checked. Not the claim restated.`})})),files_touched:x.Array(x.String({description:`A path you created or modified. Empty if you touched nothing.`}))}),Ko=[`Hand the host a child report: what you did in this run, in the shape it can read without parsing English.`,`Call it once, at the end. The exact shape is stated in your instructions, which also tell you what to do if this tool is unavailable to you.`,`Evidence is the point of a finding. Put in the independent thing you read, ran or checked — the claim restated is not evidence, and a finding with none is worse than no finding.`,`files_touched lists only paths you actually created or modified; leave it empty rather than guessing.`,`Your prose answer is kept alongside this report and is never replaced by it, so still answer in words.`,`Do not report usage or token counts — those are measured by the host, and anything you send under them is discarded.`].join(`
65
+ `);function qo(e){return R({name:Fe,label:`Child Report`,description:Ko,promptSnippet:`Hand the host a child report when you finish`,promptGuidelines:[`Call ptc_child_report once before you finish, even when the answer is "I changed nothing": a child that reports an empty result is a different thing from a child that never reported, and only the first one says so.`],parameters:Go,outputSchema:Go,defaultActive:e,renderCall(e,t){let n=e,r=typeof n?.summary==`string`?n.summary:``;return new J([{left:t.fg(`toolTitle`,t.bold(`Child report`))+(r===``?``:` `+t.fg(`dim`,Wo(r)))}])},renderResult(){return new J([{left:`child report recorded`}])},async execute(e,t){let n={summary:t.summary,findings:t.findings.map(e=>({what:e.what,evidence:e.evidence})),files_touched:[...t.files_touched]};return{content:[{type:`text`,text:`child report recorded (`+String(n.findings.length)+` findings)`}],details:void 0,structuredContent:n}}})}const Jo=Ga;function Yo(e,t,n){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: ${rr(e,n).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
66
+ `)}function Xo(e,t={}){let n=Ka(),r,i=!1,a=new da,o=()=>Mo(n,e.getActiveTools()),s=Ya(y()),c=s.optInBindings,l=()=>c,u=Ja(y()),d=tr(),f=nr(),p=t.backgroundRuntime??ja({concurrency:Re({}).dispatchConcurrency,whyEnabled:u.whyEnabled}),m=!1,h=e=>{console.warn(`[pi-ptc.background] `+e)},g=t=>{if(t.length!==0){if(m){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},_=async e=>{let{items:t,acks:n}=await p.drainNotifications(e),r=t.filter(e=>Na(e.record));for(let e of Fa(r))g(Pa(e,{batchId:Ee(),deliveredAtMs:p.clock()}));await p.acknowledgeNotifications(n)},v=async()=>{let e=await p.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]},b=async()=>{for(let e of await v())await _(e)},x=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 _(e)};p.pipeline.onIdleWake(e=>{_(e).catch(e=>{h(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})});function S(t){if(t.surfaceMode===`full`||t.surfaceMode===`subagents`){let n=t.surfaceMode===`full`?`direct`:`codemode`;e.registerTool(di({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`run_code`),depth:d,exposure:n,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps})),e.registerTool(_i({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`workflow`),depth:d,exposure:n,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps}))}t.surfaceMode===`subagents`&&e.registerTool(Uo({cwd:process.cwd(),depth:d,maxDispatchDepth:z.maxDispatchDepth,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps})),e.registerTool($i(p.registry)),e.registerTool(sa(p.registry,p.outputStorage)),e.registerTool(ua(p.registry,p.lifecycle,{clock:p.clock})),e.registerTool(qo(d>0))}let C=!1,w=t=>{C||r.codemodeActivation.activation===`inactive`&&e.getActiveTools().includes(`codemode`)&&(C=!0,t.ui.notify(`pi-ptc-subagents: pi's codemode is active in this session, but nothing this package reads predicted it — no tool list names it and no readable mcp.json auto-enables it — so the surface defaulted to full, and your model is being offered two orchestration tools. pi activates codemode at runtime in ways no settings file records (its MCP extension is one). Run pi with codemode active (-t codemode, or add it to defaultTools) to get the subagents surface instead.`,`warning`))};e.on(`turn_start`,async(e,t)=>{m=!0,w(t)}),e.on(`agent_settled`,async()=>{m=!1;try{await b()}catch(e){h(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new da,await e.drain()});let T=e=>{let t=[];n.enabled&&t.push(e.ui.theme.fg(`accent`,`PTC`)),e.ui.setStatus(Ua,t.length>0?t.join(` `):void 0)},E=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Ha,{enabled:!0,base:[...t]}),T(a),a.ui.notify(o,`info`)},D=(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(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},ee=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`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`why`||i.startsWith(`why `))return N(i.slice(4),r);if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}D(r,{announce:!0,customType:Ha});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${rr(n.base,c).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=jo({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:Jo});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}E(a.base,a.loadout,r,Yo(a.base,Jo,c))}}),e.on(`session_start`,async(n,i)=>{r=Eo(y(),e.getActiveTools(),t.codemode,t.codemodeSwitch,t.codemodeActivation),S(r),m=!1;let a=await p.bindSession(i.sessionManager?.getSessionDir?.(),e=>i.ui.notify(e,`warning`));try{await x(a)}catch(e){h(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let o=qa(y());o.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${o.error}`,`warning`),u.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${u.error}. That key was ignored rather than acted on, so it cannot have switched the dispatch \`why\` block off — \`/ptc why\` is what decides that, and \`/ptc why\` on its own reports the value in force and where it came from.`,`warning`),s.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${s.error}. No opt-in binding was granted, so the PTC surface stays narrowed. Opt-in bindings: ${fn.join(`, `)}.`,`warning`);let l=Do(y());l!==void 0&&i.ui.notify(`pi-ptc-subagents: `+l.path+` still has a "surfaceMode" key (`+JSON.stringify(l.value)+"), and it is no longer read: the surface is detected from what pi is, and no key pins it. To keep this package out of your sessions entirely, turn it off in pi -- run `pi config` and disable this package's extensions there (its `extensions` entry set to [] stops pi loading it at all). To silence this notice, delete the key.",`warning`);let d=r.codemode;d.present||i.ui.notify(`pi-ptc-subagents: the codemode probe reported `+d.how+`, so the surface is full. That is the safe direction, not an error.`,`info`),r.codemodeSwitch?.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.codemodeActivation?.mcpError!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeActivation.mcpError}`,`warning`);{let t=e.getAllTools().some(e=>e.name===`codemode`);!d.present&&t&&i.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+d.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Enable codemode for real (-t codemode) to get the subagents surface instead.`,`warning`),d.present&&!t&&i.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions), so the surface is `+JSON.stringify(r.surfaceMode)+(r.surfaceMode===`subagents`?` with no orchestrator: ptc_run_code and ptc_workflow are reachable only from codemode, and this session has none. Launch with codemode active (pi -t codemode), or turn this package off with pi config.`:`.`),`warning`)}if(r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)){let t=e.getActiveTools();t.includes(`ptc_run_code`)||t.includes(`ptc_workflow`)||i.ui.notify(`pi-ptc-subagents: the detected surface 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 turn this package off with pi config.`,`warning`)}w(i);let f=ee(i),{base:g,restoreFirst:_}=Po(f,e.getActiveTools());_&&e.setActiveTools([...g]);let v=jo({mode:i.mode,defaultMode:o.defaultMode,active:g,manual:!1,hide:Jo}),b=f?.enabled??v.enter;if(j(i),v.enter&&b){E(g,v.loadout,i,Yo(g,Jo,c));return}T(i),!v.enter&&v.reason!==`not-tui`&&f===void 0&&v.reason===`restricted-session`&&i.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{m=!1;try{await p.shutdown(`session_ended_while_running`)}catch(e){h(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let O=!1,k=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){O&&=(delete e.sections.skills,!1);return}let r=Bo(e.skills);r.length!==0&&(e.sections.skills=r,O=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(k(a,zo(e.getActiveTools())),n.enabled){if(No(n,e.getActiveTools())){D(r,{announce:!1,customType:Ha}),k(a,zo(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:Fo(rr(n.base,c),Jo),display:!1}}}});let A;function j(e){let t=te(e);t!==void 0&&(A=t.enabled,p.dispatchDeps.whyEnabled=t.enabled)}function te(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-why`)continue;let r=n.data?.enabled;if(typeof r==`boolean`)return{enabled:r}}}function M(e,t){return[`The dispatch \`why\` block is ${e?`ON`:`OFF`}`,t===`session`?`(set by this session)`:`(set by ptc.json)`,e?`-- a dispatched child receives your reason. Run /ptc why off to stop handing it over.`:`-- a dispatched child does not receive your reason. Run /ptc why on to hand it over.`].join(` `)}function N(t,n){let r=t.trim().toLowerCase(),i=A??u.whyEnabled,a=A===void 0?`config`:`session`;if(r===``){n.ui.notify(M(i,a),`info`);return}if(r!==`on`&&r!==`off`){n.ui.notify(`/ptc why takes "on" or "off", or nothing at all to report the current value -- not "${t.trim()}". Nothing changed.`,`warning`);return}let o=r===`on`;if(i===o){n.ui.notify(M(o,a),`info`);return}A=o,p.dispatchDeps.whyEnabled=o,e.appendEntry(Zo,{enabled:o}),n.ui.notify(M(o,`session`),`info`)}}const Zo=`ptc-why`;export{V as BUILTIN_BINDING_NAMES,hn as DEFAULT_BINDING_NAMES,z as DEFAULT_CONFIG,Ga as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,Un as MAX_LINE_CHARS,Va as MODE_REQUIRED_TOOL_NAMES,fn as OPT_IN_BINDING_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Wa as PTC_MODE_CONFIG_FILE,Ha as PTC_MODE_ENTRY_TYPE,Ua as PTC_MODE_STATUS_KEY,Ba as PTC_MODE_TOOL_NAMES,Ro as PTC_SKILL_LOAD_INSTRUCTION,Zo as PTC_WHY_ENTRY_TYPE,Io as SKILL_READING_TOOL_NAMES,da as TurnPools,Ie as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,En as WorkerPool,Mo as bindingSource,Fo as buildModeInstruction,Bo as buildPtcSkillsSection,Sn as createBuiltinBindings,Le as createWorkerEnv,jo as decideModeEntry,Xo as default,No as detectExternalLoadoutChange,Eo as detectSurfaceMode,Co as detectedSurfaceMode,ze as effectiveTimeoutMs,Ka as initialModeState,pn as isOptInBindingName,Ao as modeLoadout,wo as probeCodemodePresence,oo as readCodemodeSwitch,qa as readDefaultModeConfig,Do as readLegacySurfaceKey,Ya as readOptInBindingsConfig,Ja as readWhyEnabledConfig,er as renderModelValue,Po as resolveBaseOnStart,so as resolveCodemodeActivation,ao as resolveCodemodeSwitch,Re as resolveConfig,mn as resolveOptInBindingNames,Fn as runPtcProgram,ko as sameToolSet,G as sanitizeText,zo as skillsSectionDropped,Gn as stripAnsi};
62
67
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ptc-subagents",
3
- "version": "3.3.3",
3
+ "version": "4.0.0",
4
4
  "description": "Programmable tool calling (PTC) and subagent fan-out for pi — the model writes JS/TS programs that call pi's tools, or fans out to a fresh pi subprocess per subagent task",
5
5
  "keywords": [
6
6
  "pi",