pi-ptc-subagents 1.2.1 → 1.3.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
@@ -7,6 +7,84 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.0] - 2026-10-02
11
+
12
+ ### Fixed
13
+
14
+ - **A failing `bash` binding no longer resolves as a success on pi 1.0.0.** pi 1.0.0 added a
15
+ non-throwing failure channel — `AgentToolResult.isError`: "Report a failure without throwing. The
16
+ model sees `content` as an error result, like a thrown error" — and `bash` moved its non-zero exit
17
+ onto it, so `tools.bash({ command: "exit 3" })` inside a PTC program **resolved** where on 0.86.1
18
+ it threw. The binding wrapper forwarded only `{ content, details }`, so `isError` was dropped at
19
+ the boundary and the failure crossed into the program as a successful resolution whose only tell
20
+ was a sentence at the end of its stdout. The binding layer now translates `isError` back into the
21
+ rejection ADR-0024's contract already promises, which is what keeps a failing call from being
22
+ silent.
23
+ - **Disabling pi's `codemode` now brings the PTC surfaces back.** The detected surface asked one
24
+ question — does this pi ship a `codemode` extension directory — and since pi 0.99.0 that is no
25
+ longer the same as the one that matters. A user who put `"extensions": ["-builtin:codemode"]` in
26
+ their settings, or launched with `--no-extensions`, turned the orchestrator off and this package
27
+ kept handing the orchestration to it: `ptc_run_code` and `ptc_workflow` stayed unregistered and
28
+ the session was left with `ptc_subagent` and nothing to compose with. Nothing errored; two tools
29
+ were simply missing.
30
+
31
+ A second probe now reads the **switch** — whether pi will actually load the extension — from the
32
+ same three places pi reads it and in the same order (command line, `<cwd>/.pi/settings.json`,
33
+ `<agentDir>/settings.json`), and the detected default follows both questions:
34
+
35
+ | ships `codemode`? | will load it? | surface |
36
+ | ----------------- | ------------------------------------------- | ----------- |
37
+ | yes | yes (default, or `+builtin:codemode`) | `subagents` |
38
+ | yes | no (`-builtin:codemode`, `--no-extensions`) | `full` |
39
+ | no | — | `full` |
40
+
41
+ An explicit `surfaceMode` still wins; a settings file that cannot be read as a JSON object still
42
+ falls back to the next source rather than half-applying. Two notices are added at session start:
43
+ one naming an unreadable settings file, one reporting that a pinned `surfaceMode` disagrees with
44
+ the table. [ADR-0027](./docs/adr/0027-codemode-switch-decides-surface.md)
45
+
46
+ Verified on a real 1.0.0 install for the three reachable cells, asserting on the registered tool
47
+ set rather than on the resolver: `-builtin:codemode` → `ptc_run_code` + `ptc_workflow`; no switch
48
+ entry → `ptc_subagent`; `+builtin:codemode` → `ptc_subagent`. The fourth cell (no `codemode` on
49
+ disk at all) is not reachable on a machine with 1.0 installed and is covered by unit tests only.
50
+
51
+ ### Added
52
+
53
+ - **The four model-facing tools declare a structured result, so pi's `codemode` can consume them.**
54
+ A script calling a tool used to get back prose: `ptc_subagent` returned
55
+ `"Started background task 01J…"` with the id embedded, and the `ptc_task_*` tools returned
56
+ newline-joined lines to re-parse. `ptc_subagent` is the acute case — it is the only way a
57
+ `subagents`-surface session can start a subagent at all, because pi's QuickJS sandbox has no file
58
+ system, no network and no `child_process`.
59
+
60
+ All four now declare an `outputSchema` and return a matching `structuredContent`, which codemode
61
+ scripts receive instead of the text. The shape is a lean projection rather than a mirror of
62
+ `details`: `ptc_task_list` mirroring `TaskRecord[]` would push ~200 KB of per-record
63
+ `outputPreview` into a sandbox whose purpose is to keep intermediate data away from the model.
64
+ `content` and `details` are byte-identical to before on every path, and the model still sees
65
+ exactly the same text — `structuredContent` is documented as "not sent to the model".
66
+ [ADR-0028](./docs/adr/0028-structured-results-for-codemode.md); usage in
67
+ [Structured results for codemode](./docs/usage/structured-results.md).
68
+
69
+ ### Changed
70
+
71
+ - **The codemode switch now mirrors pi's own matchers instead of approximating them.** Reading the
72
+ `!` bucket by comparing a pattern's literal prefix was the wrong SHAPE of fix: the bucket is a
73
+ continuum (globs, character classes, extglobs, nested negations, backslash escapes, multi-segment
74
+ paths), so every review round found one more member — four costful defects in four rounds, and a
75
+ 412-case sweep of the prefix version still had 24 divergences. A case list cannot be finished.
76
+ `resolveCodemodeSwitch` now calls the same `minimatch` pi does, through the same
77
+ `matchesAnyPattern` / `normalizeExactPattern` helpers and with pi's own `baseDir` per scope, which
78
+ adds one small runtime dependency (`minimatch ^10.2.6`, the version pi itself pins) and **shortens**
79
+ the code. A 192-case sweep of the mirror has zero divergences in either direction, and all eight
80
+ reachable cells agree with a real pi 1.0.0 end to end.
81
+ - **The dev toolchain now compiles against pi 1.0.0** rather than 0.86.1 / 0.87.0, so the type check
82
+ and the whole suite run against the pi this package is actually used with. `peerDependencies`
83
+ already declared `>=0.86.0`; that claim had no evidence behind it until now. Two consequences of
84
+ the bump are fixed in the same change: pi narrowed a tool's fifth `execute` parameter from
85
+ `ExtensionContext` to `ExtensionToolContext` (which adds `tools` and `executeTool`), and the
86
+ `isError` channel above.
87
+
10
88
  ## [1.2.1] - 2026-09-30
11
89
 
12
90
  ### Fixed
package/README.md CHANGED
@@ -214,17 +214,32 @@ surface change needs a new session ([ADR-0025](./docs/adr/0025-extension-surface
214
214
  doing the orchestration; warns at startup when `codemode` is not in the active tool set.
215
215
  - `full` — today's set: `ptc_run_code` / `ptc_workflow` plus the three `ptc_task_*` tools.
216
216
 
217
- **The default is detected, and it is not `full` everywhere.** With no `surfaceMode` key, a pi that
218
- ships its own `codemode` resolves to `subagents` and a pi that does not resolves to `full`
219
- ([ADR-0026](./docs/adr/0026-surface-default-is-detected.md)). Setting the key always wins. A probe
220
- that cannot answer falls back to `full` — the safe direction, since `subagents` as a failure mode
221
- would take away the orchestration tool the session was relying on.
217
+ **The default is detected, and it is not `full` everywhere.** With no `surfaceMode` key, the surface
218
+ follows two questions, not one ([ADR-0026](./docs/adr/0026-surface-default-is-detected.md),
219
+ [ADR-0027](./docs/adr/0027-codemode-switch-decides-surface.md)):
220
+
221
+ | does this pi ship `codemode`? | will pi load it? | surface |
222
+ | ----------------------------- | ---------------------------------------------- | ----------- |
223
+ | yes | yes (default, or `+builtin:codemode`) | `subagents` |
224
+ | yes | no (`-builtin:codemode`, or `--no-extensions`) | `full` |
225
+ | no | — | `full` |
226
+
227
+ Setting the key always wins. A probe that cannot answer falls back to `full` — the safe direction,
228
+ since `subagents` as a failure mode would take away the orchestration tool the session was relying
229
+ on.
222
230
 
223
231
  > Upgrading onto pi 0.99.1 or newer without setting the key moves you to `subagents`. `codemode`
224
232
  > ships **inactive** (`defaultActive: false`), so until you add it to your tool list you get a
225
233
  > subagent front with no orchestrator, and the startup warning says so. If you would rather keep
226
234
  > today's tools, set `{ "surfaceMode": "full" }`.
227
235
 
236
+ > Turning pi's `codemode` **off** — `"extensions": ["-builtin:codemode"]`, or launching with
237
+ > `--no-extensions` — brings the PTC surfaces back on its own. Before ADR-0027 it did not: the
238
+ > detection asked only whether the extension directory exists, so a pi told not to load it still
239
+ > counted as an orchestrator and you got `ptc_subagent` with nothing to compose with. The switch is
240
+ > read from the same three places pi reads it — the command line, `<cwd>/.pi/settings.json`, and
241
+ > `<agentDir>/settings.json` — in the same order.
242
+
228
243
  No file, or a value outside that set, falls back to the detected default and says so at startup
229
244
  rather than half-applying: which tools exist is not something to change on a guess.
230
245
 
@@ -233,9 +248,11 @@ rather than half-applying: which tools exist is not something to change on a gue
233
248
  how the probe came out and which surface the default therefore is — but only when the probe could
234
249
  not answer. A pi that ships `codemode` and is detected as `subagents` is the expected case and says
235
250
  nothing. A second notice is issued when the probe and pi's own tool registry disagree, which is the
236
- case the probe structurally cannot see: it walks the filesystem, so under `--no-extensions` or
237
- `--exclude-tools codemode` it answers `present` for a tool this session does not have (and the
238
- mirror: a restructured `dist` answers `not-found` for one pi plainly registers). What is **not**
251
+ case the probe structurally cannot see: it walks the filesystem, so under `--exclude-tools codemode`
252
+ it answers `present` for a tool this session does not have (and the mirror: a restructured `dist`
253
+ answers `not-found` for one pi plainly registers). A third notice covers ADR-0027: a settings file
254
+ that could not be read, and an explicit `surfaceMode` that disagrees with the table — the pinned
255
+ value still wins, and the notice only says so. What is **not**
239
256
  established is that either line actually paints in a real pi TUI: a pty capture at review time
240
257
  showed neither the notice nor a control marker, and a TUI quits on stdin EOF before a toast
241
258
  renders, so that is an unmeasured end to end rather than a broken one. No test in this repository
@@ -251,11 +268,12 @@ one line of JSON: set `surfaceMode` yourself and the detection no longer matters
251
268
  **Where it does not run.** Print / JSON / RPC sessions are left exactly as launched, and so is a
252
269
  session started with an explicit tool restriction (`--tools`, `--exclude-tools`,
253
270
  `--no-builtin-tools`, `--no-extensions`) — the extension does not override what you asked for.
254
- `--no-extensions` is the one flag in that list that produces a `subagents` surface with **no
255
- orchestrator at all**: pi's own `codemode` is a built-in extension, so turning extensions off does
256
- not remove the probe's answer (`present`), and the model is left with `ptc_subagent` and nothing to
257
- compose with. If that is the session you want, set `"surfaceMode": "full"` in `ptc.json` yourself.
258
- If another extension changes the tool set while the mode is on, the mode yields and tells you.
271
+ `--no-extensions` does, however, change the **detected surface**: pi's own `codemode` is a built-in
272
+ extension, so turning extensions off means it will not load, and ADR-0027's table resolves the
273
+ default to `full` — you keep `ptc_run_code` / `ptc_workflow` rather than a `ptc_subagent` with
274
+ nothing to compose with. If you would rather pin the surface regardless, set `"surfaceMode"` in
275
+ `ptc.json`. If another extension changes the tool set while the mode is on, the mode yields and
276
+ tells you.
259
277
 
260
278
  **The important consequence:** in a TUI session, bindings come from the loadout recorded _before_
261
279
  the mode narrowed it. That is what keeps `tools.read(…)` working — and it is why a `--tools`
package/dist/index.d.ts CHANGED
@@ -558,6 +558,82 @@ export declare function readDefaultModeConfig(agentDir: string): DefaultModeConf
558
558
  */
559
559
  declare const SURFACE_MODES: readonly ["off", "subagents", "full"];
560
560
  type SurfaceMode = (typeof SURFACE_MODES)[number];
561
+ /**
562
+ * Whether the pi that launched us will actually LOAD its `codemode` extension.
563
+ *
564
+ * - `"absent"` — nothing in any settings file names it, so pi's own default applies, which is to
565
+ * load it (`settings.md`: "They load by default").
566
+ * - `"enabled"` — an explicit `+builtin:codemode`, or `-e builtin:codemode` on the command line.
567
+ * - `"disabled"` — `-builtin:codemode` or `!builtin:codemode` in a settings file, or `--no-extensions`.
568
+ *
569
+ * This is a different question from {@link CodemodePresence}, which asks whether the directory is
570
+ * on disk. Both are needed, and conflating them is what ADR-0027 fixes: pi 0.99.0 added
571
+ * `-builtin:<name>`, so "the directory exists" and "codemode will run" stopped being the same
572
+ * answer, and a probe that only asks the first one hands orchestration to a tool that is not there.
573
+ */
574
+ type CodemodeSwitch = "absent" | "enabled" | "disabled";
575
+ /** How the switch was decided, so a test can tell a measured answer from a failed read. */
576
+ type CodemodeSwitchSource = "cli" | "project" | "user" | "default" | "invalid";
577
+ /** The switch plus enough provenance to explain it in a notice. */
578
+ interface CodemodeSwitchResolution {
579
+ switch: CodemodeSwitch;
580
+ source: CodemodeSwitchSource;
581
+ /** Set when a settings file could not be read as a JSON object; the switch still resolves. */
582
+ error?: string;
583
+ }
584
+ /**
585
+ * The two directories pi resolves the `!` bucket's globs against.
586
+ *
587
+ * `matchesAnyPattern` also tests `relative(baseDir, path)` and the basename, so a glob whose
588
+ * answer depends on where pi's directories sit is only correct for the directories pi actually
589
+ * used. These are the two it uses: `join(cwd, CONFIG_DIR_NAME)` for project scope -- pi 1.0.0's
590
+ * `CONFIG_DIR_NAME` is `".pi"`, `package-manager.js:720` -- and `agentDir` for user scope (`:719`).
591
+ */
592
+ interface CodemodeBaseDirs {
593
+ project: string;
594
+ user: string;
595
+ }
596
+ export declare function resolveCodemodeSwitch(argv: readonly string[], projectSettings: unknown, userSettings: unknown, baseDirs?: CodemodeBaseDirs): CodemodeSwitchResolution;
597
+ /**
598
+ * Read pi's own settings files and resolve the switch.
599
+ *
600
+ * Project settings live at `<cwd>/.pi/settings.json` and user settings at
601
+ * `<agentDir>/settings.json` — the two `DefaultPackageManager` reads, via
602
+ * `join(this.cwd, CONFIG_DIR_NAME)` and `this.agentDir`.
603
+ */
604
+ export declare function readCodemodeSwitch(agentDir: string, cwd: string, argv?: readonly string[]): CodemodeSwitchResolution;
605
+ /**
606
+ * Whether an explicit `surfaceMode` disagrees with what the table above decided.
607
+ *
608
+ * The explicit key always WINS — that is what an override is for — so this exists only to be
609
+ * reported. `off` is exempt: it means "I do not want this package's surface at all", which is a
610
+ * statement about the package rather than a claim about who orchestrates, and warning about it on
611
+ * every session would be crying wolf.
612
+ */
613
+ export declare function surfaceModeConflict(explicit: SurfaceMode | undefined, detected: SurfaceMode): boolean;
614
+ /**
615
+ * Whether the pi that launched us ships its own `codemode` orchestration tool.
616
+ *
617
+ * pi's own tool listing is NOT usable here, and that is why this probe exists at all.
618
+ * `getAllTools()` and `getActiveTools()` are `notInitialized` stubs until `bindCore` runs
619
+ * (`loader.js:106-108`), which happens after every factory body has returned. Calling one from
620
+ * a factory throws, and `initializeExtension` catches that throw while `loadExtension` answers
621
+ * `{ extension: null, error }` (`loader.js:493-520`) -- a throwing factory makes the extension
622
+ * fail to load entirely, not degrade to an empty tool list. Registration has to happen in the
623
+ * factory, so the default has to be knowable there.
624
+ *
625
+ * Those line numbers are pi **0.99.1**'s `dist/core/extensions/loader.js`, read from a real
626
+ * install, and that is the version this reasoning is about rather than the one this repo compiles
627
+ * against: the 0.86.1 in `devDependencies` has the same two regions at 106-108 and 445-473.
628
+ *
629
+ * So this walks the filesystem from the entry script instead. `process.argv[1]` is whatever the
630
+ * user typed, which for a package-manager install is a shim, so it is resolved first. The answer
631
+ * is "does this pi ship codemode", NOT "can this session call it": codemode registers with
632
+ * `defaultActive: false`, so it is absent from `getActiveTools()` even when fully present.
633
+ * `session_start` is where the second question gets asked, and where a session handed to an
634
+ * orchestrator that is not there gets told.
635
+ */
636
+ export declare function probeCodemodePresence(argv?: readonly string[]): CodemodePresence;
561
637
  interface CodemodePresence {
562
638
  /** Whether the directory was found. */
563
639
  present: boolean;
@@ -575,6 +651,16 @@ interface SurfaceModeConfig {
575
651
  * {@link readSurfaceModeConfig}), so there is nothing to report.
576
652
  */
577
653
  codemode?: CodemodePresence;
654
+ /**
655
+ * Whether pi will actually load its own codemode (ADR-0027). Absent for the same reason as
656
+ * {@link codemode}: an explicit key short-circuits the probe, so there is nothing to report.
657
+ */
658
+ codemodeSwitch?: CodemodeSwitchResolution;
659
+ /**
660
+ * What the four-case table decided, carried even when an explicit key overrode it — that
661
+ * difference is exactly what {@link surfaceModeConflict} reports on.
662
+ */
663
+ detected?: SurfaceMode;
578
664
  }
579
665
  /**
580
666
  * Read `surfaceMode` from the agent-dir config file.
@@ -585,15 +671,15 @@ interface SurfaceModeConfig {
585
671
  * malformed shape additionally reports `invalid` with a reason. A malformed setting must never
586
672
  * half-apply - which tools exist is not something to change on a guess.
587
673
  *
588
- * The `presence` argument is a parameter rather than a hidden call, so a test can state the pi it
589
- * is reasoning about instead of depending on the machine it runs on. Omit it and the real probe
590
- * answers, but only on a path that actually needs the answer: it is resolved inside the
591
- * fallback branches rather than in a default parameter, because a default parameter is evaluated
592
- * on EVERY call -- including the ones an explicit `surfaceMode` key short-circuits, where the
593
- * user paid a `realpathSync` plus up to three `statSync` to set one line of JSON and get a
594
- * constant.
674
+ * The `presence` and `codemodeSwitch` arguments are parameters rather than hidden calls, so a test
675
+ * can state the pi it is reasoning about instead of depending on the machine it runs on. Omit
676
+ * them and the real probes answer, but only on a path that actually needs the answer: they are
677
+ * resolved inside the fallback branches rather than in a default parameter, because a default
678
+ * parameter is evaluated on EVERY call -- including the ones an explicit `surfaceMode` key
679
+ * short-circuits, where the user paid a `realpathSync` plus up to three `statSync` and two
680
+ * settings reads to set one line of JSON and get a constant.
595
681
  */
596
- export declare function readSurfaceModeConfig(agentDir: string, presence?: CodemodePresence): SurfaceModeConfig;
682
+ export declare function readSurfaceModeConfig(agentDir: string, presence?: CodemodePresence, codemodeSwitch?: CodemodeSwitchResolution, cwd?: string): SurfaceModeConfig;
597
683
  /** Why the mode declined to turn on. Surfaced in the entry notification / debug logs. */
598
684
  type ModeBlockReason = "not-tui" | "config-off" | "tools-unavailable" | "restricted-session";
599
685
  /** Either the loadout to apply, or the reason the mode stayed off. */
@@ -1247,8 +1333,15 @@ export interface PtcSubagentsOptions {
1247
1333
  * which is how the previous version of that test passed for the wrong reason.
1248
1334
  */
1249
1335
  codemode?: CodemodePresence;
1336
+ /**
1337
+ * ADR-0027 test seam: whether pi will actually LOAD its own codemode. Undefined in
1338
+ * production, where `readCodemodeSwitch` reads pi's real settings files. Separate from
1339
+ * `codemode` on purpose — a pi can ship the directory and still be told not to load it,
1340
+ * and that is the case this seam exists to state.
1341
+ */
1342
+ codemodeSwitch?: CodemodeSwitchResolution;
1250
1343
  }
1251
1344
  export default function ptcSubagents(pi: ExtensionAPI, options?: PtcSubagentsOptions): void;
1252
1345
  //#endregion
1253
- export type { Binding, BindingContext, BindingTable, CreateBuiltinBindingsOptions, DefaultModeConfig, ModeBlockReason, ModeEntryDecision, ModeEntryInput, ModeHideStrategy, PersistedModeState, PtcConfig, PtcErrorKind, PtcErrorShape, PtcImage, PtcJsonValue, PtcModeState, PtcRunOutcome, PtcSurface, RunPtcProgramOptions, TurnPoolsOptions, WorkerPoolOptions, WorkerPoolStats, WorkerPoolWorkerOptions };
1346
+ export type { Binding, BindingContext, BindingTable, CodemodePresence, CodemodeSwitch, CodemodeSwitchResolution, CodemodeSwitchSource, CreateBuiltinBindingsOptions, DefaultModeConfig, ModeBlockReason, ModeEntryDecision, ModeEntryInput, ModeHideStrategy, PersistedModeState, PtcConfig, PtcErrorKind, PtcErrorShape, PtcImage, PtcJsonValue, PtcModeState, PtcRunOutcome, PtcSurface, RunPtcProgramOptions, SurfaceModeConfig, TurnPoolsOptions, WorkerPoolOptions, WorkerPoolStats, WorkerPoolWorkerOptions };
1254
1347
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,46 +1,47 @@
1
- import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,realpathSync as ee,statSync as E,writeFileSync as te}from"node:fs";import*as ne from"node:os";import{tmpdir as re}from"node:os";import*as D from"node:path";import{dirname as O,join as k,resolve as A}from"node:path";import{spawn as ie}from"node:child_process";import{randomBytes as ae,randomUUID as j}from"node:crypto";import{ok as M}from"node:assert/strict";import{MessageChannel as oe,Worker as se}from"node:worker_threads";import N from"node:diagnostics_channel";import{fileURLToPath as ce,pathToFileURL as le}from"node:url";import{truncateToWidth as P,visibleWidth as F}from"@earendil-works/pi-tui";import{appendFile as ue,mkdir as de,readFile as fe,readdir as pe,rename as me,unlink as he,writeFile as ge}from"node:fs/promises";const _e=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function ve(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(_e[n%32]??`0`)+t,n=Math.floor(n/32);return t}function ye(e){let t=``,n=0,r=0;for(let i=0;i<e.length&&t.length<16;i++)for(n=n<<8|(e[i]??0),r+=8;r>=5&&t.length<16;)r-=5,t+=_e[n>>>r&31];return t.padEnd(16,`0`)}function be(e){let t=new Uint8Array(e);for(let e=t.length-1;e>=0;e--){if((t[e]??0)<255)return t[e]=(t[e]??0)+1,t;t[e]=0}return t}function xe(e){let t=e.randomBytes??(e=>new Uint8Array(ae(e))),n=-1,r=/* @__PURE__ */ new Uint8Array(10);return{next(){let i=Math.max(0,Math.floor(e.now())),a=i>n?i:n,o=a===n?be(r):t(10);return n=a,r=o,ve(a)+ye(o)}}}const Se=xe({now:()=>Date.now()});function Ce(){return Se.next()}function we(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function Te(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function Ee(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function De(e,t){if(e.exited)return;e.exited=!0,e.exitValue=t;for(let n of e.exitWaiters)n(t);e.exitWaiters=[];let n=e.eventWaiters;e.eventWaiters=[];for(let e of n)e(null);for(let t of e.stderrWaiters)t(e.stderr);e.stderrWaiters=[]}function Oe(e,t){let n=t.sessionDir===void 0?[...e]:e.filter(e=>e!==`--no-session`);return t.sessionDir!==void 0&&(n.push(`--session-dir`,t.sessionDir),t.sessionId!==void 0&&n.push(`--session-id`,t.sessionId),t.sessionName!==void 0&&n.push(`--name`,t.sessionName)),n}const ke={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Ae(e){return e.length<=200?e:e.slice(0,200)+`…`}var je=class{#e;constructor(e={}){this.#e=e.logger??ke}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=Oe(e,t),r=n[0],i=n.slice(1),a=ie(r,i,{cwd:t.cwd,shell:!1,stdio:[`ignore`,`pipe`,`pipe`],env:t.env}),o={proc:a,events:[],eventWaiters:[],exited:!1,exitValue:null,stderrWaiters:[],exitWaiters:[],stderr:``,lineBuffer:``},s={id:Ce(),opaque:o},c=a.stdout;c&&c.on(`data`,e=>{o.lineBuffer+=e.toString(`utf-8`);let t=o.lineBuffer.indexOf(`
2
- `);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=we(e);n?Ee(o,n):e.trim().length>0&&this.#t(s,e),t=o.lineBuffer.indexOf(`
3
- `)}});let l=a.stderr;return l&&l.on(`data`,e=>{o.stderr+=e.toString(`utf-8`)}),a.on(`close`,(e,t)=>{let n=o.lineBuffer.trim();if(n.length>0){let e=we(n);e?Ee(o,e):this.#t(s,n),o.lineBuffer=``}De(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
4
- `,o.exited||De(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Te(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Ae(t))}};const I=Object.freeze({timeoutMs:12e4,maxTimeoutMs:6e5,maxOutputBytes:67108864,maxMessageBytes:134217728,maxPendingCalls:128,maxParallelSubCalls:10,dispatchConcurrency:8,maxDispatchDepth:3,maxItemsPerCall:4096,graceMs:3e3,maxOldGenerationSizeMb:512,maxYoungGenerationSizeMb:64,poolSize:4,poolAcquireTimeoutMs:3e4,drainGraceMs:5e3}),Me=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Ne(e=process.env){let t={};for(let n of Me){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function L(e={}){let t={...I};for(let n of Object.keys(I)){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0)throw TypeError(`invalid PTC config override for ${n}: ${String(r)}`);t[n]=r}}return t}function Pe(e,t=I){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Fe={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ie=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Le=/* @__PURE__ */ new Set([`running`,`stopping`]);function Re(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function ze(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Be(e){return typeof e==`string`&&e.length>0}const Ve=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function He(e){return typeof e==`string`&&Ve.has(e)}function Ue(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function We(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Ge(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ke=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??We,this.#a=xe({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Be(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())Le.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Be(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!ze(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!He(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=(e.outputBytes??0)>0,i=n.status===`stopping`?`canceled`:e.exitCode===0&&r?`succeeded`:`failed`;return this.#v(n,i),this.#m(n,i,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview,errorMessage:Re(n,e,i,r)})}async#p(e,t){let n=await this.#y(e.taskId);if(!Le.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};Ie.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=Fe[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Be(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Ge(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function qe(e,t){return new Ke(e,t)}function Je(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function Ye(e){for(let t=1;t<e.length;t++)if(Je(e[t-1],e[t])>0)return!1;return!0}var Xe=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){M(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){M(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=Ye(t)?[...t]:[...t].sort(Je),i=n.length===0?void 0:n[n.length-1]?.eventId,a=r[0]?.eventId;if(i===void 0||a!==void 0&&i<=a){for(let e of r)n.push(structuredClone(e));this.#r.set(e,n);return}let o=[...n,...r.map(e=>structuredClone(e))];o.sort(Je),this.#r.set(e,o)}async*loadEvents(e,t){if(!this.#a(e))throw Error(`loadEvents: unknown subscriptionId ${e}`);let n=this.#r.get(e)??[],r=0;if(t!==void 0){let e=0,i=n.length;for(;e<i;){let r=e+i>>>1;(n[r]?.eventId??``)<=t?e=r+1:i=r}r=e}for(let e=r;e<n.length;e++)yield structuredClone(n[e])}};const R=new je;var Ze=class{limit;#e;#t=/* @__PURE__ */ new Set;constructor(e){if(!Number.isInteger(e)||e<0)throw TypeError(`DispatchSlotCounter: limit must be a non-negative integer, got ${String(e)}`);this.limit=e,this.#e=0}get active(){return this.#e}tryAcquire(e){return e!==void 0&&this.#t.has(e)||this.#e>=this.limit?!1:(e!==void 0&&this.#t.add(e),this.#e+=1,!0)}release(e){if(e!==void 0){if(!this.#t.delete(e))return;--this.#e;return}this.#e>this.#t.size&&--this.#e}};const Qe=new Ze(I.dispatchConcurrency);let $e;function et(e,t){return e.taskRegistry===void 0?($e??=new Ke(new Xe,{clock:t}),$e):e.taskRegistry}const tt={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}};function nt(e,t,n){let r=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`</pi-ptc-context>`].join(`
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 re from"node:os";import{tmpdir as ie}from"node:os";import*as E from"node:path";import{basename as ae,dirname as oe,join as D,relative as O,resolve as k,sep as A}from"node:path";import{spawn as se}from"node:child_process";import{randomBytes as ce,randomUUID as j}from"node:crypto";import{ok as M}from"node:assert/strict";import{MessageChannel as le,Worker as N}from"node:worker_threads";import P from"node:diagnostics_channel";import{fileURLToPath as ue,pathToFileURL as de}from"node:url";import{truncateToWidth as F,visibleWidth as I}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";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(ce(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=se(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 L=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}),Fe=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Ie(e=process.env){let t={};for(let n of Fe){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function Le(e={}){let t={...L};for(let n of Object.keys(L)){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 Re(e,t=L){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const ze={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Be=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Ve=/* @__PURE__ */ new Set([`running`,`stopping`]);function He(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function Ue(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function We(e){return typeof e==`string`&&e.length>0}const Ge=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function Ke(e){return typeof e==`string`&&Ge.has(e)}function qe(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Je(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 Ye(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Xe=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??Je,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 We(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())Ve.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=We(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(!Ue(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`&&!Ke(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:He(n,e,i,r)})}async#p(e,t){let n=await this.#y(e.taskId);if(!Ve.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};Be.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=ze[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(!We(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:Ye(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 Ze(e,t){return new Xe(e,t)}function Qe(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function $e(e){for(let t=1;t<e.length;t++)if(Qe(e[t-1],e[t])>0)return!1;return!0}var et=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){M(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){M(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=$e(t)?[...t]:[...t].sort(Qe),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(Qe),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 tt=new Pe;var nt=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 rt=new nt(L.dispatchConcurrency);let it;function at(e,t){return e.taskRegistry===void 0?(it??=new Xe(new et,{clock:t}),it):e.taskRegistry}const ot={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}};function st(e,t,n){let r=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`</pi-ptc-context>`].join(`
5
5
  `);return e.length===0?r:e+`
6
6
 
7
- `+r}function rt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch depth limit reached`}}function it(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch concurrency limit reached`}}function z(e,t,n={}){e.kill(t,`SIGTERM`);let r=setTimeout(()=>{n.isDone?.()!==!0&&e.kill(t,`SIGKILL`)},5e3);return n.unref===!0&&r.unref(),()=>clearTimeout(r)}function at(){return{...rt(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function ot(){return{...it(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function st(e){return e.aborted?{status:`rejected`,errorMessage:`dispatch cancelled`}:e.exitCode===0&&e.finalText.length>0?{status:`fulfilled`}:e.exitCode===0?{status:`rejected`,errorMessage:`dispatch produced no final text`}:{status:`rejected`}}function ct(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();if(r.length>=2){let e=r[0],t=r[r.length-1];(e===`"`&&t===`"`||e===`'`&&t===`'`)&&(r=r.slice(1,-1))}return r.length===0?void 0:r}function lt(e,t){let n=e.match(RegExp(`^`+t+`:\\s*(.+)$`,`m`));if(!n)return;let r=(n[1]??``).trim();r.startsWith(`[`)&&r.endsWith(`]`)&&(r=r.slice(1,-1));let i=r.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return i.length===0?void 0:i}function ut(e){let t=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return null;let n=t[1]??``,r=t[2]??``,i=ct(n,`name`);if(!i)return null;let a=ct(n,`description`)??``,o=ct(n,`model`)??``,s=lt(n,`tools`),c={name:i,systemPrompt:r.trim()};return a!==void 0&&(c.description=a),o!==void 0&&(c.model=o),s!==void 0&&(c.tools=s),c}function dt(e,t,n,r){let{userDir:i,projectDir:a}=ft({cwd:t,agentScope:n,homeDir:r?.homeDir}),o=[];(n===`user`||n===`both`)&&o.push({path:D.join(i,e+`.md`),source:`user`}),(n===`project`||n===`both`)&&o.push({path:D.join(a,e+`.md`),source:`project`});for(let t of o){let n;try{n=C.readFileSync(t.path,`utf-8`)}catch{continue}let r=ut(n);if(r&&r.name===e){let e={name:r.name,source:t.source,systemPrompt:r.systemPrompt};return r.model!==void 0&&(e.model=r.model),r.tools!==void 0&&(e.tools=r.tools),e}}return null}function ft(e){let t=e.homeDir??ne.homedir();return{userDir:D.join(t,`.pi`,`agent`,`agents`),projectDir:D.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function pt(e){let t=e?.code;return typeof t==`string`?t:String(e)}function mt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function ht(e,t){let n=D.resolve(e),r=D.resolve(t),i=e=>D.dirname(e),a=n,o=!1;for(let e=0;e<=8;e+=1){try{if(C.statSync(a).isDirectory()){o=!0;break}}catch{}if(a===r)break;let e=i(a);if(e===a)break;a=e}if(o){for(let e=n;e!==a&&e!==i(e);e=i(e))if(gt(e))return!0;return!1}return a===r&&gt(r)}function gt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function _t(e,t,n){let r=pt(n);return r!==`ENOENT`&&r!==`ENOTDIR`||mt(e)?!1:!ht(e,t)}function vt(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=ft(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i});let o=/* @__PURE__ */ new Set;for(let{dir:e,boundary:t}of a){let n;try{n=C.readdirSync(e)}catch(n){if(!_t(e,t,n)){let t=pt(n);console.warn(`pi.dispatch: cannot read agent directory ${e} (${t}); the agents registered there are not listed`)}continue}for(let t of n){if(!t.endsWith(`.md`))continue;let n=t.slice(0,-3),r=D.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`pi.dispatch: cannot read agent file ${r}: ${t}; falling back to the filename`),o.add(n);continue}let a=ut(i)?.name??n;a.length>0&&o.add(a)}}return[...o].sort()}function yt(e){let{userDir:t,projectDir:n}=ft(e),r=vt(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t}/<name>.md (user scope) or ${n}/<name>.md (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body`}function bt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,errorMessage:`agent is required (there is no default agent) — `+yt(e)}}function xt(e){return typeof e!=`string`||e.trim().length===0}function St(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+yt({cwd:n,agentScope:t})}}function Ct(e,t,n){let r=[`--mode`,`json`,`-p`,`--no-session`],i=e.model??t.model;i&&r.push(`--model`,i);let a=e.thinkingLevel??`off`;return r.push(`--thinking`,a),t.tools&&t.tools.length>0&&r.push(`--tools`,t.tools.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let wt=Tt;async function Tt(e,t){let n=await C.promises.mkdtemp(D.join(ne.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=D.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function Et(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Dt(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message.content;if(!Array.isArray(t))return;let n;for(let e of t)e&&e.type===`text`&&typeof e.text==`string`&&(n=e.text);return n}function Ot(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message;if(t.stopReason!==`error`)return;let n=t.errorMessage;return typeof n==`string`&&n.trim().length>0?n.trim():`child reported stopReason: error`}async function kt(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return at();if(xt(e.agent))return bt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`});let i=Ce(),a=n.slots??Qe;if(!a.tryAcquire(i))return ot();let o=n.clock??(()=>Date.now()),s=n.logger??tt,c=e.cwd??t.cwd,l=e.agentScope??`user`,u=n.lifecycle??R,d=t.callerId??`dispatch:`+String(t.callId),f=et(n,o),p=n.outputStorage,m,h;try{let n=dt(e.agent,c,l);if(!n)return a.release(i),St(e.agent,l,c);let g=e.label??e.task.slice(0,64),_=nt(n.systemPrompt,r,t.maxDispatchDepth),v=await wt(n.name,_);h=v;let y=Ct(e,n,v.filePath),b={cwd:c,env:{...process.env,PI_PTC_DEPTH:String(r),PI_PTC_TASK_ID:i},promptFile:v.filePath};t.sessionDir!==void 0&&(b.sessionDir=t.sessionDir,b.sessionId=i,b.sessionName=`bgdispatch:`+i),m=u.spawn([`pi`,...y],b);let x=m,S={kind:`ptc-program`,callerId:d};await f.transition({kind:`spawn`,handle:{taskId:i,label:g,status:`running`},record:{label:g,agentName:n.name,depth:r,startedAt:Math.max(0,Math.floor(o())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:S,parentTaskId:t.parentTaskId}},{clock:o,callerId:d,logger:s});let C=!1,w,T=f.onTransition((e,t)=>{e.id===i&&t.status===`stopping`&&(C||w!==void 0||(w=z(u,x,{isDone:()=>C,unref:!0})))});return(async()=>{let e=``,t;try{for await(let n of u.events(x)){let r=Dt(n);r!==void 0&&(e=r);let i=Ot(n);i!==void 0&&(t=i)}C=!0,w?.();let n=(await u.exit(x)).code??-1,r=Buffer.byteLength(e,`utf8`),a=r<=2048?e:void 0,c;if(p!==void 0)try{await p.writeOutput(i,e),c=p.outputRef(i)}catch(e){let t=e instanceof Error?e.message:String(e);s.warn(`background dispatch output persistence for task `+i+` failed: `+t)}await f.transition({kind:`resolve-exit`,taskId:i,exitCode:n,outputRef:c,outputBytes:r,outputPreview:a,childError:t},{clock:o,callerId:d,logger:s})}catch(t){let n=t instanceof Error?t.message:String(t);s.warn(`background dispatch pump for task `+i+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{T(),w?.(),Et(v),a.release(i)}})(),{taskId:i,label:g,status:`running`}}catch(t){let n=t instanceof Error?t.message:String(t);return m!==void 0&&z(u,m,{unref:!0}),h!==void 0&&Et(h),a.release(i),s.warn(`background dispatch failed for agent `+e.agent+`: `+n),{text:``,status:`rejected`,started:m!==void 0,agentName:e.agent,durationMs:0,exitCode:-1,errorMessage:`background dispatch failed: `+n}}}async function At(e,t,n={}){if(e.background===!0)return await kt(e,t,n);let r=t.depth+1;if(r>t.maxDispatchDepth)return rt();let i=e.cwd??t.cwd,a=e.agentScope??`user`,o=Date.now();if(xt(e.agent))return bt({cwd:i,agentScope:a});let s=n.slots??Qe;if(!s.tryAcquire())return it();let c=dt(e.agent,i,a);if(!c)return s.release(),St(e.agent,a,i,Date.now()-o);let l=nt(c.systemPrompt,r,t.maxDispatchDepth),u,d=n.lifecycle??R,f;try{u=await wt(c.name,l),f=Ct(e,c,u.filePath)}catch(e){throw s.release(),e}return await new Promise(e=>{let a=``,l,p=-1,m=``,h=!1,g,_,v=!1,y=(r,i,f=!0)=>{if(h)return;h=!0,s.release(),_!==void 0&&d.exit(_).catch(e=>{(n.logger??tt).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),g?.(),t.signal&&t.signal.removeEventListener(`abort`,b),Et(u);let v={text:a,status:r,started:f,agentName:c.name,durationMs:Date.now()-o,exitCode:p};l&&(v.usage=l),m.length>0&&(v.stderr=m),i&&(v.errorMessage=i),e(v)},b=()=>{_&&!h&&(v=!0,g=z(d,_,{isDone:()=>h}))};try{_=d.spawn([`pi`,...f],{cwd:i,env:{...process.env,PI_PTC_DEPTH:String(r)},promptFile:u.filePath})}catch(e){y(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?b():t.signal.addEventListener(`abort`,b,{once:!0})),(async()=>{if(!_)return;let e=_;try{for await(let t of d.events(e))if(t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(e.usage){let t=l??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};t.input+=e.usage.input??0,t.output+=e.usage.output??0,t.cacheRead+=e.usage.cacheRead??0,t.cacheWrite+=e.usage.cacheWrite??0,t.cost+=e.usage.cost?.total??0,t.turns+=1,l=t}if(Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(a=t.text)}let t=await R.exit(e);p=t.code??-1,m=await R.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){y(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:r,errorMessage:i}=st({exitCode:p,finalText:a,aborted:v});y(r,i)}catch(e){let t=e instanceof Error?e.message:String(e);y(`rejected`,`dispatch internal error: `+t)}})()})}const B=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],V=`pi.dispatch`,jt=B,Mt={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},Nt=x.Object({agent:x.String({minLength:1}),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)])),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String())}),Pt={name:V,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:Nt};function Ft(e){let t=e.names??jt,n=e.includeDispatch??e.names===void 0,r=/* @__PURE__ */ new Map;for(let n of t){let t=Mt[n];if(!t)throw TypeError(`unknown PTC binding "${n}"; known bindings: ${B.join(`, `)}`);let i=t(e.cwd);r.set(n,{name:n,execute:async(e,t)=>{let n=`ptc:${t.callId}`,r={type:`toolCall`,id:n,name:i.name,arguments:e},a=S(i,r),o=await i.execute(n,a,t.signal,void 0);return{content:o.content,details:o.details===void 0?null:o.details}}})}return n&&r.set(V,{name:V,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:V,arguments:t},i;try{i=S(Pt,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return xt(i)?bt({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}):{text:``,status:`rejected`,started:!1,agentName:i,durationMs:0,exitCode:1,errorMessage:n instanceof Error?n.message:String(n)}}return At(i,{signal:n.signal,callId:n.callId,cwd:e.cwd,depth:n.depth,maxDispatchDepth:n.maxDispatchDepth,...n.callerId===void 0?{}:{callerId:n.callerId},...n.sessionDir===void 0?{}:{sessionDir:n.sessionDir},...n.parentTaskId===void 0?{}:{parentTaskId:n.parentTaskId}},n.dispatchDeps)}}),r}function It(){let e=/* @__PURE__ */ new Map;return{recordStart(t,n,r){if(e.has(t))throw Error(`duplicate sub-call callId ${t}`);e.set(t,{callId:t,name:n,args:r,status:`running`,startMs:Date.now()})},recordEnd(t,n,r){let i=e.get(t);if(i===void 0)throw Error(`recordEnd on unknown callId ${t}`);return i.status=n,i.endMs=Date.now(),i.durationMs=i.endMs-i.startMs,n===`rejected`&&(i.durationMs=0),r?.errorMessage!==void 0&&(i.errorMessage=r.errorMessage),r?.resultSummary!==void 0&&(i.resultSummary=r.resultSummary),i},snapshot(){return[...e.values()].map(e=>({...e}))}}}function Lt(e){return{name:`ptc-${e.surface}`,env:e.env,workerData:e.runId===void 0?{env:e.env}:{runId:e.runId,env:e.env},resourceLimits:{maxOldGenerationSizeMb:e.limits.maxOldGenerationSizeMb,maxYoungGenerationSizeMb:e.limits.maxYoungGenerationSizeMb}}}const H={acquireLatency:N.channel(`ptc:pool:acquire-latency`),resetTime:N.channel(`ptc:worker:reset-time`),imageBytes:N.channel(`ptc:image:hoist-bytes`)};function U(e,t){e.publish(t)}var Rt=class{#e;#t;#n;#r;#i;#a=[];#o=/* @__PURE__ */ new Set;#s=[];#c=/* @__PURE__ */ new WeakMap;#l=0;#u=0;#d=!1;constructor(e){if(typeof e.buildWorkerUrl!=`function`)throw TypeError(`WorkerPool: buildWorkerUrl must be a function`);if(e.size!==void 0&&(typeof e.size!=`number`||!Number.isFinite(e.size)||e.size<=0))throw TypeError(`WorkerPool: size must be a positive finite number, received ${String(e.size)}`);if(e.acquireTimeoutMs!==void 0&&(typeof e.acquireTimeoutMs!=`number`||!Number.isFinite(e.acquireTimeoutMs)||e.acquireTimeoutMs<=0))throw TypeError(`WorkerPool: acquireTimeoutMs must be a positive finite number, received ${String(e.acquireTimeoutMs)}`);if(e.drainGraceMs!==void 0&&(typeof e.drainGraceMs!=`number`||!Number.isFinite(e.drainGraceMs)||e.drainGraceMs<=0))throw TypeError(`WorkerPool: drainGraceMs must be a positive finite number, received ${String(e.drainGraceMs)}`);this.#e=e.buildWorkerUrl,this.#t=e.size??4,this.#n=e.acquireTimeoutMs??3e4,this.#r=e.drainGraceMs??5e3,this.#i=e.workerOptions}async acquire(){if(this.#d)throw Error(`pool has been drained and can no longer serve workers`);this.#l+=1;let e=Date.now(),t=this.#a.shift();for(;t!==void 0&&!this.#p(t);)t=this.#a.shift();if(t!==void 0)return this.#o.add(t),t.ref(),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t;if(this.#o.size<this.#t){let t=this.#f();return this.#o.add(t),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-e}),t}return this.#u+=1,await new Promise((t,n)=>{let r=setTimeout(()=>{let e=this.#s.findIndex(e=>e.timer===r);e>=0&&this.#s.splice(e,1),n(/* @__PURE__ */ Error(`pool acquire timed out after ${this.#n} ms`))},this.#n);this.#s.push({resolve:t,reject:n,timer:r,startedAt:e})})}release(e){if(!this.#o.delete(e)||!this.#p(e))return;this.#c.set(e,Date.now());let t=this.#s.shift();if(t){clearTimeout(t.timer),this.#o.add(e),U(H.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-t.startedAt}),t.resolve(e);return}this.#a.push(e),e.unref()}lastSettledAt(e){return this.#c.get(e)}async drain(){for(;this.#s.length>0;){let e=this.#s.shift();if(!e)break;clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`pool drained before acquire could be satisfied`))}let e=Date.now()+this.#r;for(;this.#o.size>0&&Date.now()<e;)await new Promise(e=>setTimeout(e,5));let t=[...this.#a,...this.#o];this.#a.length=0,this.#o.clear(),await Promise.all(t.map(e=>e.terminate().catch(()=>void 0))),this.#d=!0}stats(){return{resident:this.#o.size+this.#a.length,inFlight:this.#o.size,waiters:this.#s.length,totalAcquires:this.#l,poolExhaustions:this.#u}}#f(){let e=new se(this.#e(),this.#i);return e.once(`exit`,()=>{let t=this.#a.indexOf(e);if(t>=0){this.#a.splice(t,1);return}this.#o.delete(e)}),e}#p(e){return e.threadId!==-1}};function zt(e){U(H.imageBytes,{byteLength:e})}function Bt(e){U(H.resetTime,{durationMs:e})}function Vt(){let e=O(ce(import.meta.url)),t=[A(e,`worker.js`),A(e,`worker-entry.ts`)];for(let e of t)if(w(e))return le(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function Ht(e){if(typeof e!=`object`||!e)return;let t=e;if(t.status!==`rejected`)return;let n=typeof t.errorMessage==`string`?t.errorMessage:t.started===!1?`dispatch refused`:`dispatch failed`;return{kind:t.started===!1?`refused`:`failed`,message:n}}function W(e){return e instanceof Error?e.message:String(e)}function Ut(e){if(typeof e!=`object`||!e)return;let t=e.content;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e==`object`&&e){let t=e.text;if(typeof t==`string`&&t.length>0){let e=t.indexOf(`
8
- `);return e===-1?t:t.slice(0,e)}}}}function Wt(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Gt(e,t){let n=/* @__PURE__ */ new WeakSet,r=e=>{if(e!=null){if(e instanceof ArrayBuffer){t(e);return}if(ArrayBuffer.isView(e)){t(e);return}if(typeof e==`object`&&!n.has(e)){if(n.add(e),Array.isArray(e)){for(let t of e)r(t);return}for(let t of Object.keys(e))r(e[t])}}};r(e)}function Kt(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>Wt(t)?null:t)??``,`utf8`),n=0;return Gt(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function qt(e){let i=L(e.config),s=Ne(),c=e.runId??j(),l=Pe(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new se(Vt(),Lt({surface:e.surface,env:s,limits:i,runId:c}))}catch(e){return{logs:u,narrations:d,phases:f,error:{kind:n.workerExit,message:`pool acquire failed: ${W(e)}`}}}return await new Promise(s=>{let m=new oe,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=It(),b=()=>{v||e.onSubCallChange?.(()=>y.snapshot())},x={recordStart(e,t,n){y.recordStart(e,t,n),b()},recordEnd(e,t,n){let r=y.recordEnd(e,t,n);return b(),r},snapshot:()=>y.snapshot()},S,C=!1,w=0,T=0,ee=new Ze(i.dispatchConcurrency),E=0,te=[],ne=e.depth??0,re,D,O=[],k=e=>{let t=[],n=e?.content;if(!Array.isArray(n))return t;for(let e of n){if(typeof e!=`object`||!e)continue;let n=e;if(n.type!==`image`)continue;let r;typeof n.data==`string`&&n.data.length>0?r=n.data:n.bytes instanceof ArrayBuffer&&n.bytes.byteLength>0&&(r=Buffer.from(n.bytes).toString(`base64`)),r!==void 0&&t.push({data:r,mimeType:typeof n.mimeType==`string`?n.mimeType:`application/octet-stream`})}return t},A=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,ie=e=>e===`timeout`?n.timeout:n.abort,ae=t=>{if(v)return;v=!0,re&&clearTimeout(re),D&&clearTimeout(D),e.signal?.removeEventListener(`abort`,pe),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},j=(e,t,n)=>{ae({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},M=e=>{if(!v){if(!r(e)){j(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},se=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...B],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){j(n.protocol,`internal error: malformed init frame`);return}let a=Kt(t);if(a>i.maxMessageBytes){j(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}M(t)},N=(e,t)=>(T+=e,T<=i.maxOutputBytes||(j(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),ce=async()=>{if(E<i.maxParallelSubCalls){E+=1;return}await new Promise(e=>{te.push(e)})},le=()=>{let e=te.shift();if(e){e();return}--E},P=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),j(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}F(e).finally(()=>{--w})},F=async t=>{let r=e.bindings.get(t.tool);if(!r){x.recordEnd(t.callId,`error`,{errorMessage:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)});return}let a=t.tool===V;if(!a&&(await ce(),v)){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),le();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:ne,maxDispatchDepth:i.maxDispatchDepth,callerId:c,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...e.sessionDir===void 0?{}:{sessionDir:e.sessionDir},dispatchDeps:{...e.dispatchDeps,slots:e.dispatchDeps?.slots??ee}}),l=k(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Kt(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),j(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(ue(u))for(let e of l)O.push(e),zt(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?Ht(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:Ut(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:W(e)}):x.recordEnd(t.callId,`error`,{errorMessage:W(e)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:W(e)})}finally{a||le()}},ue=e=>{if(v)return!1;try{return h.postMessage(e),!0}catch(t){try{h.postMessage({kind:o.callResult,callId:e.callId,tool:e.tool,ok:!1,message:`binding result could not be transferred: ${W(t)}`})}catch{j(n.protocol,`binding result is not transferable`)}return!1}},de=e=>S?{logs:u,narrations:d,phases:f,error:{kind:ie(S),message:A(S)}}:e,fe=r=>{if(v)return;if(!a(r)){j(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Kt(r);if(!Number.isFinite(o)){j(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){j(n.protocol,`control frame of ${o} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}switch(r.kind){case t.ready:if(e.pool){let t=e.pool.lastSettledAt(p);t!==void 0&&Bt(Date.now()-t)}if(!C&&(C=!0,S)){me(S);return}se();return;case t.call:P(r);return;case t.log:N(o,`console output`)&&u.push(r.text);return;case t.narration:N(o,`workflow narration`)&&d.push(r.message);return;case t.phase:N(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!N(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...O.length>0?{images:O}:{}};ae(de(r.value===void 0?e:{...e,value:r.value}));return}case t.error:ae(de({logs:u,narrations:d,phases:f,error:r.error}));return;default:j(n.protocol,`unknown worker frame`)}};function pe(){he(`abort`)}let me=e=>{D&&clearTimeout(D),D=setTimeout(()=>{j(ie(e),A(e))},i.graceMs)};function he(e){if(!v){if(S){j(ie(S),A(S));return}S=e,_.abort(),M({kind:o.cancel,reason:e}),me(e)}}p.on(`error`,e=>{j(n.workerExit,`worker failed: ${W(e)}`)}),p.on(`exit`,e=>{j(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,fe),h.on(`messageerror`,()=>{j(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,pe,{once:!0}),re=setTimeout(()=>{he(`timeout`)},l);let ge={kind:o.connect,port:g};r(ge)?p.postMessage(ge,[g]):j(n.protocol,`internal error: malformed connect frame`)})}const Jt=["Return value: every `tools.<name>(args)` call above resolves to `{ content, details }`.","`content` is an ARRAY of content blocks, never a string, so a text result is","`result.content[0].text`; `details` is that tool's own detail object or `null`, never","`undefined`. No binding result has a `files`, `output`, `matches` or `entries` field:","`bash`, `grep`, `find` and `ls` hand back ONE text block of newline-separated rows that","you split yourself, and the empty answer is a sentinel string (`No matches found`,","`No files found matching pattern`, `(empty directory)`) rather than an empty list.","A failing call REJECTS with `ToolCallError` instead of resolving, so wrap the call in","`try`/`catch` (or `Promise.allSettled`): a path that is not there, a builtin this run did not",`bind. A name that is not a builtin is simply not a function.`],Yt=/* @__PURE__ */ new Map([[`bash`,"`bash` rejects on a non-zero exit rather than resolving with its output."],[`write`,"`write` always reports `details: null`."],[`edit`,"`edit` always reports a `details` object carrying `diff` and `patch`."],[V,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),Xt=[Jt.join(`
9
- `),`Exceptions: `+[...Yt.values()].join(` `)].join(`
10
- `),Zt=`pi-ptc-output-`;function Qt(e,t=Zt){let n=k(re(),`${t}${j()}.txt`);return te(n,e,`utf8`),n}function $t(e,t){let n=e.totalLines-e.outputLines+1,r=e.totalLines;return e.lastLinePartial?`[Showing last ${_(e.outputBytes)} of line ${r}. Full output: ${t}]`:e.truncatedBy===`lines`?`[Showing lines ${n}-${r} of ${e.totalLines}. Full output: ${t}]`:`[Showing lines ${n}-${r} of ${e.totalLines} (${_(s)} limit). Full output: ${t}]`}function en(e,t=Zt,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Qt(n.fullText??e,t);return{text:`${r.content}\n\n${$t(r,i)}`,truncated:!0,fullPath:i}}const tn=200,nn=new RegExp([`(?:\\u001B\\][\\s\\S]*?(?:\\u0007|\\u001B\\u005C|\\u009C))`,`[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]`].join(`|`),`g`);function rn(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(nn,``)}function G(e){let t=rn(e).replace(/\r/g,``);if(t.length===0)return t;let n=``;for(let e of t){let t=e.codePointAt(0);if(t!==void 0){if(t===10||t===9){n+=e;continue}t<=31||t>=65529&&t<=65531||(n+=e)}}return n}const an=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function on(e){return an.test(e)?e:JSON.stringify(e)}function sn(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=G(e);return t.includes(`
11
- `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=sn(n);if(e===void 0)return;t.push(e)}return`[${t.join(`, `)}]`}let t=Object.keys(e);if(t.length===0)return`{}`;let n=[];for(let r of t){let t=sn(e[r]??null);if(t===void 0)return;n.push(`${on(r)}: ${t}`)}return`{${n.join(`, `)}}`}function cn(e){let t=sn(e);if(t!==void 0)return t.length<=100?t:void 0}function ln(e){return e===null?`null`:typeof e==`string`?G(e):String(e)}function un(e,t){if(typeof e!=`object`||!e)return[`${t}${ln(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=cn(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...dn(r,t+` `))}return n.push(`${t}]`),n}let n=Object.keys(e);if(n.length===0)return[`${t}{}`];let r=[`${t}{`],i=t+` `;for(let t of n){let n=e[t]??null,a=cn(n);if(a!==void 0){r.push(`${i}${on(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${on(t)}:`);for(let e of G(n).split(`
12
- `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=un(n,i);r.push(`${i}${on(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function dn(e,t){return typeof e==`string`?G(e).split(`
13
- `):typeof e!=`object`||!e?[String(e)]:un(e,t)}function fn(e){return e.split(`
7
+ `+r}function ct(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch depth limit reached`}}function lt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,errorMessage:`dispatch concurrency limit reached`}}function R(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 ut(){return{...ct(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function dt(){return{...lt(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function ft(e){return e.aborted?{status:`rejected`,errorMessage:`dispatch cancelled`}:e.exitCode===0&&e.finalText.length>0?{status:`fulfilled`}:e.exitCode===0?{status:`rejected`,errorMessage:`dispatch produced no final text`}:{status:`rejected`}}function pt(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 mt(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 ht(e){let t=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(!t)return null;let n=t[1]??``,r=t[2]??``,i=pt(n,`name`);if(!i)return null;let a=pt(n,`description`)??``,o=pt(n,`model`)??``,s=mt(n,`tools`),c={name:i,systemPrompt:r.trim()};return a!==void 0&&(c.description=a),o!==void 0&&(c.model=o),s!==void 0&&(c.tools=s),c}function gt(e,t,n,r){let{userDir:i,projectDir:a}=_t({cwd:t,agentScope:n,homeDir:r?.homeDir}),o=[];(n===`user`||n===`both`)&&o.push({path:E.join(i,e+`.md`),source:`user`}),(n===`project`||n===`both`)&&o.push({path:E.join(a,e+`.md`),source:`project`});for(let t of o){let n;try{n=C.readFileSync(t.path,`utf-8`)}catch{continue}let r=ht(n);if(r&&r.name===e){let e={name:r.name,source:t.source,systemPrompt:r.systemPrompt};return r.model!==void 0&&(e.model=r.model),r.tools!==void 0&&(e.tools=r.tools),e}}return null}function _t(e){let t=e.homeDir??re.homedir();return{userDir:E.join(t,`.pi`,`agent`,`agents`),projectDir:E.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function vt(e){let t=e?.code;return typeof t==`string`?t:String(e)}function yt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function bt(e,t){let n=E.resolve(e),r=E.resolve(t),i=e=>E.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(xt(e))return!0;return!1}return a===r&&xt(r)}function xt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function St(e,t,n){let r=vt(n);return r!==`ENOENT`&&r!==`ENOTDIR`||yt(e)?!1:!bt(e,t)}function Ct(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=_t(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i});let o=/* @__PURE__ */ new Set;for(let{dir:e,boundary:t}of a){let n;try{n=C.readdirSync(e)}catch(n){if(!St(e,t,n)){let t=vt(n);console.warn(`pi.dispatch: cannot read agent directory ${e} (${t}); the agents registered there are not listed`)}continue}for(let t of n){if(!t.endsWith(`.md`))continue;let n=t.slice(0,-3),r=E.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`pi.dispatch: cannot read agent file ${r}: ${t}; falling back to the filename`),o.add(n);continue}let a=ht(i)?.name??n;a.length>0&&o.add(a)}}return[...o].sort()}function wt(e){let{userDir:t,projectDir:n}=_t(e),r=Ct(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t}/<name>.md (user scope) or ${n}/<name>.md (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body`}function Tt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,errorMessage:`agent is required (there is no default agent) — `+wt(e)}}function Et(e){return typeof e!=`string`||e.trim().length===0}function Dt(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+wt({cwd:n,agentScope:t})}}function Ot(e,t,n){let r=[`--mode`,`json`,`-p`,`--no-session`],i=e.model??t.model;i&&r.push(`--model`,i);let a=e.thinkingLevel??`off`;return r.push(`--thinking`,a),t.tools&&t.tools.length>0&&r.push(`--tools`,t.tools.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let kt=At;async function At(e,t){let n=await C.promises.mkdtemp(E.join(re.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=E.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 Mt(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 Nt(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 Pt(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return ut();if(Et(e.agent))return Tt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`});let i=Ee(),a=n.slots??rt;if(!a.tryAcquire(i))return dt();let o=n.clock??(()=>Date.now()),s=n.logger??ot,c=e.cwd??t.cwd,l=e.agentScope??`user`,u=n.lifecycle??tt,d=t.callerId??`dispatch:`+String(t.callId),f=at(n,o),p=n.outputStorage,m,h;try{let n=gt(e.agent,c,l);if(!n)return a.release(i),Dt(e.agent,l,c);let g=e.label??e.task.slice(0,64),_=st(n.systemPrompt,r,t.maxDispatchDepth),v=await kt(n.name,_);h=v;let y=Ot(e,n,v.filePath),b={cwd:c,env:{...process.env,PI_PTC_DEPTH:String(r),PI_PTC_TASK_ID:i},promptFile:v.filePath};t.sessionDir!==void 0&&(b.sessionDir=t.sessionDir,b.sessionId=i,b.sessionName=`bgdispatch:`+i),m=u.spawn([`pi`,...y],b);let x=m,S={kind:`ptc-program`,callerId:d};await f.transition({kind:`spawn`,handle:{taskId:i,label:g,status:`running`},record:{label:g,agentName:n.name,depth:r,startedAt:Math.max(0,Math.floor(o())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:S,parentTaskId:t.parentTaskId}},{clock:o,callerId:d,logger:s});let C=!1,w,T=f.onTransition((e,t)=>{e.id===i&&t.status===`stopping`&&(C||w!==void 0||(w=R(u,x,{isDone:()=>C,unref:!0})))});return(async()=>{let e=``,t;try{for await(let n of u.events(x)){let r=Mt(n);r!==void 0&&(e=r);let i=Nt(n);i!==void 0&&(t=i)}C=!0,w?.();let n=(await u.exit(x)).code??-1,r=Buffer.byteLength(e,`utf8`),a=r<=2048?e:void 0,c;if(p!==void 0)try{await p.writeOutput(i,e),c=p.outputRef(i)}catch(e){let t=e instanceof Error?e.message:String(e);s.warn(`background dispatch output persistence for task `+i+` failed: `+t)}await f.transition({kind:`resolve-exit`,taskId:i,exitCode:n,outputRef:c,outputBytes:r,outputPreview:a,childError:t},{clock:o,callerId:d,logger:s})}catch(t){let n=t instanceof Error?t.message:String(t);s.warn(`background dispatch pump for task `+i+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{T(),w?.(),jt(v),a.release(i)}})(),{taskId:i,label:g,status:`running`}}catch(t){let n=t instanceof Error?t.message:String(t);return m!==void 0&&R(u,m,{unref:!0}),h!==void 0&&jt(h),a.release(i),s.warn(`background dispatch failed for agent `+e.agent+`: `+n),{text:``,status:`rejected`,started:m!==void 0,agentName:e.agent,durationMs:0,exitCode:-1,errorMessage:`background dispatch failed: `+n}}}async function Ft(e,t,n={}){if(e.background===!0)return await Pt(e,t,n);let r=t.depth+1;if(r>t.maxDispatchDepth)return ct();let i=e.cwd??t.cwd,a=e.agentScope??`user`,o=Date.now();if(Et(e.agent))return Tt({cwd:i,agentScope:a});let s=n.slots??rt;if(!s.tryAcquire())return lt();let c=gt(e.agent,i,a);if(!c)return s.release(),Dt(e.agent,a,i,Date.now()-o);let l=st(c.systemPrompt,r,t.maxDispatchDepth),u,d=n.lifecycle??tt,f;try{u=await kt(c.name,l),f=Ot(e,c,u.filePath)}catch(e){throw s.release(),e}return await new Promise(e=>{let a=``,l,p=-1,m=``,h=!1,g,_,v=!1,y=(r,i,f=!0)=>{if(h)return;h=!0,s.release(),_!==void 0&&d.exit(_).catch(e=>{(n.logger??ot).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),g?.(),t.signal&&t.signal.removeEventListener(`abort`,b),jt(u);let v={text:a,status:r,started:f,agentName:c.name,durationMs:Date.now()-o,exitCode:p};l&&(v.usage=l),m.length>0&&(v.stderr=m),i&&(v.errorMessage=i),e(v)},b=()=>{_&&!h&&(v=!0,g=R(d,_,{isDone:()=>h}))};try{_=d.spawn([`pi`,...f],{cwd:i,env:{...process.env,PI_PTC_DEPTH:String(r)},promptFile:u.filePath})}catch(e){y(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?b():t.signal.addEventListener(`abort`,b,{once:!0})),(async()=>{if(!_)return;let e=_;try{for await(let t of d.events(e))if(t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(e.usage){let t=l??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};t.input+=e.usage.input??0,t.output+=e.usage.output??0,t.cacheRead+=e.usage.cacheRead??0,t.cacheWrite+=e.usage.cacheWrite??0,t.cost+=e.usage.cost?.total??0,t.turns+=1,l=t}if(Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(a=t.text)}let t=await tt.exit(e);p=t.code??-1,m=await tt.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){y(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:r,errorMessage:i}=ft({exitCode:p,finalText:a,aborted:v});y(r,i)}catch(e){let t=e instanceof Error?e.message:String(e);y(`rejected`,`dispatch internal error: `+t)}})()})}const z=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],B=`pi.dispatch`,It=z,Lt={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},Rt=x.Object({agent:x.String({minLength:1}),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)])),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String())}),zt={name:B,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:Rt};function Bt(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 Vt(e){let t=e.names??It,n=e.includeDispatch??e.names===void 0,r=/* @__PURE__ */ new Map;for(let n of t){let t=Lt[n];if(!t)throw TypeError(`unknown PTC binding "${n}"; known bindings: ${z.join(`, `)}`);let i=t(e.cwd);r.set(n,{name:n,execute:async(e,t)=>{let n=`ptc:${t.callId}`,r={type:`toolCall`,id:n,name:i.name,arguments:e},a=S(i,r),o=await i.execute(n,a,t.signal,void 0);if(o.isError===!0)throw Error(Bt(i.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
8
+ `)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return n&&r.set(B,{name:B,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:B,arguments:t},i;try{i=S(zt,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return Et(i)?Tt({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}):{text:``,status:`rejected`,started:!1,agentName:i,durationMs:0,exitCode:1,errorMessage:n instanceof Error?n.message:String(n)}}return Ft(i,{signal:n.signal,callId:n.callId,cwd:e.cwd,depth:n.depth,maxDispatchDepth:n.maxDispatchDepth,...n.callerId===void 0?{}:{callerId:n.callerId},...n.sessionDir===void 0?{}:{sessionDir:n.sessionDir},...n.parentTaskId===void 0?{}:{parentTaskId:n.parentTaskId}},n.dispatchDeps)}}),r}function Ht(){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 Ut(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 V={acquireLatency:P.channel(`ptc:pool:acquire-latency`),resetTime:P.channel(`ptc:worker:reset-time`),imageBytes:P.channel(`ptc:image:hoist-bytes`)};function H(e,t){e.publish(t)}var Wt=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(),H(V.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),H(V.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),H(V.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-t.startedAt}),t.resolve(e);return}this.#a.push(e),e.unref()}lastSettledAt(e){return this.#c.get(e)}async drain(){for(;this.#s.length>0;){let e=this.#s.shift();if(!e)break;clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`pool drained before acquire could be satisfied`))}let e=Date.now()+this.#r;for(;this.#o.size>0&&Date.now()<e;)await new Promise(e=>setTimeout(e,5));let t=[...this.#a,...this.#o];this.#a.length=0,this.#o.clear(),await Promise.all(t.map(e=>e.terminate().catch(()=>void 0))),this.#d=!0}stats(){return{resident:this.#o.size+this.#a.length,inFlight:this.#o.size,waiters:this.#s.length,totalAcquires:this.#l,poolExhaustions:this.#u}}#f(){let e=new N(this.#e(),this.#i);return e.once(`exit`,()=>{let t=this.#a.indexOf(e);if(t>=0){this.#a.splice(t,1);return}this.#o.delete(e)}),e}#p(e){return e.threadId!==-1}};function Gt(e){H(V.imageBytes,{byteLength:e})}function Kt(e){H(V.resetTime,{durationMs:e})}function qt(){let e=oe(ue(import.meta.url)),t=[k(e,`worker.js`),k(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 Jt(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 Yt(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(`
9
+ `);return e===-1?t:t.slice(0,e)}}}}function Xt(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Zt(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 Qt(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>Xt(t)?null:t)??``,`utf8`),n=0;return Zt(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function $t(e){let i=Le(e.config),s=Ie(),c=e.runId??j(),l=Re(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new N(qt(),Ut({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=Ht(),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 nt(i.dispatchConcurrency),te=0,ne=[],re=e.depth??0,ie,E,ae=[],oe=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},D=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,O=e=>e===`timeout`?n.timeout:n.abort,k=t=>{if(v)return;v=!0,ie&&clearTimeout(ie),E&&clearTimeout(E),e.signal?.removeEventListener(`abort`,fe),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},A=(e,t,n)=>{k({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},se=e=>{if(!v){if(!r(e)){A(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},ce=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...z],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){A(n.protocol,`internal error: malformed init frame`);return}let a=Qt(t);if(a>i.maxMessageBytes){A(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}se(t)},j=(e,t)=>(T+=e,T<=i.maxOutputBytes||(A(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),M=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},P=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),A(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}ue(e).finally(()=>{--w})},ue=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)`)}),de({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===B;if(!a&&(await M(),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:re,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=oe(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Qt(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),A(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(de(u))for(let e of l)ae.push(e),Gt(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?Jt(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:Yt(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)}),de({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:U(e)})}finally{a||N()}},de=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{A(n.protocol,`binding result is not transferable`)}return!1}},F=e=>S?{logs:u,narrations:d,phases:f,error:{kind:O(S),message:D(S)}}:e,I=r=>{if(v)return;if(!a(r)){A(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Qt(r);if(!Number.isFinite(o)){A(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){A(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&&Kt(Date.now()-t)}if(!C&&(C=!0,S)){pe(S);return}ce();return;case t.call:P(r);return;case t.log:j(o,`console output`)&&u.push(r.text);return;case t.narration:j(o,`workflow narration`)&&d.push(r.message);return;case t.phase:j(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!j(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...ae.length>0?{images:ae}:{}};k(F(r.value===void 0?e:{...e,value:r.value}));return}case t.error:k(F({logs:u,narrations:d,phases:f,error:r.error}));return;default:A(n.protocol,`unknown worker frame`)}};function fe(){me(`abort`)}let pe=e=>{E&&clearTimeout(E),E=setTimeout(()=>{A(O(e),D(e))},i.graceMs)};function me(e){if(!v){if(S){A(O(S),D(S));return}S=e,_.abort(),se({kind:o.cancel,reason:e}),pe(e)}}p.on(`error`,e=>{A(n.workerExit,`worker failed: ${U(e)}`)}),p.on(`exit`,e=>{A(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,I),h.on(`messageerror`,()=>{A(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,fe,{once:!0}),ie=setTimeout(()=>{me(`timeout`)},l);let he={kind:o.connect,port:g};r(he)?p.postMessage(he,[g]):A(n.protocol,`internal error: malformed connect frame`)})}const en=["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.`],tn=/* @__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`."],[B,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),nn=[en.join(`
10
+ `),`Exceptions: `+[...tn.values()].join(` `)].join(`
11
+ `),rn=`pi-ptc-output-`;function an(e,t=rn){let n=D(ie(),`${t}${j()}.txt`);return ne(n,e,`utf8`),n}function on(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 sn(e,t=rn,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=an(n.fullText??e,t);return{text:`${r.content}\n\n${on(r,i)}`,truncated:!0,fullPath:i}}const cn=200,ln=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 un(e){return!e.includes(`\x1B`)&&!e.includes(`›`)?e:e.replace(ln,``)}function W(e){let t=un(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 dn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function fn(e){return dn.test(e)?e:JSON.stringify(e)}function pn(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(`
12
+ `)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=pn(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=pn(e[r]??null);if(t===void 0)return;n.push(`${fn(r)}: ${t}`)}return`{${n.join(`, `)}}`}function mn(e){let t=pn(e);if(t!==void 0)return t.length<=100?t:void 0}function hn(e){return e===null?`null`:typeof e==`string`?W(e):String(e)}function gn(e,t){if(typeof e!=`object`||!e)return[`${t}${hn(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=mn(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(..._n(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=mn(n);if(a!==void 0){r.push(`${i}${fn(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${fn(t)}:`);for(let e of W(n).split(`
13
+ `))r.push(e.length===0?``:`${i} ${e}`);continue}let o=gn(n,i);r.push(`${i}${fn(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function _n(e,t){return typeof e==`string`?W(e).split(`
14
+ `):typeof e!=`object`||!e?[String(e)]:gn(e,t)}function vn(e){return e.split(`
14
15
  `).map(e=>e.length>200?`${e.slice(0,199)}…`:e).join(`
15
- `)}function pn(e){if(typeof e==`string`)return fn(G(e));if(typeof e!=`object`||!e)return String(e);let t=cn(e);return fn((t===void 0?dn(e,``):[t]).join(`
16
- `))}function mn(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function hn(e=process.env){let t=e.PI_PTC_TASK_ID;if(t!==void 0&&/^[0-9A-HJKMNP-TV-Z]{26}$/.test(t))return t}function K(e){if(e===void 0)return B;let t=new Set(e);return B.filter(e=>t.has(e))}const gn=["Image-bearing tool results inside a program (a `tools.read` on a PNG, say) are attached to you after the run — never return image data as the completion value.",`Use ptc_run_code when a task needs several tool calls whose intermediate output you do not need to see — gather it inside the program and return only the final value.`,`Use ptc_workflow instead of ptc_run_code when the work has named phases and the user benefits from seeing progress narration.`],_n={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function vn(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function yn(e){let{surface:t,startedAt:n,onUpdate:r}=e;if(r===void 0)return{update:()=>{},cancel:()=>{}};let i=0,a,o,s=()=>{if(o===void 0)return;let e=o;o=void 0,i=Date.now(),r({content:[],details:{surface:t,logs:[],narrations:[],phases:[],warnings:[],durationMs:Date.now()-n,imageCount:0,subCalls:e()}})};return{update(e){o=e;let t=100-(Date.now()-i);if(t<=0){a!==void 0&&(clearTimeout(a),a=void 0),s();return}a??=setTimeout(()=>{a=void 0,s()},t)},cancel(){a!==void 0&&(clearTimeout(a),a=void 0),o=void 0}}}function bn(e){return[...e.phases.map(e=>`[phase] ${G(e)}`),...e.narrations.map(e=>`[log] ${G(e)}`),...e.logs.map(e=>G(e))]}function xn(e){let t=e.error;if(t===void 0)return/* @__PURE__ */ Error(`internal error: a successful PTC run was rendered as a failure`);let n=bn(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
17
- `)}`,i=Error(G(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function Sn(e){let{outcome:t,surface:n}=e,r=[...e.warnings??[]],i=t.images??[],a=[];t.phases.length>0&&a.push(`Phases: ${t.phases.map(e=>G(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>G(e)).join(`
18
- `)),t.logs.length>0&&a.push(t.logs.map(e=>G(e)).join(`
19
- `)),t.value!==void 0&&a.push(pn(t.value));for(let e of r)a.push(`Warning: ${G(e)}`);let o=en(a.length>0?a.join(`
20
- `):`(${_n[n]} completed with no output)`),s=o.text,c=o.truncated?o.fullPath:void 0;return{content:[{type:`text`,text:s},...i.map(e=>({type:`image`,data:e.data,mimeType:e.mimeType}))],details:{surface:n,logs:[...t.logs],narrations:[...t.narrations],phases:[...t.phases],warnings:r,...t.value===void 0?{}:{result:t.value},durationMs:e.durationMs,imageCount:i.length,...c===void 0?{}:{fullOutputPath:c},...t.subCalls===void 0?{}:{subCalls:t.subCalls}}}}const Cn=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function wn(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function Tn(e,t){if(e.charCodeAt(t)!==27)return t;let n=e.charCodeAt(t+1);if(n===93){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t===7)return n+1;if(t===27&&e.charCodeAt(n+1)===92)return n+2;n+=1}return n}if(n===91){let n=t+2;for(;n<e.length;){let t=e.charCodeAt(n);if(t>=64&&t<=126)return n+1;n+=1}return n}return t+2}function En(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=Tn(e,n):(n+=1,r+=1);return n}function Dn(e,t){let n=t.intervalMs??150,{state:r}=t;t.isPartial?(r.startedAt??=Date.now(),r.interval??=setInterval(()=>t.requestInvalidate(),n)):(r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0),r.startedAt=void 0);let i=e.render.bind(e),a=e;return a.render=e=>{let a=i(e);return r.startedAt===void 0?a:On(a,Math.floor((Date.now()-r.startedAt)/n),t.theme)},a.dispose=()=>{r.interval!==void 0&&(clearInterval(r.interval),r.interval=void 0)},e}function On(e,t,n){return e.map(e=>{let r=wn(e),i=Cn.exec(r);if(i===null)return e;let a=(i[3]??``).slice(1);if(a.length===0)return e;let o=t%(a.length+1),s=i[0].length-a.length,c=En(e,s),l=En(e,s+a.length),u=o>=a.length?n.fg(`dim`,a):`${o>0?n.fg(`dim`,a.slice(0,o)):``}${n.fg(`accent`,a.slice(o,o+1))}${n.fg(`dim`,a.slice(o+1))}`;return`${e.slice(0,c)}${u}${e.slice(l)}`})}const kn={run_code:`PTC`,workflow:`PTC workflow`};var An=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>jn(e,t))}};function jn(e,t){let{left:n,right:r}=e;if(r===void 0)return P(n,t,`…`);let i=F(r);if(i>=t)return P(r,t,`…`);let a=P(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-F(a));return a+` `.repeat(o)+r}function q(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Mn(e){return q((G(e).split(`
21
- `).find(e=>e.trim().length>0)??``).trim(),120)}function Nn(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function Pn(e,t){return`${e} ${t}${e===1?``:`s`}`}function Fn(e){for(let t of e.split(`
22
- `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return q(e.replace(/\s*\/\/.*$/,``),120)}}function In(e){if(e===void 0)return;if(typeof e==`string`){let t=G(e).split(`
23
- `),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:q(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=pn(e);if(!t.includes(`
24
- `)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function Ln(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,Pn(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,Pn(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,Pn(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,Pn(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Nn(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Rn(e){if(e!==void 0)return{surface:e.surface??`run_code`,logs:e.logs??[],narrations:e.narrations??[],phases:e.phases??[],warnings:e.warnings??[],durationMs:e.durationMs??0,imageCount:e.imageCount??0,...e.result===void 0?{}:{result:e.result},...e.fullOutputPath===void 0?{}:{fullOutputPath:e.fullOutputPath},...e.subCalls===void 0?{}:{subCalls:e.subCalls}}}function zn(e,t,n){let r=` `+(t?`└─ `:`├─ `),i=` `+(t?` `:`│ `),a=` `.repeat(8),o=[],s=e.lines[0]??``;o.push({left:`${r}${e.label.padEnd(8)}${n.fg(`dim`,s)}`});for(let t=1;t<e.lines.length;t++)o.push({left:`${i}${a}${n.fg(`dim`,e.lines[t]??``)}`});return e.more!==void 0&&e.more>0&&o.push({left:`${i}${a}…+${e.more} more lines`}),o}function Bn(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const Vn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Hn(e){return Vn.test(e)?e:JSON.stringify(e)}function Un(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=G(e);if(n.length===0)return`""`;if(n.includes(`
25
- `)){let e=q(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(q(n,Math.max(2,t-5)))+`…`}return`?`}function Wn(e){return typeof e!=`object`||!e}function Gn(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Wn))return;let n=`[`+e.map(e=>Un(e,Math.max(2,Math.floor(t/4)))).join(`, `)+`]`;return n.length<=t?n:void 0}if(typeof e!=`object`||!e)return;let n=Object.keys(e);if(n.length===0)return`{}`;if(n.length>5||!Object.values(e).every(Wn))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Hn(n)+`: `+Un(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Kn(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(J(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(J(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(J(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-F(l)-t.length);c.push(J(l+t+Un(e,n),o));return}let d=Gn(e,Math.max(0,o-F(l)-t.length));if(d!==void 0){c.push(J(l+t+d,o));return}let f=Array.isArray(e),p=f?e.length:Object.keys(e).length,m;m=f?`Array(`+p+`)`:p>a?`{`+a+` of `+p+`}`:`{`+p+` keys}`,c.push(J(l+t+m,o));let h=Math.min(a,p);if(f)for(let t=0;t<h;t+=1){let n=t===h-1&&p<=h;Kn(e[t]??null,`[`+t+`] `,u,n,i,a,o,s+1,c)}else{let t=Object.keys(e);for(let n=0;n<h;n+=1){let r=n===h-1&&p<=h,l=t[n];Kn(e[l]??null,Hn(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(J(u+`└─ …+`+(p-h)+` more `+e,o))}}function J(e,t){if(F(e)<=t)return e;let n=e.match(/^([\s│├└─]*)/),r=n&&n[1]?n[1]:``,i=F(r),a=Math.max(0,t-i-1),o=``,s=0;for(let t of e.slice(r.length)){let e=F(t);if(s+e>a)break;o+=t,s+=e}return r+o+`…`}function qn(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Bn(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Un(e,i)];let o=[];if(Array.isArray(e)){let t=e.length,s=Math.min(r,t);for(let c=0;c<s;c+=1){let l=!a&&c===s-1&&t<=s;Kn(e[c]??null,`[`+c+`] `,``,l,n,r,i,0,o)}return t>s&&o.push((a?`├─ `:`└─ `)+`…+`+(t-s)+` more items`),o}let s=Object.keys(e),c=s.length,l=Math.min(r,c);for(let t=0;t<l;t+=1){let u=!a&&t===l-1&&c<=l,d=s[t];Kn(e[d]??null,Hn(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}function Jn(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Fn(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return Dn(new An([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(kn[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??Yn,state:r.state??{}})}function Yn(){}function Xn(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Mn(t?.text??``)||`failed`}function Zn(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t&&`agent`in t)return`→ ${String(t.agent)}`;if(typeof t==`object`&&t){let n=t,r=e=>typeof n[e]==`string`?n[e]:void 0,i=e===`read`?r(`path`):e===`bash`?r(`command`):e===`grep`||e===`find`?r(`pattern`):e===`ls`||e===`edit`||e===`write`?r(`path`):void 0;if(typeof i==`string`)return i}try{let e=JSON.stringify(t).replace(/\n/g,` `);return e.length>40?`${e.slice(0,39)}…`:e}catch{return String(t).slice(0,40)}}const Qn={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Nn(e.durationMs)}`,themeSlot:`accent`},error:{text:e=>`failed: ${e.errorMessage??`error`}`,themeSlot:`error`},cancelled:{text:()=>`cancelled`,themeSlot:`muted`},rejected:{text:e=>`rejected: ${e.errorMessage??`concurrency`}`,themeSlot:`warning`}};function $n(e,t){if(e.length===0)return[];let n=e.slice(0,32),r=e.length>32?e.length-32:0,i=[];return n.forEach((e,a)=>{let o=a===n.length-1&&r===0?`└─ `:`├─ `,s=e.name.length>=8?`${e.name} `:e.name.padEnd(8),c=Zn(e.name,e.args),l=Qn[e.status];i.push({left:` ${o}${t.fg(`toolTitle`,s)}${t.fg(l.themeSlot,l.text(e))}${t.fg(`dim`,` `+c)}`})}),r>0&&i.push({left:` └─ …+${r} more calls`}),i}function er(e,t,n,r=!1,i=!1){let a=Ln(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${Xn(e)}`)}`})];if(i&&e.details?.result===void 0)return[];let s=e.details?.result;if(s===void 0)return[o({left:` ${n.fg(`muted`,`done`)}`})];if(Bn(s))return qn(s,{maxDepth:4,maxChildren:6,maxLineChars:120,moreAfter:r}).map((e,t)=>{let n={left:` ${e}`};return t===0&&a!==void 0?{...n,right:a}:n});let c=In(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function tr(e,t,n,r={}){let i=Rn(e.details),a=[...er({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...$n(i.subCalls,n)),new An(a)}function nr(e,t,n,r,i={}){let a=Rn(e.details);if(n){let t=[...er({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...$n(a.subCalls,r));let n=G(e.content?.find(e=>e.type===`text`)?.text??Xn(e));for(let e of n.split(`
26
- `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new An(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
27
- `).map(e=>q(e,120)),t=e.slice(0,3);o.push({label:`code`,lines:t,...e.length>t.length?{more:e.length-t.length}:{}})}if(a!==void 0&&a.surface===`workflow`&&a.phases.length>0){let e=a.phases.slice(0,8),t=a.phases.length-e.length,n=t>0?` …+${t} more phases`:``;o.push({label:`phases`,lines:[`${e.join(` → `)}${n}`]})}if(a!==void 0&&a.narrations.length>0){let e=a.narrations.slice(0,12);o.push({label:`log`,lines:e.map(e=>G(e)),...a.narrations.length>e.length?{more:a.narrations.length-e.length}:{}})}if(a!==void 0&&a.logs.length>0){let e=a.logs.slice(0,12);o.push({label:`out`,lines:e.map(e=>G(e)),...a.logs.length>e.length?{more:a.logs.length-e.length}:{}})}if(a!==void 0&&a.warnings.length>0){let e=a.warnings.slice(0,4);o.push({label:`warn`,lines:e.map(e=>G(e)),...a.warnings.length>e.length?{more:a.warnings.length-e.length}:{}})}if(a!==void 0&&a.imageCount>0){let e=a.imageCount===1?`1 image attached`:`${a.imageCount} images attached`;o.push({label:`image`,lines:[e]})}let c=a?.subCalls,l=c!==void 0&&c.length>0||o.length>0,u=er({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...$n(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...zn(o[e]??{label:``,lines:[]},t,r))}return new An(u)}function rr(e){return{renderCall(t,n,r){return Jn(t,n,e,{...r?.invalidate===void 0?{}:{requestInvalidate:r.invalidate},...r?.isPartial===void 0?{}:{isPartial:r.isPartial},...r?.state===void 0?{}:{state:r.state}})},renderResult(e,t,n,r){let i=t.isPartial===!0;return t.expanded===!0?nr(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):tr(e,r?.isError===!0,n,{isPartial:i})}}}const ir=["Run a TypeScript program that composes pi's tools in one shot. Required arguments: `code` —","the body of an async function (top-level `return` and `await` work; type annotations are","advisory, the code runs type-stripped) — and `description`, a 5-10 word summary of what the",`program does.`,``,"Inside the program, call this session's enabled built-in tools as `tools.<name>(args)` — e.g.",'`await tools.read({ path: "src/index.ts" })` or `await tools.bash({ command: "npm test" })`.',"The bound names mirror the session's active tools (a default session has `read`, `bash`, `edit`,","`write`); independent calls may overlap under `Promise.all`.",``,"The parallel binding `pi.dispatch` is always available, registered under its literal dot name —",'call it with string indexing, e.g. `await tools["pi.dispatch"]({ agent: "reviewer", task: "..." })`;',"`tools.pi.dispatch` does not exist. It fans work out to child pi agents, and independent","foreground dispatches compose under `Promise.all` exactly like the built-in calls. The run's","actual bound names (this run, not a static list) are on the `ptcBindings` global, so the program",`never has to guess what is bound.`,``,Xt,``,"Only the program's return value and its `console.log` output come back. This surface has no","helpers: `log` / `phase` / `parallel` / `pipeline` exist only in `ptc_workflow`.",``,"Image-bearing tool results inside the program (a `tools.read` on a PNG, say) are attached to you",`after the run, so never return image data as the completion value — that only spends your context`,`on base64.`].join(`
28
- `),ar=x.Object({code:x.String({description:`The program: the body of an async TypeScript function.`}),description:x.String({description:`Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI).`}),timeoutMs:x.Optional(x.Number({description:`Elapsed deadline in milliseconds for the whole run, including tool calls. Omit it (or pass 0) for the default of ${I.timeoutMs/1e3} s; anything above ${I.maxTimeoutMs/1e3} s is capped. The deadline bounds the whole run: if it expires, in-flight foreground dispatches spawned by the program are terminated with it.`}))});function or(e={}){return g({name:`ptc_run_code`,label:`PTC Run Code`,description:ir,promptSnippet:`Run a TypeScript program that composes pi's tools in one shot (tools.<name>(args)); only its return value and console.log come back`,promptGuidelines:[...gn],parameters:ar,async execute(t,n,r,i,a){let o=vn(a),s=K(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=yn({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await qt({code:n.code,surface:`run_code`,cwd:o,bindings:Ft({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...n.timeoutMs===void 0?{}:{timeoutMs:n.timeoutMs},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw xn(p);return Sn({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...rr(`run_code`)})}const sr=[`Run a structured TypeScript workflow: a named plan that reports phases and narration as it`,"goes. `script` is the body of an async function, `meta` names it (`{ name, description, phases? }`,","where `phases` is the ordered plan), and optional `args` is plain-JSON input bound to the","program's `args` global.",``,"Helpers inside the script: `log(message)` narrates progress; `phase(title)` frames the workflow","(titles outside `meta.phases` are reported as warnings); `parallel(thunks)` runs thunks","concurrently, a failed item becoming `null`; `pipeline(items, ...stages)` chains stages per item","with the same per-item `null` on failure. There is no `agent()` helper.",``,"Tools are reachable as `tools.<name>(args)` exactly as in `ptc_run_code`, and the bound names","mirror the session's enabled tools. The parallel binding `pi.dispatch` is always available under",'its literal dot name — call it with string indexing: `await tools["pi.dispatch"]({ agent, task })`;',"the run's actual bound names are on the `ptcBindings` global. What comes back is the script's","return value, its `log`/`phase` narration and its `console.log` output.",``,Xt,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
29
- `),cr=x.Object({meta:x.Object({name:x.String({description:`Short workflow name, shown in the UI.`}),description:x.String({description:`What this workflow does, in active voice.`}),phases:x.Optional(x.Array(x.Object({name:x.String({description:`Phase title, matched against phase(title) calls.`})}),{description:`Ordered plan of the workflow's phases. phase() titles outside this list are reported as warnings.`}))},{description:`Workflow metadata: what this run is and which phases it declares.`}),script:x.String({description:`The program: the body of an async TypeScript function.`}),args:x.Optional(x.Record(x.String(),x.Unknown(),{description:"Plain-JSON input bound to the program's `args` global. No functions, symbols, undefined values or cycles."}))});function lr(t){if(t!==void 0){if(typeof t!=`object`||!t||Array.isArray(t))throw TypeError(`ptc_workflow args must be a plain JSON object, received ${e(t)}`);for(let e of Object.keys(t)){let n=ur(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function ur(t,n,r){if(t===null||typeof t==`string`||typeof t==`boolean`)return;if(t===void 0)return`${n} is undefined`;if(typeof t==`number`)return Number.isFinite(t)?void 0:`${n} is ${String(t)}, which is not representable as JSON`;if(typeof t!=`object`)return`${n} is ${e(t)}`;let i=t;if(r.has(i))return`${n} is a circular reference`;r.add(i);try{if(Array.isArray(i)){for(let e=0;e<i.length;e+=1){let t=ur(i[e],`${n}[${e}]`,r);if(t!==void 0)return t}return}let e=Object.getPrototypeOf(i);if(e!==Object.prototype&&e!==null){let e=i.constructor?.name;return`${n} is a ${typeof e==`string`&&e.length>0?e:`non-plain object`}, not plain JSON`}for(let e of Object.keys(i)){let t=ur(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function dr(e,t){if(t===void 0||t.length===0)return[];let n=new Set(t),r=/* @__PURE__ */ new Set,i=[];for(let t of e.phases)n.has(t)||r.has(t)||(r.add(t),i.push(`phase "${t}" is not listed in meta.phases (declared: ${[...n].join(`, `)})`));return i}function fr(e={}){return g({name:`ptc_workflow`,label:`PTC Workflow`,description:sr,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...gn],parameters:cr,async execute(t,n,r,i,a){lr(n.args);let o=vn(a),s=K(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=yn({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await qt({code:n.script,surface:`workflow`,cwd:o,bindings:Ft({cwd:o,names:s,includeDispatch:!0}),...u===void 0?{}:{sessionDir:u},...d===void 0?{}:{dispatchDeps:d},...n.args===void 0?{}:{args:n.args},...e.depth===void 0?{}:{depth:e.depth},...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>f.update(e)})}finally{f.cancel()}if(p.error!==void 0)throw xn(p);let m=n.meta.phases?.map(e=>e.name);return Sn({outcome:p,surface:`workflow`,warnings:dr(p,m),durationMs:Date.now()-c})},...rr(`workflow`)})}var pr=class{#e;constructor(e){this.#e=new Map(e??[])}async readOutput(e){let t=this.#e.get(e);return t===void 0?null:t}async writeOutput(e,t){this.#e.set(e,t)}outputRef(e){return`memory:tasks/${e}/output.log`}};function mr(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var hr=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await fe(this.#t(e),`utf8`)}catch(e){if(mr(e))return null;throw e}}async writeOutput(e,t){let n=k(this.#e,`tasks`,e);await de(n,{recursive:!0}),await ge(k(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return k(this.#e,`tasks`,e,`output.log`)}};function gr(e,t){return en(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const _r={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},vr={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var Y=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>yr(e,t))}};function yr(e,t){let{left:n,right:r}=e;if(r===void 0)return P(n,t,`…`);let i=F(r);if(i>=t)return P(r,t,`…`);let a=P(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-F(a));return a+` `.repeat(o)+r}function br(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function xr(e){return br((G(e).split(`
30
- `).find(e=>e.trim().length>0)??``).trim(),120)}function Sr(e){return typeof e==`object`&&e?e:{}}function Cr(e){return e===`running`||e===`stopping`}function wr(e){let t=Math.max(0,Math.floor(e));if(t<1e3)return`${t}ms`;let n=Math.floor(t/1e3);if(n<60)return`${n}s`;let r=Math.floor(n/60),i=n%60;return r<60?`${r}m${i}s`:`${Math.floor(r/60)}h${String(r%60).padStart(2,`0`)}m`}function Tr(e,t){if(Cr(e.status))return wr(t-e.createdAt);if(e.durationMs!==void 0)return wr(e.durationMs);if(e.finishedAt!==void 0)return wr(e.finishedAt-e.createdAt)}function Er(e,t){let{state:n}=t;t.isLive?n.interval??=setInterval(()=>t.requestInvalidate(),1e3):n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0);let r=e;return r.dispose=()=>{n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0)},e}function Dr(){}function Or(e,t,n){return new Y([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function kr(e,t,n){let r=Sr(t);switch(e){case`task-list`:{let e=Array.isArray(r.status)?r.status:void 0,t=e!==void 0&&e.length>0?e.join(`,`):`all`,i=typeof r.limit==`number`?` · limit=${r.limit}`:``;return Or(`PTC task list`,n.fg(`dim`,`status=${t}${i}`),n)}case`task-output`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.sinceBytes==`number`?` · since=${r.sinceBytes}B`:``;return Or(`PTC task output`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}case`task-stop`:{let e=typeof r.taskId==`string`&&r.taskId.length>0?r.taskId:void 0,t=typeof r.reason==`string`&&r.reason.length>0?` · reason=${G(r.reason)}`:``;return Or(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Ar(e,t,n,r){let i=_r[e.status]??`muted`,a=n.fg(i,vr[e.status]??`?`),o=br(G(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,G(e.agentName))],c=Tr(e,r);return c!==void 0&&s.push(n.fg(`dim`,c)),e.outputBytes!==void 0&&s.push(n.fg(`dim`,`${e.outputBytes}B`)),{left:` ${t?`└─ `:`├─ `}${s.join(n.fg(`dim`,` · `))}`}}function jr(e,t){let n=Sr(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Er(new Y([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>Cr(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>Ar(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Er(new Y(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Mr(e,t,n){let r=[];if(e!==void 0&&r.push(n.fg(`dim`,`${e}B`)),t&&r.push(n.fg(`warning`,`truncated`)),r.length!==0)return`${n.fg(`dim`,`•`)} ${r.join(n.fg(`dim`,` · `))}`}function Nr(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Pr(e,t){let n=Sr(e),r=typeof n.output==`string`?n.output:``,i=typeof n.outputBytes==`number`?n.outputBytes:void 0,a=n.outputTruncated===!0,o=typeof n.outputFullPath==`string`&&n.outputFullPath.length>0?n.outputFullPath:void 0,s=Mr(i,a,t.theme),c=[];if(r.length>0){let e=G(r).split(`
31
- `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,br(e,160));c.push(n===0&&s!==void 0?{left:` ${r}`,right:s}:{left:` ${r}`})}),e.length>n.length&&c.push({left:` ${t.theme.fg(`dim`,`…+${e.length-n.length} more lines`)}`}),a&&o!==void 0&&c.push({left:Nr(o,t.theme)})}else o===void 0?c.push({left:` ${t.theme.fg(`muted`,`(no output yet)`)}`,...s===void 0?{}:{right:s}}):c.push({left:Nr(o,t.theme),...s===void 0?{}:{right:s}});return new Y(c)}function Fr(e,t){let n=Sr(e),r=n.task;if(typeof r!=`object`||!r)return new Y([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=_r[r.status]??`muted`,a=t.theme.fg(i,vr[r.status]??`?`),o=typeof n.fromStatus==`string`?n.fromStatus:void 0,s=o===void 0?r.status===`stopping`?`running → stopping`:`→ ${String(r.status)}`:`${o} → ${r.status}`,c=[`${a} ${t.theme.fg(`text`,G(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${G(r.stopReason)}`)),new Y([{left:` ${c.join(` `)}`}])}function Ir(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=xr(n?.text??``)||`failed`;return new Y([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Lr(e,t,n){switch(e){case`task-list`:return jr(t.details,n);case`task-output`:return Pr(t.details,n);case`task-stop`:return Fr(t.details,n)}}function Rr(e){return{renderCall(t,n){return kr(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Ir(t,r):Lr(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Dr,state:i?.state??{},now:Date.now()})}}}const zr=[`Use ptc_task_list to see the background tasks this session dispatched and their live status.`,`Use ptc_task_output to read a task's captured output (it is tail-truncated; the footer names the full-output file).`,`Use ptc_task_stop to ask a running task to stop; the dispatcher delivers the actual signal, so the task transitions through stopping to canceled.`,`These background-task tools stay callable when PTC mode is off — /ptc off only blocks new dispatches.`],Br=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Vr=x.Object({status:x.Optional(x.Array(Br,{description:`Only return tasks in these states. Omit for all six states (running, stopping, succeeded, failed, canceled, lost).`})),limit:x.Optional(x.Number({description:`Maximum number of tasks to return, newest first. Defaults to 100.`}))});function Hr(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,G(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${G(e.errorMessage)}`),t.join(` `)}function Ur(e){return g({name:`ptc_task_list`,label:`PTC Task List`,description:[`List the background tasks this session has dispatched (from pi.dispatch({ background: true })).`,`Returns each task's id, status, agent, depth, label and output size, newest first.`,`Filter with status (e.g. ["running"]); limit caps the row count (default 100).`].join(`
32
- `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...zr],parameters:Vr,async execute(t,n){let r=await e.query({...n.status===void 0?{}:{status:n.status},limit:n.limit??100,orderBy:`createdAt-desc`});return{content:[{type:`text`,text:r.length===0?`(no background tasks)`:r.map(e=>Hr(e)).join(`
33
- `)}],details:{tasks:r,count:r.length}}},...Rr(`task-list`)})}async function Wr(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}const Gr=x.Object({taskId:x.String({description:`The background task's id (as returned by ptc_task_list or the dispatch handle).`}),sinceBytes:x.Optional(x.Number({description:`Skip this many bytes of the stored output before returning it. Use for paging larger logs; defaults to 0.`}))});function Kr(e,t){return g({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
34
- `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...zr],parameters:Gr,async execute(n,r){let i=r.taskId,a=await Wr(e,i,`ptc_task_output`),o=await t.readOutput(i)??``,s=Buffer.byteLength(o,`utf8`),c=r.sinceBytes??0;if(!Number.isInteger(c)||c<0)throw Error(`ptc_task_output: sinceBytes must be a non-negative integer, got ${String(r.sinceBytes)}`);if(c>s)throw Error(`ptc_task_output: sinceBytes ${c} exceeds the ${s}-byte output of task ${i}`);let l=Buffer.from(o,`utf8`);if(c<s&&((l[c]??0)&192)==128)throw Error(`ptc_task_output: sinceBytes ${c} splits a UTF-8 character in task ${i}; use a byte offset on a character boundary`);let u=gr(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath}};return{content:[{type:`text`,text:f.output.length>0?f.output:`(no output yet; task ${i} is ${a.status})`}],details:f}},...Rr(`task-output`)})}const qr=x.Object({taskId:x.String({description:`The running task's id (as returned by ptc_task_list or the dispatch handle).`}),reason:x.Optional(x.String({description:`Why the task is being stopped; recorded as the task's stopReason. Defaults to "model stop".`}))});function Jr(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return g({name:`ptc_task_stop`,label:`PTC Task Stop`,description:[`Ask a running background task to stop.`,`The task moves to "stopping"; the dispatcher sends the signal and records the terminal "canceled" state when the child exits.`,`The call is idempotent when the task is already stopping, and errors when the task is already terminal.`].join(`
35
- `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...zr],parameters:qr,async execute(t,n){let i=n.taskId,a=await Wr(e,i,`ptc_task_stop`),o=a.spawnSource.callerId.length>0?a.spawnSource.callerId:`ptc_task_stop`,{record:s,fromStatus:c}=await e.transition({kind:`stop`,taskId:i,reason:n.reason??`model stop`},{clock:r,callerId:o}),l=s.stopReason===void 0?``:` reason=${G(s.stopReason)}`;return{content:[{type:`text`,text:`${s.id} ${s.status}${l}`}],details:{task:s,fromStatus:c??a.status}}},...Rr(`task-stop`)})}var Yr=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=L(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Ne(),r=new Rt({buildWorkerUrl:Vt,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:Lt({surface:e,env:n,limits:this.#e})});return this.#t.set(e,r),r}async drain(){let e=[...this.#t.values()];this.#t.clear(),await Promise.all(e.map(e=>e.drain()))}};const Xr={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var Zr=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??Xr,this.#r=[],this.#i=/* @__PURE__ */ new Map}async subscribe(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r!==null)return r;let i={subscriberId:e,taskId:t,cursor:n??`00000000000000000000`,status:`active`,createdAt:this.#t()};return await this.#e.saveSubscription(i),i}async drainPending(e,t){let n=await this.#o(e,t,`drainPending`);return this.#s(n)}async acknowledgeEvents(e,t,n){await this.#a(e,t,async()=>{let r=await this.#o(e,t,`acknowledgeEvents`);n<=r.cursor||await this.#e.saveSubscription({...r,cursor:n})})}#a(e,t,n){let r=`${e}-${t}`,i=(this.#i.get(r)??Promise.resolve()).then(n),a=i.then(()=>void 0,()=>void 0);return this.#i.set(r,a),a.then(()=>{this.#i.get(r)===a&&this.#i.delete(r)}),i}onIdleWake(e){this.#r.push(e)}async pendingCount(e,t){let n=await this.#o(e,t,`pendingCount`);return(await this.#s(n)).length}async notifyIdle(e,t){let n=await this.drainPending(e,t);if(n.length===0)return n;let r=this.#r.slice();for(let i of r)try{i(e,n)}catch(n){let r=n instanceof Error?n.message:String(n);this.#n.warn(`notifyIdle: idle-wake handler for subscriber ${e} / task ${t} threw: ${r}`)}return n}async#o(e,t,n){let r=await this.#e.loadSubscription(e,t);if(r===null)throw Error(`${n}: unknown subscription for subscriber ${e} / task ${t}`);return r}async#s(e){let t=[];for await(let n of this.#e.loadEvents(e.subscriberId,e.cursor===`00000000000000000000`?void 0:e.cursor))n.taskId===e.taskId&&t.push(n);return t}};const Qr={mkdir:(e,t)=>de(e,t),readFile:(e,t)=>fe(e,t),writeFile:(e,t,n)=>ge(e,t,n),appendFile:(e,t,n)=>ue(e,t,n),rename:(e,t)=>me(e,t),unlink:e=>he(e),readdir:e=>pe(e)};function $r(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function ei(e){return e instanceof Error?e.message:String(e)}function ti(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var ni=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??Qr}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){M(e,`saveTask: record is required`),await this.#o(this.#f(e.id),e)}async deleteTask(e){let t=this.#f(e);if(!await this.#c(t))throw Error(`deleteTask: unknown taskId `+e);await this.#t.unlink(t)}async*listTasks(e){let t=this.#l();for(let n of(await this.#s(t)).sort()){if(!n.endsWith(`.json`))continue;let r=await this.#r(k(t,n));r!==null&&(e?.status===void 0||r.status===e.status)&&(e?.label===void 0||r.label===e.label)&&(yield r)}}async loadSubscription(e,t){return await this.#r(this.#p(e,t))}async saveSubscription(e){M(e,`saveSubscription: sub is required`),await this.#o(this.#p(e.subscriberId,e.taskId),e)}async appendEvents(e,t){if(t.length===0){if((await this.#n(e)).length===0)throw Error(`appendEvents: unknown subscriptionId `+e);return}let n=/* @__PURE__ */ new Map;for(let e of t){let t=n.get(e.taskId);t===void 0?n.set(e.taskId,[e]):t.push(e)}let r;for(let t of n.keys())if(await this.loadSubscription(e,t)===null){r=t;break}if(r!==void 0)throw(await this.#n(e)).length===0?Error(`appendEvents: unknown subscriptionId `+e):Error(`appendEvents: no subscription for subscriber `+e+` on task `+r);await this.#t.mkdir(this.#d(),{recursive:!0});for(let[t,r]of n){let n=(r.every((e,t)=>t===0||ti(r[t-1],e)<=0)?r:[...r].sort(ti)).map(e=>JSON.stringify(e)).join(`
16
+ `)}function yn(e){if(typeof e==`string`)return vn(W(e));if(typeof e!=`object`||!e)return String(e);let t=mn(e);return vn((t===void 0?_n(e,``):[t]).join(`
17
+ `))}function bn(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function xn(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 G(e){if(e===void 0)return z;let t=new Set(e);return z.filter(e=>t.has(e))}const Sn=["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.`],Cn={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function wn(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function Tn(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 En(e){return[...e.phases.map(e=>`[phase] ${W(e)}`),...e.narrations.map(e=>`[log] ${W(e)}`),...e.logs.map(e=>W(e))]}function Dn(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=En(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
18
+ `)}`,i=Error(W(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function On(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(`
19
+ `)),t.logs.length>0&&a.push(t.logs.map(e=>W(e)).join(`
20
+ `)),t.value!==void 0&&a.push(yn(t.value));for(let e of r)a.push(`Warning: ${W(e)}`);let o=sn(a.length>0?a.join(`
21
+ `):`(${Cn[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 kn=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function An(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function jn(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 Mn(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=jn(e,n):(n+=1,r+=1);return n}function Nn(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:Pn(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 Pn(e,t,n){return e.map(e=>{let r=An(e),i=kn.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=Mn(e,s),l=Mn(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 Fn={run_code:`PTC`,workflow:`PTC workflow`};var In=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>Ln(e,t))}};function Ln(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 K(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Rn(e){return K((W(e).split(`
22
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function zn(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function Bn(e,t){return`${e} ${t}${e===1?``:`s`}`}function Vn(e){for(let t of e.split(`
23
+ `)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return K(e.replace(/\s*\/\/.*$/,``),120)}}function Hn(e){if(e===void 0)return;if(typeof e==`string`){let t=W(e).split(`
24
+ `),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=yn(e);if(!t.includes(`
25
+ `)&&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 Un(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,Bn(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,Bn(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,Bn(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,Bn(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,zn(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Wn(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 Gn(e,t,n){let r=` `+(t?`└─ `:`├─ `),i=` `+(t?` `:`│ `),a=` `.repeat(8),o=[],s=e.lines[0]??``;o.push({left:`${r}${e.label.padEnd(8)}${n.fg(`dim`,s)}`});for(let t=1;t<e.lines.length;t++)o.push({left:`${i}${a}${n.fg(`dim`,e.lines[t]??``)}`});return e.more!==void 0&&e.more>0&&o.push({left:`${i}${a}…+${e.more} more lines`}),o}function Kn(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const qn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Jn(e){return qn.test(e)?e:JSON.stringify(e)}function Yn(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(`
26
+ `)){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 Xn(e){return typeof e!=`object`||!e}function Zn(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Xn))return;let n=`[`+e.map(e=>Yn(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(Xn))return;let r=`{`+n.map(n=>{let r=e[n]??null;return Jn(n)+`: `+Yn(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Qn(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-I(l)-t.length);c.push(q(l+t+Yn(e,n),o));return}let d=Zn(e,Math.max(0,o-I(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;Qn(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];Qn(e[l]??null,Jn(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(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 $n(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Kn(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Yn(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;Qn(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];Qn(e[d]??null,Jn(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}function er(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Vn(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return Nn(new In([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(Fn[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??tr,state:r.state??{}})}function tr(){}function nr(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Rn(t?.text??``)||`failed`}function rr(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t&&`agent`in t)return`→ ${String(t.agent)}`;if(typeof t==`object`&&t){let n=t,r=e=>typeof n[e]==`string`?n[e]:void 0,i=e===`read`?r(`path`):e===`bash`?r(`command`):e===`grep`||e===`find`?r(`pattern`):e===`ls`||e===`edit`||e===`write`?r(`path`):void 0;if(typeof i==`string`)return i}try{let e=JSON.stringify(t).replace(/\n/g,` `);return e.length>40?`${e.slice(0,39)}…`:e}catch{return String(t).slice(0,40)}}const ir={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${zn(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 ar(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=rr(e.name,e.args),l=ir[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 or(e,t,n,r=!1,i=!1){let a=Un(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${nr(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(Kn(s))return $n(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=Hn(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function sr(e,t,n,r={}){let i=Wn(e.details),a=[...or({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...ar(i.subCalls,n)),new In(a)}function cr(e,t,n,r,i={}){let a=Wn(e.details);if(n){let t=[...or({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...ar(a.subCalls,r));let n=W(e.content?.find(e=>e.type===`text`)?.text??nr(e));for(let e of n.split(`
27
+ `).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new In(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
28
+ `).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=>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=or({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...ar(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...Gn(o[e]??{label:``,lines:[]},t,r))}return new In(u)}function lr(e){return{renderCall(t,n,r){return er(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?cr(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):sr(e,r?.isError===!0,n,{isPartial:i})}}}const ur=["Run a TypeScript program that composes pi's tools in one shot. Required arguments: `code` —","the body of an async function (top-level `return` and `await` work; type annotations are","advisory, the code runs type-stripped) — and `description`, a 5-10 word summary of what the",`program does.`,``,"Inside the program, call this session's enabled built-in tools as `tools.<name>(args)` — e.g.",'`await tools.read({ path: "src/index.ts" })` or `await tools.bash({ command: "npm test" })`.',"The bound names mirror the session's active tools (a default session has `read`, `bash`, `edit`,","`write`); independent calls may overlap under `Promise.all`.",``,"The parallel binding `pi.dispatch` is always available, registered under its literal dot name —",'call it with string indexing, e.g. `await tools["pi.dispatch"]({ agent: "reviewer", task: "..." })`;',"`tools.pi.dispatch` does not exist. It fans work out to child pi agents, and independent","foreground dispatches compose under `Promise.all` exactly like the built-in calls. The run's","actual bound names (this run, not a static list) are on the `ptcBindings` global, so the program",`never has to guess what is bound.`,``,nn,``,"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(`
29
+ `),dr=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 ${L.timeoutMs/1e3} s; anything above ${L.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 fr(e={}){return g({name:`ptc_run_code`,label:`PTC Run Code`,description:ur,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:[...Sn],parameters:dr,async execute(t,n,r,i,a){let o=wn(a),s=G(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=Tn({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await $t({code:n.code,surface:`run_code`,cwd:o,bindings:Vt({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 Dn(p);return On({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...lr(`run_code`)})}const pr=[`Run a structured TypeScript workflow: a named plan that reports phases and narration as it`,"goes. `script` is the body of an async function, `meta` names it (`{ name, description, phases? }`,","where `phases` is the ordered plan), and optional `args` is plain-JSON input bound to the","program's `args` global.",``,"Helpers inside the script: `log(message)` narrates progress; `phase(title)` frames the workflow","(titles outside `meta.phases` are reported as warnings); `parallel(thunks)` runs thunks","concurrently, a failed item becoming `null`; `pipeline(items, ...stages)` chains stages per item","with the same per-item `null` on failure. There is no `agent()` helper.",``,"Tools are reachable as `tools.<name>(args)` exactly as in `ptc_run_code`, and the bound names","mirror the session's enabled tools. The parallel binding `pi.dispatch` is always available under",'its literal dot name — call it with string indexing: `await tools["pi.dispatch"]({ agent, task })`;',"the run's actual bound names are on the `ptcBindings` global. What comes back is the script's","return value, its `log`/`phase` narration and its `console.log` output.",``,nn,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
30
+ `),mr=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 hr(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=gr(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function gr(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=gr(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=gr(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function _r(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 vr(e={}){return g({name:`ptc_workflow`,label:`PTC Workflow`,description:pr,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...Sn],parameters:mr,async execute(t,n,r,i,a){hr(n.args);let o=wn(a),s=G(e.getBindingSourceNames?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=Tn({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await $t({code:n.script,surface:`workflow`,cwd:o,bindings:Vt({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 Dn(p);let m=n.meta.phases?.map(e=>e.name);return On({outcome:p,surface:`workflow`,warnings:_r(p,m),durationMs:Date.now()-c})},...lr(`workflow`)})}var yr=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 br(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var xr=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(br(e))return null;throw e}}async writeOutput(e,t){let n=D(this.#e,`tasks`,e);await pe(n,{recursive:!0}),await ve(D(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return D(this.#e,`tasks`,e,`output.log`)}};function Sr(e,t){return sn(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const Cr={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},wr={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=>Tr(e,t))}};function Tr(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 Er(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Dr(e){return Er((W(e).split(`
31
+ `).find(e=>e.trim().length>0)??``).trim(),120)}function Or(e){return typeof e==`object`&&e?e:{}}function kr(e){return e===`running`||e===`stopping`}function Ar(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 jr(e,t){if(kr(e.status))return Ar(t-e.createdAt);if(e.durationMs!==void 0)return Ar(e.durationMs);if(e.finishedAt!==void 0)return Ar(e.finishedAt-e.createdAt)}function Mr(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 Nr(){}function Pr(e,t,n){return new J([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function Fr(e,t,n){let r=Or(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 Pr(`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 Pr(`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 Pr(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Ir(e,t,n,r){let i=Cr[e.status]??`muted`,a=n.fg(i,wr[e.status]??`?`),o=Er(W(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,W(e.agentName))],c=jr(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 Lr(e,t){let n=Or(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Mr(new J([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>kr(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>Ir(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Mr(new J(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Rr(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 zr(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function Br(e,t){let n=Or(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=Rr(i,a,t.theme),c=[];if(r.length>0){let e=W(r).split(`
32
+ `),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,Er(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:zr(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:zr(o,t.theme),...s===void 0?{}:{right:s}});return new J(c)}function Vr(e,t){let n=Or(e),r=n.task;if(typeof r!=`object`||!r)return new J([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=Cr[r.status]??`muted`,a=t.theme.fg(i,wr[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 J([{left:` ${c.join(` `)}`}])}function Hr(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=Dr(n?.text??``)||`failed`;return new J([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Ur(e,t,n){switch(e){case`task-list`:return Lr(t.details,n);case`task-output`:return Br(t.details,n);case`task-stop`:return Vr(t.details,n)}}function Wr(e){return{renderCall(t,n){return Fr(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Hr(t,r):Ur(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Nr,state:i?.state??{},now:Date.now()})}}}const Gr=[`Use ptc_task_list to see the background tasks this session dispatched and their live status.`,`Use ptc_task_output to read a task's captured output (it is tail-truncated; the footer names the full-output file).`,`Use ptc_task_stop to ask a running task to stop; the dispatcher delivers the actual signal, so the task transitions through stopping to canceled.`,`These background-task tools stay callable when PTC mode is off — /ptc off only blocks new dispatches.`],Kr=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),qr=x.Object({status:x.Optional(x.Array(Kr,{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.`}))}),Jr=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 Yr(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 Xr(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 Zr(e){return g({name:`ptc_task_list`,label:`PTC Task List`,description:[`List the background tasks this session has dispatched (from pi.dispatch({ background: true })).`,`Returns each task's id, status, agent, depth, label and output size, newest first.`,`Filter with status (e.g. ["running"]); limit caps the row count (default 100).`].join(`
33
+ `),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...Gr],parameters:qr,outputSchema:Jr,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=>Xr(e)).join(`
34
+ `),a={tasks:r.map(e=>Yr(e)),count:r.length};return{content:[{type:`text`,text:i}],details:{tasks:r,count:r.length},structuredContent:a}},...Wr(`task-list`)})}async function Qr(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}const $r=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.`}))}),ei=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)."}))});function ti(e,t){return g({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
35
+ `),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...Gr],parameters:$r,outputSchema:ei,async execute(n,r){let i=r.taskId,a=await Qr(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=Sr(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath}},p=f.output.length>0?f.output:`(no output yet; task ${i} is ${a.status})`,m={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}};return{content:[{type:`text`,text:p}],details:f,structuredContent:m}},...Wr(`task-output`)})}const ni=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".`}))}),ri=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 ii(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return g({name:`ptc_task_stop`,label:`PTC Task Stop`,description:[`Ask a running background task to stop.`,`The task moves to "stopping"; the dispatcher sends the signal and records the terminal "canceled" state when the child exits.`,`The call is idempotent when the task is already stopping, and errors when the task is already terminal.`].join(`
36
+ `),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...Gr],parameters:ni,outputSchema:ri,async execute(t,n){let i=n.taskId,a=await Qr(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}},...Wr(`task-stop`)})}var ai=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=Le(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Ie(),r=new Wt({buildWorkerUrl:qt,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:Ut({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 oi={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var si=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??oi,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 ci={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 li(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function ui(e){return e instanceof Error?e.message:String(e)}function di(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var fi=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??ci}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){M(e,`saveTask: record is required`),await this.#o(this.#f(e.id),e)}async deleteTask(e){let t=this.#f(e);if(!await this.#c(t))throw Error(`deleteTask: unknown taskId `+e);await this.#t.unlink(t)}async*listTasks(e){let t=this.#l();for(let n of(await this.#s(t)).sort()){if(!n.endsWith(`.json`))continue;let r=await this.#r(D(t,n));r!==null&&(e?.status===void 0||r.status===e.status)&&(e?.label===void 0||r.label===e.label)&&(yield r)}}async loadSubscription(e,t){return await this.#r(this.#p(e,t))}async saveSubscription(e){M(e,`saveSubscription: sub is required`),await this.#o(this.#p(e.subscriberId,e.taskId),e)}async appendEvents(e,t){if(t.length===0){if((await this.#n(e)).length===0)throw Error(`appendEvents: unknown subscriptionId `+e);return}let n=/* @__PURE__ */ new Map;for(let e of t){let t=n.get(e.taskId);t===void 0?n.set(e.taskId,[e]):t.push(e)}let r;for(let t of n.keys())if(await this.loadSubscription(e,t)===null){r=t;break}if(r!==void 0)throw(await this.#n(e)).length===0?Error(`appendEvents: unknown subscriptionId `+e):Error(`appendEvents: no subscription for subscriber `+e+` on task `+r);await this.#t.mkdir(this.#d(),{recursive:!0});for(let[t,r]of n){let n=(r.every((e,t)=>t===0||di(r[t-1],e)<=0)?r:[...r].sort(di)).map(e=>JSON.stringify(e)).join(`
36
37
  `)+`
37
- `;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(ti);for(let e of r)t!==void 0&&e.eventId<=t||(yield e)}async#n(e){let t=this.#u(),n=[];for(let r of await this.#s(t)){if(!r.endsWith(`.json`))continue;let i=await this.#r(k(t,r));i!==null&&i.subscriberId===e&&n.push(i)}return n}async#r(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if($r(e))return null;throw e}return this.#i(e,t)}#i(e,t){let n;try{n=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt JSON in `+e+`: `+ei(t))}if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`FileTaskStorage: corrupt JSON in `+e+`: expected a JSON object`);return n}async#a(e){let t;try{t=await this.#t.readFile(e,{encoding:`utf8`})}catch(e){if($r(e))return[];throw e}let n=[];for(let r of t.split(`
38
- `)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+ei(t))}if(typeof i!=`object`||!i||Array.isArray(i))throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: expected a JSON object`);n.push(i)}return n}async#o(e,t){await this.#t.mkdir(O(e),{recursive:!0});let n=e+`.tmp-`+j();await this.#t.writeFile(n,JSON.stringify(t,null,2),{encoding:`utf8`}),await this.#t.rename(n,e)}async#s(e){try{return await this.#t.readdir(e)}catch(e){if($r(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if($r(e))return!1;throw e}}#l(){return k(this.#e,`tasks`)}#u(){return k(this.#e,`subscriptions`)}#d(){return k(this.#e,`events`)}#f(e){return k(this.#l(),e+`.json`)}#p(e,t){return k(this.#u(),e+`-`+t+`.json`)}#m(e,t){return k(this.#d(),e+`-`+t+`.jsonl`)}};function ri(e,t){return new ni(e,t)}const ii=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),ai=/* @__PURE__ */ new Set([`running`,`stopping`]),oi=2**53-1,si={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function X(e){return e instanceof Error?e.message:String(e)}function ci(e){return e===void 0||e.length===0?`<in-memory>`:e}function li(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var ui=class{#e;#t=/* @__PURE__ */ new Map;constructor(e){this.#e=e}setCurrent(e){this.#e=e}async transition(e,t){let n=e.kind===`spawn`?this.#e:this.#t.get(e.taskId)??this.#e,r=await n.transition(e,t);return e.kind===`spawn`&&this.#t.set(r.record.id,n),r}query(e){return this.#e.query(e)}get(e){return this.#e.get(e)}onTransition(e){return this.#e.onTransition(e)}reconcileLostTasks(){return this.#e.reconcileLostTasks()}},di=class{#e;constructor(e){this.#e=e}setCurrent(e){this.#e=e}readOutput(e){return this.#e.readOutput(e)}writeOutput(e,t){return this.#e.writeOutput(e,t)}outputRef(e){return this.#e.outputRef(e)}},fi=class{#e;#t=[];constructor(e){this.#e=e}setCurrent(e){this.#e=e;for(let t of this.#t)e.onIdleWake(t)}current(){return this.#e}subscribe(e,t,n){return this.#e.subscribe(e,t,n)}drainPending(e,t){return this.#e.drainPending(e,t)}acknowledgeEvents(e,t,n){return this.#e.acknowledgeEvents(e,t,n)}onIdleWake(e){this.#t.push(e),this.#e.onIdleWake(e)}pendingCount(e,t){return this.#e.pendingCount(e,t)}notifyIdle(e,t){return this.#e.notifyIdle(e,t)}},pi=class{#e;#t=/* @__PURE__ */ new Set;#n=/* @__PURE__ */ new Map;constructor(e){this.#e=e}isLive(e){return this.#t.has(e)}trackReapCancel(e,t){this.#n.set(e,t)}spawn(e,t){let n=this.#e.spawn(e,t);return this.#t.add(n),n}kill(e,t){this.#e.kill(e,t)}events(e){return this.#e.events(e)}async exit(e){try{return await this.#e.exit(e)}finally{this.#t.delete(e);let t=this.#n.get(e);t!==void 0&&(this.#n.delete(e),t())}}stderr(e){return this.#e.stderr(e)}liveHandles(){return[...this.#t]}},mi=class{registry;outputStorage;pipeline;slots;lifecycle;dispatchDeps;clock;#e;#t;#n;#r;#i;#a=!1;constructor(e){this.clock=e.clock??(()=>Date.now()),this.#e=e.logger??si,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??We,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new Xe:ri(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new pr:new hr(e));let t=(e.createInitialStorage??(()=>new Xe))(),n=qe(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new Zr(t,{now:this.clock,logger:this.#e});this.registry=new ui(n),this.outputStorage=new di(new pr),this.pipeline=new fi(r),this.lifecycle=new pi((e.createLifecycle??(()=>new je({logger:this.#e})))()),this.slots=new Ze(e.concurrency??I.dispatchConcurrency),this.dispatchDeps={taskRegistry:this.registry,lifecycle:this.lifecycle,slots:this.slots,outputStorage:this.outputStorage,clock:this.clock,logger:this.#e},this.registry.onTransition(this.#o)}#o=(e,t)=>{this.#a||ii.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+X(t))})};async bindSession(e,t){let n,r;try{n=this.#t(e),r=this.#n(e)}catch(n){return this.#s(`background runtime: session storage for `+ci(e)+` is unavailable: `+X(n),t),[]}let i=qe(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new Zr(n,{now:this.clock,logger:this.#e});this.registry.setCurrent(i),this.outputStorage.setCurrent(r),this.pipeline.setCurrent(a),this.#a=!1;try{return await i.reconcileLostTasks()}catch(e){return this.#s(`background runtime: startup reconcile failed; stale running tasks were not all marked lost (reconcile is not per-record tolerant yet): `+X(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:oi})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+X(t)),{items:[],acks:[]}}let n=[],r=[],i=this.pipeline.current();for(let a of t){if(a.spawnSource.callerId!==e)continue;let t;try{t=await i.drainPending(e,a.id)}catch(t){this.#e.warn(`drainNotifications: task `+a.id+` for subscriber `+e+`: `+X(t));continue}for(let e of t)n.push({event:e,record:a});let o=t[t.length-1];o!==void 0&&r.push({subscriberId:e,taskId:a.id,cursor:o.eventId,sink:i})}return{items:n,acks:r}}async acknowledgeNotifications(e){for(let t of e)try{await t.sink.acknowledgeEvents(t.subscriberId,t.taskId,t.cursor)}catch(e){this.#e.warn(`acknowledgeNotifications: could not acknowledge task `+t.taskId+`: `+X(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:oi})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+X(e)),t=[]}let n=[];for(let r of t)if(ai.has(r.status)&&Ue(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:li(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+X(e))}for(let e of this.lifecycle.liveHandles()){let t=z(this.lifecycle,e,{isDone:()=>!this.lifecycle.isLive(e),unref:!0});this.lifecycle.trackReapCancel(e,t)}for(let e of n)this.slots.release(e.id);return n}#s(e,t){if(this.#e.warn(e),t!==void 0)try{t(e)}catch(e){this.#e.warn(`bindSession reporter threw: `+X(e))}}};function hi(e={}){return new mi(e)}const gi=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function _i(e){return gi.has(e.status)}function vi(e,t){if(e.length===0)return``;let n=e.map(bi).join(`
39
- `);return`${`<bg-task-notifications batch-id="${Z(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function yi(e,t=102400){let n=[],r=[],i=0,a=t-Si;for(let t of e){let e=xi(t);r.length>0&&i+1+e>a&&(n.push(r),r=[],i=0),r.length>0&&(i+=1),r.push(t),i+=e}return r.length>0&&n.push(r),n}function bi(e){let{event:t,record:n}=e,r=t.outputBytes??n.outputBytes,i=r??0,a=t.outputPreview??n.outputPreview,o=[` <bg-task-notification`,` id="${Z(t.type)}"`,` task-id="${Z(t.taskId)}"`,` subscription-id="${Z(t.subscriptionId)}"`,` status="${Z(t.status)}"`,` label="${Z(n.label)}"`,` agent-name="${Z(n.agentName)}"`,` depth="${n.depth}"`,` duration-ms="${n.durationMs??0}"`,` transition-at-ms="${t.transitionAtMs}">`,` <output-bytes>${i}</output-bytes>`];return n.outputRef!==void 0&&o.push(` <output-ref>${Z(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${Z(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
40
- `)}function Z(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
41
- `,`&#10;`).replaceAll(`\r`,`&#13;`)}function xi(e){return Buffer.byteLength(bi(e),`utf8`)}const Si=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),Ci=[`ptc_run_code`,`ptc_workflow`],wi=[`read`,`bash`,`edit`,`write`],Q=`ptc-mode`,Ti=`ptc-mode`,Ei=`ptc.json`,Di=`builtins-only`;function Oi(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function ki(e){let t=k(e,Ei),n;try{n=T(t,`utf8`)}catch{return{defaultMode:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch(e){return{defaultMode:!0,source:`invalid`,error:`${t} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof r!=`object`||!r||Array.isArray(r))return{defaultMode:!0,source:`invalid`,error:`${t} must contain a JSON object`};let i=r.defaultMode;return i===void 0?{defaultMode:!0,source:`default`}:typeof i==`boolean`?{defaultMode:i,source:`file`}:{defaultMode:!0,source:`invalid`,error:`${t}: "defaultMode" must be a boolean, received ${typeof i}`}}const Ai=[`off`,`subagents`,`full`];function ji(e){return e.present?`subagents`:`full`}function Mi(e=process.argv){let t=e[1];if(t===void 0||t===``)return{present:!1,how:`no-entry`};let n;try{n=ee(t)}catch{return{present:!1,how:`unresolvable-entry`}}let r=O(n);for(let e of Ni){let t=k(r,...e);try{if(E(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const Ni=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function Pi(e,t){let n=k(e,Ei),r=()=>{let e=t??Mi();return{surfaceMode:ji(e),codemode:e}},i;try{i=T(n,`utf8`)}catch{return{...r(),source:`default`}}let a;try{a=JSON.parse(i)}catch(e){return{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof a!=`object`||!a||Array.isArray(a))return{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n} must contain a JSON object`};let o=a.surfaceMode;return o===void 0?{...r(),source:`default`}:typeof o==`string`?Ai.includes(o)?{surfaceMode:o,source:`file`}:{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n}: "surfaceMode" must be one of ${Ai.join(` | `)}, received ${JSON.stringify(o)}`}:{surfaceMode:r().surfaceMode,source:`invalid`,error:`${n}: "surfaceMode" must be a string, received ${typeof o}`}}function Fi(e){return[...new Set(e)]}function Ii(e,t){if(e.length!==t.length)return!1;let n=[...e].sort(),r=[...t].sort();return n.every((e,t)=>e===r[t])}function Li(e,t){let n=e=>Ci.includes(e);if(t===`all-but-ptc`)return Fi(e.filter(n));let r=new Set(B);return Fi(e.filter(e=>n(e)||!r.has(e)))}function Ri(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:Ci.some(e=>r.includes(e))?!i&&wi.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:Fi(r),loadout:Li(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function zi(e,t){return e.enabled&&e.base!==void 0?e.base:t}function Bi(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!Ii(e.ourLoadout,t)}function Vi(e,t){let n=t.length>0&&t.every(e=>Ci.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function Hi(e,t){let n=t===`all-but-ptc`?`Every built-in tool is hidden from you, and so are other extensions' tools.`:`The built-in tools (read, bash, edit, write, grep, find, ls) are hidden from you.`,r=e.map(e=>`tools.${e}(args)`),i=e.slice(0,2).map(e=>e===`read`?`await tools.read({ path: "src/index.ts" })`:e===`bash`?`await tools.bash({ command: "pnpm test" })`:`await tools.${e}({ /* … */ })`).join(`
38
+ `;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(di);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(D(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(li(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+`: `+ui(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(li(e))return[];throw e}let n=[];for(let r of t.split(`
39
+ `)){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+`: `+ui(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(oe(e),{recursive:!0});let n=e+`.tmp-`+j();await this.#t.writeFile(n,JSON.stringify(t,null,2),{encoding:`utf8`}),await this.#t.rename(n,e)}async#s(e){try{return await this.#t.readdir(e)}catch(e){if(li(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(li(e))return!1;throw e}}#l(){return D(this.#e,`tasks`)}#u(){return D(this.#e,`subscriptions`)}#d(){return D(this.#e,`events`)}#f(e){return D(this.#l(),e+`.json`)}#p(e,t){return D(this.#u(),e+`-`+t+`.json`)}#m(e,t){return D(this.#d(),e+`-`+t+`.jsonl`)}};function pi(e,t){return new fi(e,t)}const mi=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),hi=/* @__PURE__ */ new Set([`running`,`stopping`]),gi=2**53-1,_i={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function Y(e){return e instanceof Error?e.message:String(e)}function vi(e){return e===void 0||e.length===0?`<in-memory>`:e}function yi(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var bi=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()}},xi=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)}},Si=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)}},Ci=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]}},wi=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??_i,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??Je,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new et:pi(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new yr:new xr(e));let t=(e.createInitialStorage??(()=>new et))(),n=Ze(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new si(t,{now:this.clock,logger:this.#e});this.registry=new bi(n),this.outputStorage=new xi(new yr),this.pipeline=new Si(r),this.lifecycle=new Ci((e.createLifecycle??(()=>new Pe({logger:this.#e})))()),this.slots=new nt(e.concurrency??L.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||mi.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 `+vi(e)+` is unavailable: `+Y(n),t),[]}let i=Ze(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new si(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:gi})}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:gi})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+Y(e)),t=[]}let n=[];for(let r of t)if(hi.has(r.status)&&qe(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:yi(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=R(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 Ti(e={}){return new wi(e)}const Ei=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function Di(e){return Ei.has(e.status)}function Oi(e,t){if(e.length===0)return``;let n=e.map(Ai).join(`
40
+ `);return`${`<bg-task-notifications batch-id="${X(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function ki(e,t=102400){let n=[],r=[],i=0,a=t-Mi;for(let t of e){let e=ji(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 Ai(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.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(`
41
+ `)}function X(e){return e.replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`"`,`&quot;`).replaceAll(` `,`&#9;`).replaceAll(`
42
+ `,`&#10;`).replaceAll(`\r`,`&#13;`)}function ji(e){return Buffer.byteLength(Ai(e),`utf8`)}const Mi=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),Ni=[`ptc_run_code`,`ptc_workflow`],Pi=[`read`,`bash`,`edit`,`write`],Fi=`ptc-mode`,Ii=`ptc-mode`,Li=`ptc.json`,Ri=`builtins-only`;function zi(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function Bi(e){let t=D(e,Li),n;try{n=T(t,`utf8`)}catch{return{defaultMode:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch(e){return{defaultMode:!0,source:`invalid`,error:`${t} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof r!=`object`||!r||Array.isArray(r))return{defaultMode:!0,source:`invalid`,error:`${t} must contain a JSON object`};let i=r.defaultMode;return i===void 0?{defaultMode:!0,source:`default`}:typeof i==`boolean`?{defaultMode:i,source:`file`}:{defaultMode:!0,source:`invalid`,error:`${t}: "defaultMode" must be a boolean, received ${typeof i}`}}const Vi=[`off`,`subagents`,`full`],Z=`builtin:codemode`;function Q(e){return e.split(A).join(`/`)}function Hi(e){return Q(e.startsWith(`./`)||e.startsWith(`.\\`)?e.slice(2):e)}function Ui(e,t,n){let r=Q(O(n,e)),i=ae(e),a=Q(e);return t.some(e=>{let t=Q(e);return ye(r,t)||ye(i,t)||ye(a,t)})}function Wi(e,t,n){if(t.length===0)return!1;let r=Q(O(n,e)),i=Q(e);return t.some(e=>{let t=Hi(e);return t===r||t===i})}function Gi(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 Ki(e,t){if(!Array.isArray(e))return;let n;for(let{sign:r,target:i}of Gi(e)){let e=r!==`-`&&r!==`!`;(r===`+`||r===`-`?Wi(Z,[i],t):Ui(Z,[i],t))&&(n=e?`enabled`:`disabled`)}return n}function qi(e,t){if(!Array.isArray(e))return;let n=Gi(e),r=e=>n.filter(t=>t.sign===e).map(e=>e.target),i=r(`!`),a=r(`+`),o=r(`-`),s;return Ui(Z,i,t)&&(s=`disabled`),Wi(Z,a,t)&&(s=`enabled`),Wi(Z,o,t)&&(s=`disabled`),s}function Ji(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 Yi(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 Xi(e,t,n,r={project:process.cwd(),user:process.cwd()}){let i=e.slice(1);if(Ji(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=Ki(a,r.project);if(o!==void 0)return{switch:o,source:`project`};let s=n?.extensions,c=qi(s,r.user);return c===void 0?{switch:`absent`,source:`default`}:{switch:c,source:`user`}}function Zi(e,t,n=process.argv){let r=Yi(D(t,`.pi`,`settings.json`)),i=Yi(D(e,`settings.json`)),a=Xi(n,r.value,i.value,{project:D(t,`.pi`),user:e}),o=r.error??i.error;return o===void 0?a:{...a,source:`invalid`,error:o}}function Qi(e,t){return e.present?t===`disabled`?`full`:`subagents`:`full`}function $i(e,t){return e!==void 0&&e!==`off`&&e!==t}function ea(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=oe(n);for(let e of ta){let t=D(r,...e);try{if(te(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const ta=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function na(e,t,n,r=process.cwd()){let i=D(e,Li),a=()=>{let i=t??ea(),a=n??Zi(e,r);return{surfaceMode:Qi(i,a.switch),codemode:i,codemodeSwitch:a}},o;try{o=T(i,`utf8`)}catch{return{...a(),source:`default`}}let s;try{s=JSON.parse(o)}catch(e){return{surfaceMode:a().surfaceMode,source:`invalid`,error:`${i} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof s!=`object`||!s||Array.isArray(s))return{surfaceMode:a().surfaceMode,source:`invalid`,error:`${i} must contain a JSON object`};let c=s.surfaceMode;if(c===void 0)return{...a(),source:`default`};if(typeof c!=`string`)return{surfaceMode:a().surfaceMode,source:`invalid`,error:`${i}: "surfaceMode" must be a string, received ${typeof c}`};if(!Vi.includes(c))return{surfaceMode:a().surfaceMode,source:`invalid`,error:`${i}: "surfaceMode" must be one of ${Vi.join(` | `)}, received ${JSON.stringify(c)}`};let l=a();return{surfaceMode:c,source:`file`,detected:l.surfaceMode,codemode:l.codemode,codemodeSwitch:l.codemodeSwitch}}function ra(e){return[...new Set(e)]}function ia(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 aa(e,t){let n=e=>Ni.includes(e);if(t===`all-but-ptc`)return ra(e.filter(n));let r=new Set(z);return ra(e.filter(e=>n(e)||!r.has(e)))}function oa(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:Ni.some(e=>r.includes(e))?!i&&Pi.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:ra(r),loadout:aa(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function sa(e,t){return e.enabled&&e.base!==void 0?e.base:t}function ca(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!ia(e.ourLoadout,t)}function la(e,t){let n=t.length>0&&t.every(e=>Ni.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function ua(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(`
42
43
  `);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(`
43
- `)}const Ui=[`read`,`bash`],Wi=`Use the read tool to load a skill's file when the task matches its description.`,Gi=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function Ki(e){return!Ui.some(t=>e.includes(t))}function qi(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Wi)?n.replace(Wi,Gi):`${Gi}\n\n${n}`}function Ji(e){let t=e.taskId;return typeof t==`string`?t:void 0}function Yi(e){return g({name:`ptc_subagent`,label:`PTC Subagent`,description:[`Start a fresh pi agent as a child process: it gets its own context, its own model and its own tools, and it cannot see or change this session except through what it returns. Use it for work that would otherwise flood this context: a survey, a second opinion, or a task that can run while you do something else.`].join(`
44
- `),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:Nt,async execute(t,n){let r=await At(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=Ji(r),a=i===void 0?{taskId:void 0,status:r.status,exitCode:r.exitCode}:{taskId:i,status:`background`,exitCode:void 0};if(i!==void 0)return{content:[{type:`text`,text:`Started background task `+i}],details:a};if(r.status===`rejected`)throw Error(`ptc_subagent refused the call: `+r.errorMessage);return{content:[{type:`text`,text:r.text}],details:a}}})}const $=Di;function Xi(e,t){return[`PTC mode on — ${t===`all-but-ptc`?`all other tools`:`built-in tools (now reachable only as tools.<name> inside a program)`} hidden.`,`Bindings available inside a program: ${K(e).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
45
- `)}function Zi(e,t={}){let n=Oi(),r=t.surfaceMode===void 0?Pi(y(),t.codemode):{surfaceMode:t.surfaceMode,source:`file`},i=!1,a=new Yr,o=()=>zi(n,e.getActiveTools()),s=mn(),c=hn();if(r.surfaceMode===`off`)return;let l=t.backgroundRuntime??hi({concurrency:L({}).dispatchConcurrency}),u=!1,d=e=>{console.warn(`[pi-ptc.background] `+e)},f=t=>{if(t.length!==0){if(u){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},p=async e=>{let{items:t,acks:n}=await l.drainNotifications(e),r=t.filter(e=>_i(e.record));for(let e of yi(r))f(vi(e,{batchId:Ce(),deliveredAtMs:l.clock()}));await l.acknowledgeNotifications(n)},m=async()=>{let e=await l.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},h=async()=>{for(let e of await m())await p(e)},g=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await p(e)};l.pipeline.onIdleWake(e=>{p(e).catch(e=>{d(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})}),r.surfaceMode===`full`&&(e.registerTool(or({getBindingSourceNames:o,getPool:()=>a.get(`run_code`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(fr({getBindingSourceNames:o,getPool:()=>a.get(`workflow`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps}))),r.surfaceMode===`subagents`&&e.registerTool(Yi({cwd:process.cwd(),depth:s,maxDispatchDepth:I.maxDispatchDepth,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(Ur(l.registry)),e.registerTool(Kr(l.registry,l.outputStorage)),e.registerTool(Jr(l.registry,l.lifecycle,{clock:l.clock})),e.on(`turn_start`,async()=>{u=!0}),e.on(`agent_settled`,async()=>{u=!1;try{await h()}catch(e){d(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new Yr,await e.drain()});let _=e=>{e.ui.setStatus(Ti,n.enabled?e.ui.theme.fg(`accent`,`PTC`):void 0)},v=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Q,{enabled:!0,base:[...t]}),_(a),a.ui.notify(o,`info`)},b=(t,r)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,i=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(r.customType,{enabled:!1}),_(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},x=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode (built-in tools reachable only from inside a PTC program)`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}b(r,{announce:!0,customType:Q});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${K(n.base).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=Ri({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:$});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}v(a.base,a.loadout,r,Xi(a.base,$))}}),e.on(`session_start`,async(t,n)=>{u=!1;let i=await l.bindSession(n.sessionManager?.getSessionDir?.(),e=>n.ui.notify(e,`warning`));try{await g(i)}catch(e){d(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let a=ki(y());a.error!==void 0&&n.ui.notify(`pi-ptc-subagents: ${a.error}`,`warning`),r.error!==void 0&&r.error!==a.error&&n.ui.notify(`pi-ptc-subagents: ${r.error}`,`warning`);let o=r.codemode;if(o!==void 0&&!o.present&&n.ui.notify(`pi-ptc-subagents: no surfaceMode is set, and the codemode probe reported `+o.how+`, so the surface defaults to full. That is the safe direction, not an error. If this pi really does ship pi's own codemode, set "surfaceMode" in ptc.json -- an explicit key always wins over detection.`,`info`),o!==void 0&&r.source!==`file`){let t=e.getAllTools().some(e=>e.name===`codemode`);!o.present&&t&&n.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+o.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Set an explicit "surfaceMode" in ptc.json to pick one.`,`warning`),o.present&&!t&&n.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions or --exclude-tools codemode), so the detected surface is "subagents" with no orchestrator. Set "surfaceMode" to "full" in ptc.json to use ptc_run_code instead.`,`warning`)}r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)&&n.ui.notify(`pi-ptc-subagents: surfaceMode is subagents, but codemode is not active in this session, so there is no orchestration tool. Add codemode to your pi tool list (the --tools flag or the default tools setting), or set surfaceMode to "full" to use ptc_run_code instead.`,`warning`);let s=x(n),{base:c,restoreFirst:f}=Vi(s,e.getActiveTools());f&&e.setActiveTools([...c]);let p=Ri({mode:n.mode,defaultMode:a.defaultMode,active:c,manual:!1,hide:$}),m=s?.enabled??p.enter;if(p.enter&&m){v(c,p.loadout,n,Xi(c,$));return}_(n),!p.enter&&p.reason!==`not-tui`&&s===void 0&&p.reason===`restricted-session`&&n.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{u=!1;try{await l.shutdown(`session_ended_while_running`)}catch(e){d(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let S=!1,C=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){S&&=(delete e.sections.skills,!1);return}let r=qi(e.skills);r.length!==0&&(e.sections.skills=r,S=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(C(a,Ki(e.getActiveTools())),n.enabled){if(Bi(n,e.getActiveTools())){b(r,{announce:!1,customType:Q}),C(a,Ki(e.getActiveTools())),r.ui.notify(`PTC mode off — another extension changed the active tool set.`,`warning`);return}if(i)return i=!1,{message:{customType:`ptc-mode-briefing`,content:Hi(K(n.base),$),display:!1}}}})}export{B as BUILTIN_BINDING_NAMES,jt as DEFAULT_BINDING_NAMES,I as DEFAULT_CONFIG,Di as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,tn as MAX_LINE_CHARS,wi as MODE_REQUIRED_TOOL_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Ei as PTC_MODE_CONFIG_FILE,Q as PTC_MODE_ENTRY_TYPE,Ti as PTC_MODE_STATUS_KEY,Ci as PTC_MODE_TOOL_NAMES,Gi as PTC_SKILL_LOAD_INSTRUCTION,Ui as SKILL_READING_TOOL_NAMES,Yr as TurnPools,Me as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Rt as WorkerPool,zi as bindingSource,Hi as buildModeInstruction,qi as buildPtcSkillsSection,Ft as createBuiltinBindings,Ne as createWorkerEnv,Ri as decideModeEntry,Zi as default,Bi as detectExternalLoadoutChange,Pe as effectiveTimeoutMs,Oi as initialModeState,Li as modeLoadout,ki as readDefaultModeConfig,Pi as readSurfaceModeConfig,pn as renderModelValue,Vi as resolveBaseOnStart,L as resolveConfig,qt as runPtcProgram,Ii as sameToolSet,G as sanitizeText,Ki as skillsSectionDropped,rn as stripAnsi};
44
+ `)}const da=[`read`,`bash`],fa=`Use the read tool to load a skill's file when the task matches its description.`,pa=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function ma(e){return!da.some(t=>e.includes(t))}function ha(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(fa)?n.replace(fa,pa):`${pa}\n\n${n}`}const ga=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").`}),exit_code:x.Optional(x.Number({description:`The child's exit code. Present ONLY for a call that already finished.`}))});function _a(e){let t=e.taskId;return typeof t==`string`?t:void 0}function va(e){return g({name:`ptc_subagent`,label:`PTC Subagent`,description:[`Start a fresh pi agent as a child process: it gets its own context, its own model and its own tools, and it cannot see or change this session except through what it returns. Use it for work that would otherwise flood this context: a survey, a second opinion, or a task that can run while you do something else.`].join(`
45
+ `),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:Rt,outputSchema:ga,async execute(t,n){let r=await Ft(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=_a(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={task_id:i,status:a.status};return{content:[{type:`text`,text:`Started background task `+i}],details:a,structuredContent:e}}if(r.status===`rejected`)throw Error(`ptc_subagent refused the call: `+r.errorMessage);let o=a.exitCode===void 0?{status:a.status}:{status:a.status,exit_code:a.exitCode};return{content:[{type:`text`,text:r.text}],details:a,structuredContent:o}}})}const $=Ri;function ya(e,t){return[`PTC mode on — ${t===`all-but-ptc`?`all other tools`:`built-in tools (now reachable only as tools.<name> inside a program)`} hidden.`,`Bindings available inside a program: ${G(e).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
46
+ `)}function ba(e,t={}){let n=zi(),r=t.surfaceMode===void 0?na(y(),t.codemode,t.codemodeSwitch):{surfaceMode:t.surfaceMode,source:`file`},i=!1,a=new ai,o=()=>sa(n,e.getActiveTools()),s=bn(),c=xn();if(r.surfaceMode===`off`)return;let l=t.backgroundRuntime??Ti({concurrency:Le({}).dispatchConcurrency}),u=!1,d=e=>{console.warn(`[pi-ptc.background] `+e)},f=t=>{if(t.length!==0){if(u){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},p=async e=>{let{items:t,acks:n}=await l.drainNotifications(e),r=t.filter(e=>Di(e.record));for(let e of ki(r))f(Oi(e,{batchId:Ee(),deliveredAtMs:l.clock()}));await l.acknowledgeNotifications(n)},m=async()=>{let e=await l.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},h=async()=>{for(let e of await m())await p(e)},g=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await p(e)};l.pipeline.onIdleWake(e=>{p(e).catch(e=>{d(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})}),r.surfaceMode===`full`&&(e.registerTool(fr({getBindingSourceNames:o,getPool:()=>a.get(`run_code`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(vr({getBindingSourceNames:o,getPool:()=>a.get(`workflow`),depth:s,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps}))),r.surfaceMode===`subagents`&&e.registerTool(va({cwd:process.cwd(),depth:s,maxDispatchDepth:L.maxDispatchDepth,...c===void 0?{}:{parentTaskId:c},getDispatchDeps:()=>l.dispatchDeps})),e.registerTool(Zr(l.registry)),e.registerTool(ti(l.registry,l.outputStorage)),e.registerTool(ii(l.registry,l.lifecycle,{clock:l.clock})),e.on(`turn_start`,async()=>{u=!0}),e.on(`agent_settled`,async()=>{u=!1;try{await h()}catch(e){d(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new ai,await e.drain()});let _=e=>{e.ui.setStatus(Ii,n.enabled?e.ui.theme.fg(`accent`,`PTC`):void 0)},v=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Fi,{enabled:!0,base:[...t]}),_(a),a.ui.notify(o,`info`)},b=(t,r)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,i=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(r.customType,{enabled:!1}),_(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},x=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode (built-in tools reachable only from inside a PTC program)`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}b(r,{announce:!0,customType:Fi});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${G(n.base).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=oa({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:$});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}v(a.base,a.loadout,r,ya(a.base,$))}}),e.on(`session_start`,async(t,n)=>{u=!1;let i=await l.bindSession(n.sessionManager?.getSessionDir?.(),e=>n.ui.notify(e,`warning`));try{await g(i)}catch(e){d(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let a=Bi(y());a.error!==void 0&&n.ui.notify(`pi-ptc-subagents: ${a.error}`,`warning`),r.error!==void 0&&r.error!==a.error&&n.ui.notify(`pi-ptc-subagents: ${r.error}`,`warning`);let o=r.codemode;if(o!==void 0&&!o.present&&n.ui.notify(`pi-ptc-subagents: no surfaceMode is set, and the codemode probe reported `+o.how+`, so the surface defaults to full. That is the safe direction, not an error. If this pi really does ship pi's own codemode, set "surfaceMode" in ptc.json -- an explicit key always wins over detection.`,`info`),r.codemodeSwitch?.error!==void 0&&n.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.source===`file`&&r.detected!==void 0&&$i(r.surfaceMode,r.detected)){let e=r.codemodeSwitch;n.ui.notify(`pi-ptc-subagents: surfaceMode is pinned to `+JSON.stringify(r.surfaceMode)+`, but this pi resolves to `+JSON.stringify(r.detected)+(e===void 0?``:` (pi's codemode is on disk and its switch is `+e.switch+`)`)+`. The pinned value is in force. Change it in ptc.json if that is not what you meant.`,`info`)}if(o!==void 0&&r.source!==`file`){let t=e.getAllTools().some(e=>e.name===`codemode`);!o.present&&t&&n.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+o.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Set an explicit "surfaceMode" in ptc.json to pick one.`,`warning`),o.present&&!t&&n.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions or --exclude-tools codemode), so the detected surface is "subagents" with no orchestrator. Set "surfaceMode" to "full" in ptc.json to use ptc_run_code instead.`,`warning`)}r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)&&n.ui.notify(`pi-ptc-subagents: surfaceMode is subagents, but codemode is not active in this session, so there is no orchestration tool. Add codemode to your pi tool list (the --tools flag or the default tools setting), or set surfaceMode to "full" to use ptc_run_code instead.`,`warning`);let s=x(n),{base:c,restoreFirst:f}=la(s,e.getActiveTools());f&&e.setActiveTools([...c]);let p=oa({mode:n.mode,defaultMode:a.defaultMode,active:c,manual:!1,hide:$}),m=s?.enabled??p.enter;if(p.enter&&m){v(c,p.loadout,n,ya(c,$));return}_(n),!p.enter&&p.reason!==`not-tui`&&s===void 0&&p.reason===`restricted-session`&&n.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{u=!1;try{await l.shutdown(`session_ended_while_running`)}catch(e){d(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let S=!1,C=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){S&&=(delete e.sections.skills,!1);return}let r=ha(e.skills);r.length!==0&&(e.sections.skills=r,S=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(C(a,ma(e.getActiveTools())),n.enabled){if(ca(n,e.getActiveTools())){b(r,{announce:!1,customType:Fi}),C(a,ma(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:ua(G(n.base),$),display:!1}}}})}export{z as BUILTIN_BINDING_NAMES,It as DEFAULT_BINDING_NAMES,L as DEFAULT_CONFIG,Ri as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,cn as MAX_LINE_CHARS,Pi as MODE_REQUIRED_TOOL_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Li as PTC_MODE_CONFIG_FILE,Fi as PTC_MODE_ENTRY_TYPE,Ii as PTC_MODE_STATUS_KEY,Ni as PTC_MODE_TOOL_NAMES,pa as PTC_SKILL_LOAD_INSTRUCTION,da as SKILL_READING_TOOL_NAMES,ai as TurnPools,Fe as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Wt as WorkerPool,sa as bindingSource,ua as buildModeInstruction,ha as buildPtcSkillsSection,Vt as createBuiltinBindings,Ie as createWorkerEnv,oa as decideModeEntry,ba as default,ca as detectExternalLoadoutChange,Re as effectiveTimeoutMs,zi as initialModeState,aa as modeLoadout,ea as probeCodemodePresence,Zi as readCodemodeSwitch,Bi as readDefaultModeConfig,na as readSurfaceModeConfig,yn as renderModelValue,la as resolveBaseOnStart,Xi as resolveCodemodeSwitch,Le as resolveConfig,$t as runPtcProgram,ia as sameToolSet,W as sanitizeText,ma as skillsSectionDropped,un as stripAnsi,$i as surfaceModeConflict};
46
47
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ptc-subagents",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "DSH PTC mode (ptc_run_code + ptc_workflow) for pi",
5
5
  "keywords": [
6
6
  "pi",
@@ -46,10 +46,13 @@
46
46
  "verify:dist": "node scripts/verify-dist-render.mjs",
47
47
  "prepublishOnly": "npm run typecheck && npm run lint && npm run fmt:check && npm run build && npm run test"
48
48
  },
49
+ "dependencies": {
50
+ "minimatch": "^10.2.6"
51
+ },
49
52
  "devDependencies": {
50
- "@earendil-works/pi-ai": "^0.86.1",
51
- "@earendil-works/pi-coding-agent": "^0.86.1",
52
- "@earendil-works/pi-tui": "^0.87.0",
53
+ "@earendil-works/pi-ai": "^1.0.0",
54
+ "@earendil-works/pi-coding-agent": "^1.0.0",
55
+ "@earendil-works/pi-tui": "^1.0.0",
53
56
  "@types/node": "^22.0.0",
54
57
  "@vitest/coverage-v8": "4.1.11",
55
58
  "oxfmt": "^0.70.0",