pi-ptc-subagents 2.1.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +19 -4
- package/dist/index.d.ts +142 -78
- package/dist/index.js +47 -47
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.0] - 2026-10-14
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **BREAKING: `tools.bash(...)` is no longer bound by default; it is an explicit opt-in.** A PTC
|
|
13
|
+
program runs with the user's own machine identity and its binding calls bypass pi's `tool_call`
|
|
14
|
+
guards, so a default shell binding hands every model-written program a shell with your identity —
|
|
15
|
+
the largest single thing a program can reach, granted by nothing more than installing this package.
|
|
16
|
+
`bash` is now an _opt-in_ binding: it stays in the known binding set, and a program only gets it
|
|
17
|
+
when the install grants it in `~/.pi/agent/ptc.json`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{ "optInBindings": ["bash"] }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Migration:** a program that calls `tools.bash(...)` and was relying on the default now fails with
|
|
24
|
+
`no binding named "bash" in this run; available bindings: …`. Either add the key above (restart
|
|
25
|
+
pi to pick it up), or, for a narrower change, pass an explicit `names` list to
|
|
26
|
+
`createBuiltinBindings` — a caller-curated list is honoured verbatim and needs no second key. The
|
|
27
|
+
error names the bindings that _are_ available, so the fix is readable from the refusal.
|
|
28
|
+
|
|
29
|
+
Two properties worth knowing: the opt-in is **separate from the session's tool set** — pi having
|
|
30
|
+
`bash` enabled does not grant it, because "enabled" and "you agreed to give a model-written program
|
|
31
|
+
a shell" are different questions; and the file is read with a **fail-closed** direction, so an
|
|
32
|
+
absent, unparseable or misspelled key grants nothing and reports why at session start rather than
|
|
33
|
+
falling back to the old default. Note this narrows relative to DSH, whose PTC preset mounts
|
|
34
|
+
`tool-bash`/`tool-pwsh`; a program written against DSH that wants its shell back needs the key.
|
|
35
|
+
|
|
8
36
|
## [2.1.0] - 2026-10-12
|
|
9
37
|
|
|
10
38
|
### Added
|
package/README.md
CHANGED
|
@@ -47,8 +47,9 @@ Documentation site: **[pi-ptc-subagents on GitHub Pages](https://a1121611810.git
|
|
|
47
47
|
capability is the `pi.dispatch` binding inside a program.
|
|
48
48
|
- `ptc_run_code` — run a JS/TS program that composes tool calls; the program reaches the
|
|
49
49
|
session's enabled built-in tools as `tools.read(...)`, `tools.write(...)`, etc.
|
|
50
|
-
(`read`, `
|
|
51
|
-
its return value and `console.log` output are reported back.
|
|
50
|
+
(`read`, `edit`, `write`, `grep`, `find`, `ls`), plus `tools["pi.dispatch"]`;
|
|
51
|
+
its return value and `console.log` output are reported back. `tools.bash(...)` is an
|
|
52
|
+
**opt-in** — see [Trust posture](#trust-posture-read-me).
|
|
52
53
|
- `ptc_workflow` — structured variant with `meta` + plain-JSON `args`, plus the workflow
|
|
53
54
|
helpers (`log`, `phase`, `parallel`, `pipeline`). There is no `agent()` helper on either
|
|
54
55
|
surface.
|
|
@@ -201,8 +202,22 @@ untrusted projects) live in [docs/usage/surface.md](./docs/usage/surface.md).
|
|
|
201
202
|
extension: PTC programs run as **you**, with no OS-level sandbox (ADR-0007).
|
|
202
203
|
- Bindings mirror the session's **enabled** built-in tools (`pi.getActiveTools()`):
|
|
203
204
|
a session started with `--tools …` / `--no-builtin-tools` can only reach those
|
|
204
|
-
tools from inside a PTC program
|
|
205
|
-
`write` —
|
|
205
|
+
tools from inside a PTC program. pi's default session has `read`, `bash`,
|
|
206
|
+
`edit`, `write` — of which the default surface binds `read`, `edit`, `write`
|
|
207
|
+
(see the next bullet).
|
|
208
|
+
- **`tools.bash(...)` is not in that default.** A PTC program runs as you, so a
|
|
209
|
+
default shell binding hands every model-written program a shell with your own
|
|
210
|
+
identity. It is granted explicitly, per install, in `~/.pi/agent/ptc.json`:
|
|
211
|
+
|
|
212
|
+
```json
|
|
213
|
+
{ "optInBindings": ["bash"] }
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
An absent or unreadable file grants nothing, and a name in that list that is not
|
|
217
|
+
an opt-in binding is reported at session start rather than ignored. The opt-in is
|
|
218
|
+
separate from the session's tool set on purpose: **enabled is not granted** — pi
|
|
219
|
+
having `bash` enabled says nothing about whether you agreed to hand it to a program.
|
|
220
|
+
|
|
206
221
|
- Tool calls made from inside a PTC program execute directly and **bypass**
|
|
207
222
|
pi's `tool_call` hooks (permission gates, path guards) — see ADR-0005. Do not
|
|
208
223
|
rely on those guards to constrain tool use while this extension is enabled.
|
package/dist/index.d.ts
CHANGED
|
@@ -594,6 +594,119 @@ interface BackgroundTaskRuntime {
|
|
|
594
594
|
shutdown(reason: LostReason): Promise<TaskRecord[]>;
|
|
595
595
|
}
|
|
596
596
|
//#endregion
|
|
597
|
+
//#region src/runtime/bindings.d.ts
|
|
598
|
+
/** pi's built-in tools that can be exposed as bindings, in native order. */
|
|
599
|
+
export declare const BUILTIN_BINDING_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
|
|
600
|
+
type BuiltinBindingName = (typeof BUILTIN_BINDING_NAMES)[number];
|
|
601
|
+
/**
|
|
602
|
+
* Bindings that are known but NOT exposed unless someone asks for them (#73).
|
|
603
|
+
*
|
|
604
|
+
* `bash` is here rather than deleted from {@link BUILTIN_BINDING_NAMES} because DSH's PTC preset
|
|
605
|
+
* still mounts `tool-bash`/`tool-pwsh` (R1 §2 — PTC mode hides the tools from the wire list and
|
|
606
|
+
* re-exposes the same registry as bindings), so a PTC program written against DSH may run shell
|
|
607
|
+
* commands. Removing it outright would break those programs; leaving it on by default hands every
|
|
608
|
+
* model-written program a shell with the user's own identity, which is the larger risk. An explicit
|
|
609
|
+
* opt-in is what makes the second case a decision instead of a default.
|
|
610
|
+
*/
|
|
611
|
+
export declare const OPT_IN_BINDING_NAMES: readonly ["bash"];
|
|
612
|
+
type OptInBindingName = (typeof OPT_IN_BINDING_NAMES)[number];
|
|
613
|
+
/** Whether `name` is one of the {@link OPT_IN_BINDING_NAMES}. */
|
|
614
|
+
export declare function isOptInBindingName(name: string): name is OptInBindingName;
|
|
615
|
+
/**
|
|
616
|
+
* Validate a caller's opt-in list and return it in {@link BUILTIN_BINDING_NAMES} order.
|
|
617
|
+
*
|
|
618
|
+
* Order is normalised rather than kept as given so that a table built with and without an opt-in
|
|
619
|
+
* lists the same bindings in the same sequence — the model-facing prompt renders this list, and two
|
|
620
|
+
* spellings of the same surface would be two things to drift.
|
|
621
|
+
*
|
|
622
|
+
* A name that is not an opt-in is refused, including a name that IS a known builtin: `["read"]` is
|
|
623
|
+
* a configuration mistake, not a request, and accepting it would mean `optIns` silently no-ops for
|
|
624
|
+
* every name a caller already had by default.
|
|
625
|
+
*/
|
|
626
|
+
export declare function resolveOptInBindingNames(optIns: readonly string[] | undefined): readonly BuiltinBindingName[];
|
|
627
|
+
/**
|
|
628
|
+
* Bindings exposed when the caller does not pass an explicit name list and does not opt in.
|
|
629
|
+
*
|
|
630
|
+
* The known set minus {@link OPT_IN_BINDING_NAMES}, in native order. Both resolution paths emit
|
|
631
|
+
* {@link BUILTIN_BINDING_NAMES} order, so adding an opt-in re-inserts the binding where the model
|
|
632
|
+
* expects it rather than at the end.
|
|
633
|
+
*/
|
|
634
|
+
export declare const DEFAULT_BINDING_NAMES: readonly BuiltinBindingName[];
|
|
635
|
+
interface BindingContext {
|
|
636
|
+
/** Aborted when the run is cancelled, times out, or settles. */
|
|
637
|
+
signal?: AbortSignal;
|
|
638
|
+
/** Wire call id; also used to build the tool call id the tools see. */
|
|
639
|
+
callId: number;
|
|
640
|
+
/** Depth of the current PTC run (0 for parent turn, 1+ for a child of `pi.dispatch`). */
|
|
641
|
+
depth: number;
|
|
642
|
+
/** Maximum allowed depth; passed through to `pi.dispatch` for the depth check. */
|
|
643
|
+
maxDispatchDepth: number;
|
|
644
|
+
/**
|
|
645
|
+
* ADR-0022 §5: the TaskRecord owner / subscription subscriber. The dispatcher threads the
|
|
646
|
+
* run id here so a background task's events are addressed to the spawning run.
|
|
647
|
+
*/
|
|
648
|
+
callerId?: string;
|
|
649
|
+
/**
|
|
650
|
+
* ADR-0022 R1: the session dir a background child persists into. Threaded from the
|
|
651
|
+
* dispatcher (see `RunPtcProgramOptions.sessionDir`); when no dir is available the spawn
|
|
652
|
+
* keeps the foreground no-session shape.
|
|
653
|
+
*/
|
|
654
|
+
sessionDir?: string;
|
|
655
|
+
/**
|
|
656
|
+
* ADR-0022 §3/reopen R-m12: this process's own background task id, when this run is inside a
|
|
657
|
+
* background child. Threaded from the dispatcher (see `RunPtcProgramOptions.parentTaskId`)
|
|
658
|
+
* and forwarded to `pi.dispatch` so a nested spawn records `TaskRecord.parentTaskId`.
|
|
659
|
+
*/
|
|
660
|
+
parentTaskId?: ULID;
|
|
661
|
+
/**
|
|
662
|
+
* ADR-0022 §9: per-run dispatch dependencies. The dispatcher supplies the run's shared
|
|
663
|
+
* `DispatchSlotCounter` here; a host may also pass session-level deps (registry / lifecycle /
|
|
664
|
+
* output storage) so the binding's `dispatch()` call shares them.
|
|
665
|
+
*/
|
|
666
|
+
dispatchDeps?: DispatchDeps;
|
|
667
|
+
}
|
|
668
|
+
interface Binding {
|
|
669
|
+
readonly name: string;
|
|
670
|
+
execute(args: unknown, context: BindingContext): Promise<unknown>;
|
|
671
|
+
}
|
|
672
|
+
type BindingTable = ReadonlyMap<string, Binding>;
|
|
673
|
+
interface CreateBuiltinBindingsOptions {
|
|
674
|
+
/** Per-run working directory: the F4 `RunConfig.cwd`, used to build every tool. */
|
|
675
|
+
cwd: string;
|
|
676
|
+
/**
|
|
677
|
+
* Subset of {@link BUILTIN_BINDING_NAMES}; defaults to {@link DEFAULT_BINDING_NAMES} plus any
|
|
678
|
+
* {@link CreateBuiltinBindingsOptions.optIns}. A list passed here is honoured VERBATIM: a caller
|
|
679
|
+
* that curates names has already decided its surface, so an opt-in name in an explicit list is
|
|
680
|
+
* taken at face value and the default gate does not apply to it.
|
|
681
|
+
*/
|
|
682
|
+
names?: readonly string[];
|
|
683
|
+
/**
|
|
684
|
+
* Opt-in bindings to add to the default surface (#73). Each must be an
|
|
685
|
+
* {@link OPT_IN_BINDING_NAMES} member or {@link resolveOptInBindingNames} throws. Omitted means
|
|
686
|
+
* "none granted", which is the safe direction: an unreadable or absent opt-in list narrows the
|
|
687
|
+
* surface rather than widening it.
|
|
688
|
+
*/
|
|
689
|
+
optIns?: readonly string[];
|
|
690
|
+
/**
|
|
691
|
+
* Whether the parallel binding `pi.dispatch` (ADR-0016) joins the table. Defaults to
|
|
692
|
+
* "did the caller curate the surface": `true` when `names` is omitted, `false` when an
|
|
693
|
+
* explicit list is passed (R3's read-only PTC surface pattern). Deciding on whether
|
|
694
|
+
* `names` was provided — not on array identity with {@link DEFAULT_BINDING_NAMES} —
|
|
695
|
+
* matters because production callers resolve names through a `.filter()` that always
|
|
696
|
+
* returns a fresh array. The two shipped tools pass `true` explicitly: the dispatch
|
|
697
|
+
* binding is part of every production surface.
|
|
698
|
+
*/
|
|
699
|
+
includeDispatch?: boolean;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Build the binding table for one run.
|
|
703
|
+
*
|
|
704
|
+
* Tools are created once per table and reused across calls, matching pi's own extension
|
|
705
|
+
* examples (`createXxxTool(cwd)` caches nothing internally, so one instance per run is
|
|
706
|
+
* the intended granularity).
|
|
707
|
+
*/
|
|
708
|
+
export declare function createBuiltinBindings(options: CreateBuiltinBindingsOptions): BindingTable;
|
|
709
|
+
//#endregion
|
|
597
710
|
//#region src/mode/ptc-mode.d.ts
|
|
598
711
|
/** The two surfaces this package exposes. `/ptc on` needs at least one of them active. */
|
|
599
712
|
export declare const PTC_MODE_TOOL_NAMES: readonly string[];
|
|
@@ -660,6 +773,34 @@ interface DefaultModeConfig {
|
|
|
660
773
|
* on** — the caller should surface the problem rather than silently changing behavior.
|
|
661
774
|
*/
|
|
662
775
|
export declare function readDefaultModeConfig(agentDir: string): DefaultModeConfig;
|
|
776
|
+
/** Result of reading the opt-in binding config, with enough detail to warn about a broken file. */
|
|
777
|
+
interface OptInBindingsConfig {
|
|
778
|
+
optInBindings: readonly BuiltinBindingName[];
|
|
779
|
+
source: "file" | "default" | "invalid";
|
|
780
|
+
error?: string;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Read `optInBindings` from the agent-dir config file — the user-facing half of #73.
|
|
784
|
+
*
|
|
785
|
+
* Absent file, or a file with no `optInBindings` key, grants nothing: `bash` stays out of the
|
|
786
|
+
* default surface. A key that is present but wrong is reported as `invalid` **and still grants
|
|
787
|
+
* nothing**, which is the safe direction — a typo in a list whose whole purpose is to widen the
|
|
788
|
+
* surface must never be the thing that widens it. The caller surfaces `error` rather than silently
|
|
789
|
+
* running a narrower surface than the user asked for.
|
|
790
|
+
*
|
|
791
|
+
* **A file too broken to parse is not this function's to report.** A non-object or unparseable
|
|
792
|
+
* `ptc.json` is a parse failure of the FILE, and {@link readDefaultModeConfig} — the reader that
|
|
793
|
+
* owns `defaultMode` in the same file — already reports it at session start. Reporting it here too
|
|
794
|
+
* would put the identical sentence on screen twice for one broken file, which trains the user to
|
|
795
|
+
* ignore the notice that matters. The boundary is the same one `readLegacySurfaceKey` draws: no
|
|
796
|
+
* key to be stale about means nothing to say. What this function reports is only what is wrong with
|
|
797
|
+
* the `optInBindings` KEY specifically.
|
|
798
|
+
*
|
|
799
|
+
* The name check lives in {@link resolveOptInBindingNames} so the config path and the programmatic
|
|
800
|
+
* path cannot disagree about what a valid opt-in is; this function's job is only to turn a thrown
|
|
801
|
+
* TypeError into a reportable string.
|
|
802
|
+
*/
|
|
803
|
+
export declare function readOptInBindingsConfig(agentDir: string): OptInBindingsConfig;
|
|
663
804
|
/**
|
|
664
805
|
* Which model-facing tools this package registers, independent of PTC mode (which decides
|
|
665
806
|
* which registered tools are *active*).
|
|
@@ -1267,83 +1408,6 @@ export declare function sanitizeText(value: string): string;
|
|
|
1267
1408
|
*/
|
|
1268
1409
|
export declare function renderModelValue(value: PtcJsonValue): string;
|
|
1269
1410
|
//#endregion
|
|
1270
|
-
//#region src/runtime/bindings.d.ts
|
|
1271
|
-
/** pi's built-in tools that can be exposed as bindings, in native order. */
|
|
1272
|
-
export declare const BUILTIN_BINDING_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
|
|
1273
|
-
type BuiltinBindingName = (typeof BUILTIN_BINDING_NAMES)[number];
|
|
1274
|
-
/**
|
|
1275
|
-
* Bindings exposed when the caller does not pass an explicit name list.
|
|
1276
|
-
*
|
|
1277
|
-
* `bash` is included on purpose: DSH's PTC preset still mounts `tool-bash`/`tool-pwsh`
|
|
1278
|
-
* (R1 §2 — PTC mode hides the tools from the wire list and re-exposes the same registry
|
|
1279
|
-
* as bindings), so a PTC program written against DSH may run shell commands. Leaving it
|
|
1280
|
-
* out would silently shrink the surface relative to DSH. Callers that want a read-only
|
|
1281
|
-
* PTC surface pass an explicit subset.
|
|
1282
|
-
*/
|
|
1283
|
-
export declare const DEFAULT_BINDING_NAMES: readonly BuiltinBindingName[];
|
|
1284
|
-
interface BindingContext {
|
|
1285
|
-
/** Aborted when the run is cancelled, times out, or settles. */
|
|
1286
|
-
signal?: AbortSignal;
|
|
1287
|
-
/** Wire call id; also used to build the tool call id the tools see. */
|
|
1288
|
-
callId: number;
|
|
1289
|
-
/** Depth of the current PTC run (0 for parent turn, 1+ for a child of `pi.dispatch`). */
|
|
1290
|
-
depth: number;
|
|
1291
|
-
/** Maximum allowed depth; passed through to `pi.dispatch` for the depth check. */
|
|
1292
|
-
maxDispatchDepth: number;
|
|
1293
|
-
/**
|
|
1294
|
-
* ADR-0022 §5: the TaskRecord owner / subscription subscriber. The dispatcher threads the
|
|
1295
|
-
* run id here so a background task's events are addressed to the spawning run.
|
|
1296
|
-
*/
|
|
1297
|
-
callerId?: string;
|
|
1298
|
-
/**
|
|
1299
|
-
* ADR-0022 R1: the session dir a background child persists into. Threaded from the
|
|
1300
|
-
* dispatcher (see `RunPtcProgramOptions.sessionDir`); when no dir is available the spawn
|
|
1301
|
-
* keeps the foreground no-session shape.
|
|
1302
|
-
*/
|
|
1303
|
-
sessionDir?: string;
|
|
1304
|
-
/**
|
|
1305
|
-
* ADR-0022 §3/reopen R-m12: this process's own background task id, when this run is inside a
|
|
1306
|
-
* background child. Threaded from the dispatcher (see `RunPtcProgramOptions.parentTaskId`)
|
|
1307
|
-
* and forwarded to `pi.dispatch` so a nested spawn records `TaskRecord.parentTaskId`.
|
|
1308
|
-
*/
|
|
1309
|
-
parentTaskId?: ULID;
|
|
1310
|
-
/**
|
|
1311
|
-
* ADR-0022 §9: per-run dispatch dependencies. The dispatcher supplies the run's shared
|
|
1312
|
-
* `DispatchSlotCounter` here; a host may also pass session-level deps (registry / lifecycle /
|
|
1313
|
-
* output storage) so the binding's `dispatch()` call shares them.
|
|
1314
|
-
*/
|
|
1315
|
-
dispatchDeps?: DispatchDeps;
|
|
1316
|
-
}
|
|
1317
|
-
interface Binding {
|
|
1318
|
-
readonly name: string;
|
|
1319
|
-
execute(args: unknown, context: BindingContext): Promise<unknown>;
|
|
1320
|
-
}
|
|
1321
|
-
type BindingTable = ReadonlyMap<string, Binding>;
|
|
1322
|
-
interface CreateBuiltinBindingsOptions {
|
|
1323
|
-
/** Per-run working directory: the F4 `RunConfig.cwd`, used to build every tool. */
|
|
1324
|
-
cwd: string;
|
|
1325
|
-
/** Subset of {@link BUILTIN_BINDING_NAMES}; defaults to all of them (bash included). */
|
|
1326
|
-
names?: readonly string[];
|
|
1327
|
-
/**
|
|
1328
|
-
* Whether the parallel binding `pi.dispatch` (ADR-0016) joins the table. Defaults to
|
|
1329
|
-
* "did the caller curate the surface": `true` when `names` is omitted, `false` when an
|
|
1330
|
-
* explicit list is passed (R3's read-only PTC surface pattern). Deciding on whether
|
|
1331
|
-
* `names` was provided — not on array identity with {@link DEFAULT_BINDING_NAMES} —
|
|
1332
|
-
* matters because production callers resolve names through a `.filter()` that always
|
|
1333
|
-
* returns a fresh array. The two shipped tools pass `true` explicitly: the dispatch
|
|
1334
|
-
* binding is part of every production surface.
|
|
1335
|
-
*/
|
|
1336
|
-
includeDispatch?: boolean;
|
|
1337
|
-
}
|
|
1338
|
-
/**
|
|
1339
|
-
* Build the binding table for one run.
|
|
1340
|
-
*
|
|
1341
|
-
* Tools are created once per table and reused across calls, matching pi's own extension
|
|
1342
|
-
* examples (`createXxxTool(cwd)` caches nothing internally, so one instance per run is
|
|
1343
|
-
* the intended granularity).
|
|
1344
|
-
*/
|
|
1345
|
-
export declare function createBuiltinBindings(options: CreateBuiltinBindingsOptions): BindingTable;
|
|
1346
|
-
//#endregion
|
|
1347
1411
|
//#region src/runtime/worker-pool.d.ts
|
|
1348
1412
|
/** Options the dispatcher hands to `new Worker(...)`. */
|
|
1349
1413
|
type WorkerPoolWorkerOptions = ConstructorParameters<typeof Worker>[1];
|
|
@@ -1605,5 +1669,5 @@ export interface PtcSubagentsOptions {
|
|
|
1605
1669
|
}
|
|
1606
1670
|
export default function ptcSubagents(pi: ExtensionAPI, options?: PtcSubagentsOptions): void;
|
|
1607
1671
|
//#endregion
|
|
1608
|
-
export type { Binding, BindingContext, BindingTable, CodemodePresence, CodemodeSwitch, CodemodeSwitchResolution, CodemodeSwitchSource, CreateBuiltinBindingsOptions, DefaultModeConfig, DetectedSurface, LegacySurfaceKey, ModeBlockReason, ModeEntryDecision, ModeEntryInput, ModeHideStrategy, PersistedModeState, PtcConfig, PtcErrorKind, PtcErrorShape, PtcImage, PtcJsonValue, PtcModeState, PtcRunOutcome, PtcSurface, RunPtcProgramOptions, TurnPoolsOptions, WorkerPoolOptions, WorkerPoolStats, WorkerPoolWorkerOptions };
|
|
1672
|
+
export type { Binding, BindingContext, BindingTable, CodemodePresence, CodemodeSwitch, CodemodeSwitchResolution, CodemodeSwitchSource, CreateBuiltinBindingsOptions, DefaultModeConfig, DetectedSurface, LegacySurfaceKey, ModeBlockReason, ModeEntryDecision, ModeEntryInput, ModeHideStrategy, OptInBindingName, OptInBindingsConfig, PersistedModeState, PtcConfig, PtcErrorKind, PtcErrorShape, PtcImage, PtcJsonValue, PtcModeState, PtcRunOutcome, PtcSurface, RunPtcProgramOptions, TurnPoolsOptions, WorkerPoolOptions, WorkerPoolStats, WorkerPoolWorkerOptions };
|
|
1609
1673
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,60 +1,60 @@
|
|
|
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
|
|
2
|
-
`);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=
|
|
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=
|
|
4
|
-
`,o.exited||Me(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Ae(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): `+Fe(t))}};const Le=`ptc_child_report`,F=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}),Re=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function ze(e=process.env){let t={};for(let n of Re){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function Be(e={}){let t={...F};for(let n of Object.keys(F)){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 Ve(e,t=F){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const He={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ue=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),We=/* @__PURE__ */ new Set([`running`,`stopping`]);function Ge(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 Ke(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function qe(e){return typeof e==`string`&&e.length>0}const Je=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function Ye(e){return typeof e==`string`&&Je.has(e)}function Xe(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Ze(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Qe(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var $e=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??Ze,this.#a=Ee({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 qe(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())We.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=qe(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(!Ke(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`&&!Ye(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:Ge(n,e,i,r),...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!We.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};Ue.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.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=He[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(!qe(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:Qe(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 et(e,t){return new $e(e,t)}function tt(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function nt(e){for(let t=1;t<e.length;t++)if(tt(e[t-1],e[t])>0)return!1;return!0}var rt=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=nt(t)?[...t]:[...t].sort(tt),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(tt),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 it=new Ie;var at=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 ot=new at(F.dispatchConcurrency);let st;function ct(e,t){return e.taskRegistry===void 0?(st??=new $e(new rt,{clock:t}),st):e.taskRegistry}const lt={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},ut=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function dt(e,t,n,r={}){let i=r.reportContract!==!1,a=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],`</pi-ptc-context>`].join(`
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,realpathSync as ee,statSync as E,writeFileSync as te}from"node:fs";import*as D from"node:os";import{tmpdir as ne}from"node:os";import*as O from"node:path";import{basename as re,dirname as ie,join as k,relative as A,resolve as j,sep as M}from"node:path";import{spawn as ae}from"node:child_process";import{randomBytes as oe,randomUUID as N}from"node:crypto";import{ok as se}from"node:assert/strict";import{MessageChannel as ce,Worker as le}from"node:worker_threads";import ue from"node:diagnostics_channel";import{fileURLToPath as de,pathToFileURL as fe}from"node:url";import{truncateToWidth as P,visibleWidth as F}from"@earendil-works/pi-tui";import{appendFile as pe,mkdir as me,readFile as he,readdir as ge,rename as _e,unlink as ve,writeFile as ye}from"node:fs/promises";import{minimatch as be}from"minimatch";const xe=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function Se(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(xe[n%32]??`0`)+t,n=Math.floor(n/32);return t}function Ce(e){let t=``,n=0,r=0;for(let i=0;i<e.length&&t.length<16;i++)for(n=n<<8|(e[i]??0),r+=8;r>=5&&t.length<16;)r-=5,t+=xe[n>>>r&31];return t.padEnd(16,`0`)}function we(e){let t=new Uint8Array(e);for(let e=t.length-1;e>=0;e--){if((t[e]??0)<255)return t[e]=(t[e]??0)+1,t;t[e]=0}return t}function Te(e){let t=e.randomBytes??(e=>new Uint8Array(oe(e))),n=-1,r=/* @__PURE__ */ new Uint8Array(10);return{next(){let i=Math.max(0,Math.floor(e.now())),a=i>n?i:n,o=a===n?we(r):t(10);return n=a,r=o,Se(a)+Ce(o)}}}const Ee=Te({now:()=>Date.now()});function De(){return Ee.next()}function Oe(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function ke(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function Ae(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function je(e,t){if(e.exited)return;e.exited=!0,e.exitValue=t;for(let n of e.exitWaiters)n(t);e.exitWaiters=[];let n=e.eventWaiters;e.eventWaiters=[];for(let e of n)e(null);for(let t of e.stderrWaiters)t(e.stderr);e.stderrWaiters=[]}function Me(e,t){let n=t.sessionDir===void 0?[...e]:e.filter(e=>e!==`--no-session`);return t.sessionDir!==void 0&&(n.push(`--session-dir`,t.sessionDir),t.sessionId!==void 0&&n.push(`--session-id`,t.sessionId),t.sessionName!==void 0&&n.push(`--name`,t.sessionName)),n}const Ne={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Pe(e){return e.length<=200?e:e.slice(0,200)+`…`}var Fe=class{#e;constructor(e={}){this.#e=e.logger??Ne}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=Me(e,t),r=n[0],i=n.slice(1),a=ae(r,i,{cwd:t.cwd,shell:!1,stdio:[`ignore`,`pipe`,`pipe`],env:t.env}),o={proc:a,events:[],eventWaiters:[],exited:!1,exitValue:null,stderrWaiters:[],exitWaiters:[],stderr:``,lineBuffer:``},s={id:De(),opaque:o},c=a.stdout;c&&c.on(`data`,e=>{o.lineBuffer+=e.toString(`utf-8`);let t=o.lineBuffer.indexOf(`
|
|
2
|
+
`);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=Oe(e);n?Ae(o,n):e.trim().length>0&&this.#t(s,e),t=o.lineBuffer.indexOf(`
|
|
3
|
+
`)}});let l=a.stderr;return l&&l.on(`data`,e=>{o.stderr+=e.toString(`utf-8`)}),a.on(`close`,(e,t)=>{let n=o.lineBuffer.trim();if(n.length>0){let e=Oe(n);e?Ae(o,e):this.#t(s,n),o.lineBuffer=``}je(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
|
|
4
|
+
`,o.exited||je(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;ke(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Pe(t))}};const Ie=`ptc_child_report`,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}),Le=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Re(e=process.env){let t={};for(let n of Le){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function ze(e={}){let t={...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 Be(e,t=I){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Ve={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},He=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Ue=/* @__PURE__ */ new Set([`running`,`stopping`]);function We(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function Ge(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Ke(e){return typeof e==`string`&&e.length>0}const qe=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function Je(e){return typeof e==`string`&&qe.has(e)}function Ye(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Xe(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Ze(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Qe=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??Xe,this.#a=Te({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Ke(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())Ue.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Ke(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!Ge(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!Je(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=(e.outputBytes??0)>0,i=n.status===`stopping`?`canceled`:e.exitCode===0&&r?`succeeded`:`failed`;return this.#v(n,i),this.#m(n,i,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview,errorMessage:We(n,e,i,r),...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!Ue.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};He.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=Ve[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Ke(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Ze(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function $e(e,t){return new Qe(e,t)}function et(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function tt(e){for(let t=1;t<e.length;t++)if(et(e[t-1],e[t])>0)return!1;return!0}var nt=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){se(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){se(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=tt(t)?[...t]:[...t].sort(et),i=n.length===0?void 0:n[n.length-1]?.eventId,a=r[0]?.eventId;if(i===void 0||a!==void 0&&i<=a){for(let e of r)n.push(structuredClone(e));this.#r.set(e,n);return}let o=[...n,...r.map(e=>structuredClone(e))];o.sort(et),this.#r.set(e,o)}async*loadEvents(e,t){if(!this.#a(e))throw Error(`loadEvents: unknown subscriptionId ${e}`);let n=this.#r.get(e)??[],r=0;if(t!==void 0){let e=0,i=n.length;for(;e<i;){let r=e+i>>>1;(n[r]?.eventId??``)<=t?e=r+1:i=r}r=e}for(let e=r;e<n.length;e++)yield structuredClone(n[e])}};const rt=new Fe;var it=class{limit;#e;#t=/* @__PURE__ */ new Set;constructor(e){if(!Number.isInteger(e)||e<0)throw TypeError(`DispatchSlotCounter: limit must be a non-negative integer, got ${String(e)}`);this.limit=e,this.#e=0}get active(){return this.#e}tryAcquire(e){return e!==void 0&&this.#t.has(e)||this.#e>=this.limit?!1:(e!==void 0&&this.#t.add(e),this.#e+=1,!0)}release(e){if(e!==void 0){if(!this.#t.delete(e))return;--this.#e;return}this.#e>this.#t.size&&--this.#e}};const at=new it(I.dispatchConcurrency);let ot;function st(e,t){return e.taskRegistry===void 0?(ot??=new Qe(new nt,{clock:t}),ot):e.taskRegistry}const ct={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},lt=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function ut(e,t,n,r={}){let i=r.reportContract!==!1,a=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],`</pi-ptc-context>`].join(`
|
|
5
5
|
`);return e.length===0?a:e+`
|
|
6
6
|
|
|
7
|
-
`+a}function
|
|
7
|
+
`+a}function dt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch depth limit reached`}}function ft(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch concurrency limit reached`}}function pt(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 mt(){return{...dt(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function ht(){return{...ft(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function gt(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 _t(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 vt(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 yt(e){let t=_t(e,`childReport`);if(t!==void 0)return t.toLowerCase()!==`false`&&t.toLowerCase()!==`no`}function bt(e){return e.childReport!==!1}function xt(e){let t=e.match(/^\uFEFF?[ \t]*(?:\r?\n)?---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*(?:\r?\n([\s\S]*))?$/);if(!t)return null;let n=(t[1]??``).replace(/\r\n/g,`
|
|
8
8
|
`),r=(t[2]??``).replace(/\r\n/g,`
|
|
9
|
-
`),i=
|
|
9
|
+
`),i=_t(n,`name`);if(!i)return null;let a=_t(n,`description`)??``,o=_t(n,`model`)??``,s=vt(n,`tools`),c=yt(n),l={name:i,systemPrompt:r.trim()};return a!==void 0&&(l.description=a),o!==void 0&&(l.model=o),s!==void 0&&(l.tools=s),c!==void 0&&(l.childReport=c),l}function St(e,t,n,r){let{userDir:i,projectDir:a}=Ct({cwd:t,agentScope:n,homeDir:r?.homeDir}),o=[];(n===`user`||n===`both`)&&o.push({path:O.join(i,e+`.md`),source:`user`}),(n===`project`||n===`both`)&&o.push({path:O.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=xt(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),r.childReport!==void 0&&(e.childReport=r.childReport),e}}return null}function Ct(e){let t=e.homeDir??D.homedir();return{userDir:O.join(t,`.pi`,`agent`,`agents`),projectDir:O.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function wt(e){let t=e?.code;return typeof t==`string`?t:String(e)}function Tt(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function Et(e,t){let n=O.resolve(e),r=O.resolve(t),i=e=>O.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(Dt(e))return!0;return!1}return a===r&&Dt(r)}function Dt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function Ot(e,t,n){let r=wt(n);return r!==`ENOENT`&&r!==`ENOTDIR`||Tt(e)?!1:!Et(e,t)}function kt(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=Ct(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r,source:`user`}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i,source:`project`});let o=/* @__PURE__ */ new Map;for(let{dir:e,boundary:t,source:n}of a){let r;try{r=C.readdirSync(e)}catch(n){if(!Ot(e,t,n)){let t=wt(n);console.warn(`pi.dispatch: cannot read agent directory ${e} (${t}); the agents registered there are not listed`)}continue}for(let t of r){if(!t.endsWith(`.md`))continue;let r=t.slice(0,-3),i=O.join(e,t),a;try{a=C.readFileSync(i,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`pi.dispatch: cannot read agent file ${i}: ${t}; falling back to the filename`),o.has(r)||o.set(r,{name:r,description:``,source:n});continue}let s=xt(a),c=s?.name??r;c.length!==0&&(o.has(c)||o.set(c,{name:c,description:(s?.description??``).trim(),source:n}))}}return[...o.values()]}function At(e){return kt(e).map(e=>e.name).sort()}function jt(e){let t=kt(e),n="`agent` is optional: omit it for a fresh generalist pi with pi's own system prompt and its full toolset. Name a definition to NARROW the child instead.";if(t.length===0)return n+` None are registered here, so there is nothing to name.`;let r=t.map(e=>{let t=e.description.length>0?e.description:`(no description given)`;return`- ${e.name} (${e.source} scope): ${t}`});return n+"\nRegistered definitions — pass `agentScope` matching the scope shown, since it defaults "+`to "user" and does not see the others:
|
|
10
10
|
`+r.join(`
|
|
11
|
-
`)}function Mt(e){let{userDir:t,projectDir:n}=Ct(e),r=At(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 Nt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:`agent, when given, must be a non-empty string — omit it entirely to dispatch a generalist child; `+Mt(e)}}function Pt(e){return e!==void 0&&(typeof e!=`string`||e.trim().length===0)}function Ft(e){return e===void 0}function It(e,t,n){if(Ft(e.agent))return{kind:`resolved`,agent:
|
|
11
|
+
`)}function Mt(e){let{userDir:t,projectDir:n}=Ct(e),r=At(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 Nt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:`agent, when given, must be a non-empty string — omit it entirely to dispatch a generalist child; `+Mt(e)}}function Pt(e){return e!==void 0&&(typeof e!=`string`||e.trim().length===0)}function Ft(e){return e===void 0}function It(e,t,n){if(Ft(e.agent))return{kind:`resolved`,agent:lt};let r=St(e.agent,t,n);return r?{kind:`resolved`,agent:r}:{kind:`unknown`,name:e.agent}}function Lt(e,t,n,r=0){return{text:``,status:`rejected`,started:!1,agentName:e,durationMs:r,exitCode:1,reportChannel:`none`,errorMessage:`unknown agent: `+e+` (agentScope=`+t+`, cwd=`+n+`). `+Mt({cwd:n,agentScope:t})}}function Rt(e){let t=e.tools??[];if(!bt(e))return t.length>0?t:void 0;if(t.length!==0)return t.includes(`ptc_child_report`)?t:[...t,Ie]}function zt(e,t,n){let r=[`--mode`,`json`,`-p`,`--no-session`],i=e.model??t.model;i&&r.push(`--model`,i);let a=e.thinkingLevel??`off`;r.push(`--thinking`,a);let o=Rt(t);return o!==void 0&&r.push(`--tools`,o.join(`,`)),r.push(`--append-system-prompt`,n),r.push(`Task: `+e.task),r}let Bt=Vt;async function Vt(e,t){let n=await C.promises.mkdtemp(O.join(D.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=O.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function Ht(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function Ut(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 Wt(e,t){if(t.type!==`message_end`)return e;let n=t.message;if(n?.role!==`assistant`||n.usage===void 0)return e;let r=e??{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0,turns:0};return r.input+=n.usage.input??0,r.output+=n.usage.output??0,r.cacheRead+=n.usage.cacheRead??0,r.cacheWrite+=n.usage.cacheWrite??0,r.cost+=n.usage.cost?.total??0,r.turns+=1,r}function Gt(e){let t=[],n;for(let r of e.split(`
|
|
12
12
|
`)){let e=r.trim();if(n===void 0){let t=/^(`{3,}|~{3,})(.*)$/.exec(e);t&&(n={marker:(t[1]??``)[0],info:(t[2]??``).trim(),body:[]});continue}RegExp(`^`+n.marker+`{3,}\\s*$`).test(e)?(t.push({info:n.info,body:n.body.join(`
|
|
13
13
|
`)}),n=void 0):n.body.push(r)}return n!==void 0&&t.push({info:n.info,body:n.body.join(`
|
|
14
|
-
`)}),t}function Kt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function qt(e){if(!Kt(e))return;let{summary:t,findings:n,files_touched:r}=e;if(typeof t!=`string`||!Array.isArray(n))return;let i=[];for(let e of n){if(!Kt(e)||typeof e.what!=`string`||typeof e.evidence!=`string`)return;i.push({what:e.what,evidence:e.evidence})}if(!Array.isArray(r))return;let a=[];for(let e of r){if(typeof e!=`string`)return;a.push(e)}return{summary:t,findings:i,files_touched:a}}function Jt(e){let t=Gt(e),n=t[t.length-1];if(n===void 0)return{reportChannel:`none`};let r;try{r=JSON.parse(n.body)}catch{return{reportChannel:`none`}}let i=qt(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function Yt(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return qt(e.result?.structuredContent)}function Xt(){return{prompt:{reportChannel:`none`},tool:void 0}}function Zt(e,t){let n=Yt(t);n!==void 0&&(e.tool=n)}function Qt(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function $t(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 en(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return
|
|
15
|
-
`)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return
|
|
16
|
-
`);return e===-1?t:t.slice(0,e)}}}}function
|
|
17
|
-
`),`Exceptions: `+[...
|
|
18
|
-
`),
|
|
19
|
-
`)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=
|
|
20
|
-
`))r.push(e.length===0?``:`${i} ${e}`);continue}let o=
|
|
21
|
-
`):typeof e!=`object`||!e?[String(e)]:
|
|
14
|
+
`)}),t}function Kt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function qt(e){if(!Kt(e))return;let{summary:t,findings:n,files_touched:r}=e;if(typeof t!=`string`||!Array.isArray(n))return;let i=[];for(let e of n){if(!Kt(e)||typeof e.what!=`string`||typeof e.evidence!=`string`)return;i.push({what:e.what,evidence:e.evidence})}if(!Array.isArray(r))return;let a=[];for(let e of r){if(typeof e!=`string`)return;a.push(e)}return{summary:t,findings:i,files_touched:a}}function Jt(e){let t=Gt(e),n=t[t.length-1];if(n===void 0)return{reportChannel:`none`};let r;try{r=JSON.parse(n.body)}catch{return{reportChannel:`none`}}let i=qt(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function Yt(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return qt(e.result?.structuredContent)}function Xt(){return{prompt:{reportChannel:`none`},tool:void 0}}function Zt(e,t){let n=Yt(t);n!==void 0&&(e.tool=n)}function Qt(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function $t(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 en(e,t,n){let r=t.depth+1;if(r>t.maxDispatchDepth)return mt();if(Pt(e.agent))return Nt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`});let i=De(),a=n.slots??at;if(!a.tryAcquire(i))return ht();let o=n.clock??(()=>Date.now()),s=n.logger??ct,c=e.cwd??t.cwd,l=e.agentScope??`user`,u=n.lifecycle??rt,d=t.callerId??`dispatch:`+String(t.callId),f=st(n,o),p=n.outputStorage,m=It(e,c,l);if(m.kind===`unknown`)return a.release(i),Lt(m.name,l,c);let h=m.agent,g,_;try{let n=e.label??e.task.slice(0,64),l=bt(h),m=ut(h.systemPrompt,r,t.maxDispatchDepth,{reportContract:l}),v=await Bt(h.name,m);_=v;let y=zt(e,h,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),g=u.spawn([`pi`,...y],b);let x=g,S={kind:`ptc-program`,callerId:d};await f.transition({kind:`spawn`,handle:{taskId:i,label:n,status:`running`},record:{label:n,agentName:h.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=pt(u,x,{isDone:()=>C,unref:!0})))});return(async()=>{let e=``,t,n=Xt(),r;try{for await(let i of u.events(x)){Zt(n,i);let a=Ut(i);a!==void 0&&(e=a,n.prompt=Jt(a)),r=Wt(r,i);let o=$t(i);o!==void 0&&(t=o)}C=!0,w?.();let a=(await u.exit(x)).code??-1,c=Buffer.byteLength(e,`utf8`),m=c<=2048?e:void 0,h;if(p!==void 0)try{await p.writeOutput(i,e),h=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)}let g=l?Qt(n):{reportChannel:`opted-out`};await f.transition({kind:`resolve-exit`,taskId:i,exitCode:a,reportChannel:g.reportChannel,...g.report===void 0?{}:{report:{...g.report,usage:{input:r?.input??0,output:r?.output??0,cost:r?.cost??0,turns:r?.turns??0}}},outputRef:h,outputBytes:c,outputPreview:m,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?.(),Ht(v),a.release(i)}})(),{taskId:i,label:n,status:`running`}}catch(e){let t=e instanceof Error?e.message:String(e);return g!==void 0&&pt(u,g,{unref:!0}),_!==void 0&&Ht(_),a.release(i),s.warn(`background dispatch failed for agent `+h.name+`: `+t),{text:``,status:`rejected`,started:g!==void 0,agentName:h.name,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`background dispatch failed: `+t}}}async function tn(e,t,n={}){if(e.background===!0)return await en(e,t,n);let r=t.depth+1;if(r>t.maxDispatchDepth)return dt();let i=e.cwd??t.cwd,a=e.agentScope??`user`,o=Date.now();if(Pt(e.agent))return Nt({cwd:i,agentScope:a});let s=n.slots??at;if(!s.tryAcquire())return ft();let c=It(e,i,a);if(c.kind===`unknown`)return s.release(),Lt(c.name,a,i,Date.now()-o);let l=c.agent,u=bt(l),d=ut(l.systemPrompt,r,t.maxDispatchDepth,{reportContract:u}),f,p=n.lifecycle??rt,m;try{f=await Bt(l.name,d),m=zt(e,l,f.filePath)}catch(e){throw s.release(),e}return await new Promise(e=>{let a=``,c,d=Xt(),h=-1,g=``,_=!1,v,y,b=!1,x=(r,i,m=!0)=>{if(_)return;_=!0,s.release(),y!==void 0&&p.exit(y).catch(e=>{(n.logger??ct).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),v?.(),t.signal&&t.signal.removeEventListener(`abort`,S),Ht(f);let b=u?Qt(d):{reportChannel:`opted-out`},x={text:a,status:r,started:m,agentName:l.name,durationMs:Date.now()-o,exitCode:h,reportChannel:b.reportChannel};b.report&&(x.report={...b.report,usage:{input:c?.input??0,output:c?.output??0,cost:c?.cost??0,turns:c?.turns??0}}),c&&(x.usage=c),g.length>0&&(x.stderr=g),i&&(x.errorMessage=i),e(x)},S=()=>{y&&!_&&(b=!0,v=pt(p,y,{isDone:()=>_}))};try{y=p.spawn([`pi`,...m],{cwd:i,env:{...process.env,PI_PTC_DEPTH:String(r)},promptFile:f.filePath})}catch(e){x(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?S():t.signal.addEventListener(`abort`,S,{once:!0})),(async()=>{if(!y)return;let e=y;try{for await(let t of p.events(e))if(Zt(d,t),t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(c=Wt(c,t),Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(a=t.text,d.prompt=Jt(t.text))}let t=await rt.exit(e);h=t.code??-1,g=await rt.stderr(e);let n=g.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){x(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:r,errorMessage:i}=gt({exitCode:h,finalText:a,aborted:b});x(r,i)}catch(e){let t=e instanceof Error?e.message:String(e);x(`rejected`,`dispatch internal error: `+t)}})()})}const L=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],R=`pi.dispatch`,nn=[`bash`];function rn(e){return nn.includes(e)}function an(e){if(e===void 0)return[];let t=new Set(e);for(let e of t)if(!rn(e))throw TypeError(`unknown PTC opt-in binding "${e}"; opt-in bindings: ${nn.join(`, `)}`);return L.filter(e=>t.has(e))}const on=L.filter(e=>!rn(e)),sn={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},cn=x.Object({agent:x.Optional(x.String({minLength:1,description:`Optional. Name a registered agent definition to narrow the child, or omit it entirely for a fresh generalist pi with pi's own prompt and its full toolset. A name with no definition behind it is refused; an empty string is refused.`})),task:x.String({minLength:1}),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)],{description:`Which agent directories to search: "user" (~/.pi/agent/agents, the default), "project" (<cwd>/.pi/agents), or "both". Defaults to "user", which cannot see project agents.`})),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String())}),ln={name:R,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:cn};function un(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 dn(e){let t=new Set(an(e.optIns)),n=e.names??L.filter(e=>on.includes(e)||t.has(e)),r=e.includeDispatch??e.names===void 0,i=/* @__PURE__ */ new Map;for(let t of n){let n=sn[t];if(!n)throw TypeError(`unknown PTC binding "${t}"; known bindings: ${L.join(`, `)}`);let r=n(e.cwd);i.set(t,{name:t,execute:async(e,t)=>{let n=`ptc:${t.callId}`,i={type:`toolCall`,id:n,name:r.name,arguments:e},a=S(r,i),o=await r.execute(n,a,t.signal,void 0);if(o.isError===!0)throw Error(un(r.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
|
|
15
|
+
`)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return r&&i.set(R,{name:R,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:R,arguments:t},i;try{i=S(ln,r)}catch(n){let r=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,i=r?.agent,a=r?.agentScope;return Pt(i)?Nt({cwd:e.cwd,agentScope:a===`user`||a===`project`||a===`both`?a:`user`}):{text:``,status:`rejected`,started:!1,agentName:typeof i==`string`?i:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:n instanceof Error?n.message:String(n)}}return tn(i,{signal:n.signal,callId:n.callId,cwd:e.cwd,depth:n.depth,maxDispatchDepth:n.maxDispatchDepth,...n.callerId===void 0?{}:{callerId:n.callerId},...n.sessionDir===void 0?{}:{sessionDir:n.sessionDir},...n.parentTaskId===void 0?{}:{parentTaskId:n.parentTaskId}},n.dispatchDeps)}}),i}function fn(){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 pn(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 z={acquireLatency:ue.channel(`ptc:pool:acquire-latency`),resetTime:ue.channel(`ptc:worker:reset-time`),imageBytes:ue.channel(`ptc:image:hoist-bytes`)};function B(e,t){e.publish(t)}var mn=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(),B(z.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),B(z.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),B(z.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 le(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 hn(e){B(z.imageBytes,{byteLength:e})}function gn(e){B(z.resetTime,{durationMs:e})}function _n(){let e=ie(de(import.meta.url)),t=[j(e,`worker.js`),j(e,`worker-entry.ts`)];for(let e of t)if(w(e))return fe(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function vn(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 V(e){return e instanceof Error?e.message:String(e)}function yn(e){if(typeof e!=`object`||!e)return;let t=e.content;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e==`object`&&e){let t=e.text;if(typeof t==`string`&&t.length>0){let e=t.indexOf(`
|
|
16
|
+
`);return e===-1?t:t.slice(0,e)}}}}function bn(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function xn(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 Sn(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>bn(t)?null:t)??``,`utf8`),n=0;return xn(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function Cn(e){let i=ze(e.config),s=Re(),c=e.runId??N(),l=Be(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new le(_n(),pn({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: ${V(e)}`}}}return await new Promise(s=>{let m=new ce,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=fn(),b=()=>{v||e.onSubCallChange?.(()=>y.snapshot())},x={recordStart(e,t,n){y.recordStart(e,t,n),b()},recordEnd(e,t,n){let r=y.recordEnd(e,t,n);return b(),r},snapshot:()=>y.snapshot()},S,C=!1,w=0,T=0,ee=new it(i.dispatchConcurrency),E=0,te=[],D=e.depth??0,ne,O,re=[],ie=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},k=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,A=e=>e===`timeout`?n.timeout:n.abort,j=t=>{if(v)return;v=!0,ne&&clearTimeout(ne),O&&clearTimeout(O),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)},M=(e,t,n)=>{j({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},ae=e=>{if(!v){if(!r(e)){M(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},oe=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...L],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){M(n.protocol,`internal error: malformed init frame`);return}let a=Sn(t);if(a>i.maxMessageBytes){M(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}ae(t)},N=(e,t)=>(T+=e,T<=i.maxOutputBytes||(M(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),se=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},ue=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),M(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}de(e).finally(()=>{--w})},de=async t=>{let r=e.bindings.get(t.tool);if(!r){x.recordEnd(t.callId,`error`,{errorMessage:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)}),fe({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===R;if(!a&&(await se(),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:D,maxDispatchDepth:i.maxDispatchDepth,callerId:c,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...e.sessionDir===void 0?{}:{sessionDir:e.sessionDir},dispatchDeps:{...e.dispatchDeps,slots:e.dispatchDeps?.slots??ee}}),l=ie(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Sn(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),M(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(fe(u))for(let e of l)re.push(e),hn(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?vn(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:yn(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:V(e)}):x.recordEnd(t.callId,`error`,{errorMessage:V(e)}),fe({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:V(e)})}finally{a||le()}},fe=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: ${V(t)}`})}catch{M(n.protocol,`binding result is not transferable`)}return!1}},P=e=>S?{logs:u,narrations:d,phases:f,error:{kind:A(S),message:k(S)}}:e,F=r=>{if(v)return;if(!a(r)){M(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Sn(r);if(!Number.isFinite(o)){M(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){M(n.protocol,`control frame of ${o} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}switch(r.kind){case t.ready:if(e.pool){let t=e.pool.lastSettledAt(p);t!==void 0&&gn(Date.now()-t)}if(!C&&(C=!0,S)){me(S);return}oe();return;case t.call:ue(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,...re.length>0?{images:re}:{}};j(P(r.value===void 0?e:{...e,value:r.value}));return}case t.error:j(P({logs:u,narrations:d,phases:f,error:r.error}));return;default:M(n.protocol,`unknown worker frame`)}};function pe(){he(`abort`)}let me=e=>{O&&clearTimeout(O),O=setTimeout(()=>{M(A(e),k(e))},i.graceMs)};function he(e){if(!v){if(S){M(A(S),k(S));return}S=e,_.abort(),ae({kind:o.cancel,reason:e}),me(e)}}p.on(`error`,e=>{M(n.workerExit,`worker failed: ${V(e)}`)}),p.on(`exit`,e=>{M(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,F),h.on(`messageerror`,()=>{M(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,pe,{once:!0}),ne=setTimeout(()=>{he(`timeout`)},l);let ge={kind:o.connect,port:g};r(ge)?p.postMessage(ge,[g]):M(n.protocol,`internal error: malformed connect frame`)})}const wn=["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`."],[R,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),En=[wn.join(`
|
|
17
|
+
`),`Exceptions: `+[...Tn.values()].join(` `)].join(`
|
|
18
|
+
`),Dn=`pi-ptc-output-`;function On(e,t=Dn){let n=k(ne(),`${t}${N()}.txt`);return te(n,e,`utf8`),n}function kn(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 An(e,t=Dn,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=On(n.fullText??e,t);return{text:`${r.content}\n\n${kn(r,i)}`,truncated:!0,fullPath:i}}const jn=200,Mn=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 Nn(e){return!e.includes(`\x1B`)&&!e.includes(``)?e:e.replace(Mn,``)}function H(e){let t=Nn(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 Pn=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function Fn(e){return Pn.test(e)?e:JSON.stringify(e)}function In(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=H(e);return t.includes(`
|
|
19
|
+
`)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=In(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=In(e[r]??null);if(t===void 0)return;n.push(`${Fn(r)}: ${t}`)}return`{${n.join(`, `)}}`}function Ln(e){let t=In(e);if(t!==void 0)return t.length<=100?t:void 0}function Rn(e){return e===null?`null`:typeof e==`string`?H(e):String(e)}function zn(e,t){if(typeof e!=`object`||!e)return[`${t}${Rn(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=Ln(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...Bn(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=Ln(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 H(n).split(`
|
|
20
|
+
`))r.push(e.length===0?``:`${i} ${e}`);continue}let o=zn(n,i);r.push(`${i}${Fn(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function Bn(e,t){return typeof e==`string`?H(e).split(`
|
|
21
|
+
`):typeof e!=`object`||!e?[String(e)]:zn(e,t)}function Vn(e){return e.split(`
|
|
22
22
|
`).map(e=>e.length>200?`${e.slice(0,199)}…`:e).join(`
|
|
23
|
-
`)}function
|
|
24
|
-
`))}function
|
|
25
|
-
`)}`,i=Error(H(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function
|
|
23
|
+
`)}function Hn(e){if(typeof e==`string`)return Vn(H(e));if(typeof e!=`object`||!e)return String(e);let t=Ln(e);return Vn((t===void 0?Bn(e,``):[t]).join(`
|
|
24
|
+
`))}function Un(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function Wn(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 U(e,t){let n=e===void 0?void 0:new Set(e),r=new Set(an(t));return L.filter(e=>(n===void 0||n.has(e))&&(on.includes(e)||r.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.`],Kn={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function qn(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function Jn(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 Yn(e){return[...e.phases.map(e=>`[phase] ${H(e)}`),...e.narrations.map(e=>`[log] ${H(e)}`),...e.logs.map(e=>H(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=Yn(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
|
|
25
|
+
`)}`,i=Error(H(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function Zn(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=>H(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>H(e)).join(`
|
|
26
26
|
`)),t.logs.length>0&&a.push(t.logs.map(e=>H(e)).join(`
|
|
27
|
-
`)),t.value!==void 0&&a.push(
|
|
28
|
-
`):`(${
|
|
29
|
-
`).find(e=>e.trim().length>0)??``).trim(),120)}function
|
|
30
|
-
`)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return W(e.replace(/\s*\/\/.*$/,``),120)}}function
|
|
31
|
-
`),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:W(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=
|
|
32
|
-
`)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function
|
|
33
|
-
`)){let e=W(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(W(n,Math.max(2,t-5)))+`…`}return`?`}function
|
|
34
|
-
`).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:W(t,200)}function
|
|
35
|
-
`)}function
|
|
36
|
-
`).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new
|
|
37
|
-
`).map(e=>W(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=>H(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=>H(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=>H(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=
|
|
38
|
-
`),
|
|
39
|
-
`),
|
|
40
|
-
`).find(e=>e.trim().length>0)??``).trim(),120)}function
|
|
41
|
-
`),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,
|
|
42
|
-
`),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...
|
|
43
|
-
`),a={tasks:r.map(e=>
|
|
44
|
-
`)}const
|
|
45
|
-
`),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...
|
|
46
|
-
`),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...
|
|
27
|
+
`)),t.value!==void 0&&a.push(Hn(t.value));for(let e of r)a.push(`Warning: ${H(e)}`);let o=An(a.length>0?a.join(`
|
|
28
|
+
`):`(${Kn[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 Qn=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function $n(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function er(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 tr(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=er(e,n):(n+=1,r+=1);return n}function nr(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:rr(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 rr(e,t,n){return e.map(e=>{let r=$n(e),i=Qn.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=tr(e,s),l=tr(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 ir={run_code:`PTC`,workflow:`PTC workflow`},ar=`├─ `,or=`└─ `,sr=`│ `;var cr=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>lr(e,t))}};function lr(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 W(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function ur(e){return W((H(e).split(`
|
|
29
|
+
`).find(e=>e.trim().length>0)??``).trim(),120)}function dr(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function G(e,t){return`${e} ${t}${e===1?``:`s`}`}function fr(e){for(let t of e.split(`
|
|
30
|
+
`)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return W(e.replace(/\s*\/\/.*$/,``),120)}}function pr(e){if(e===void 0)return;if(typeof e==`string`){let t=H(e).split(`
|
|
31
|
+
`),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:W(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=Hn(e);if(!t.includes(`
|
|
32
|
+
`)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function mr(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,G(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,G(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,G(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,G(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,dr(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function hr(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 gr(e,t,n){let r=` `+(t?or:ar),i=` `+(t?` `:sr),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 _r(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const vr=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function yr(e){return vr.test(e)?e:JSON.stringify(e)}function br(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=H(e);if(n.length===0)return`""`;if(n.includes(`
|
|
33
|
+
`)){let e=W(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(W(n,Math.max(2,t-5)))+`…`}return`?`}function xr(e){return typeof e!=`object`||!e}function Sr(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(xr))return;let n=`[`+e.map(e=>br(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(xr))return;let r=`{`+n.map(n=>{let r=e[n]??null;return yr(n)+`: `+br(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Cr(e,t,n,r,i,a,o,s,c){let l=n+(r?`└─ `:`├─ `),u=n+(r?` `:`│ `);if(s>=i){c.push(K(l+t+`…`,o));return}if(Array.isArray(e)&&e.length===0){c.push(K(l+t+`[]`,o));return}if(!Array.isArray(e)&&typeof e==`object`&&e&&Object.keys(e).length===0){c.push(K(l+t+`{}`,o));return}if(typeof e!=`object`||!e){let n=Math.max(0,o-F(l)-t.length);c.push(K(l+t+br(e,n),o));return}let d=Sr(e,Math.max(0,o-F(l)-t.length));if(d!==void 0){c.push(K(l+t+d,o));return}let f=Array.isArray(e),p=f?e.length:Object.keys(e).length,m;m=f?`Array(`+p+`)`:p>a?`{`+a+` of `+p+`}`:`{`+p+` keys}`,c.push(K(l+t+m,o));let h=Math.min(a,p);if(f)for(let t=0;t<h;t+=1){let n=t===h-1&&p<=h;Cr(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];Cr(e[l]??null,yr(l)+`: `,u,r,i,a,o,s+1,c)}}if(p>h){let e=f?`items`:`keys`;c.push(K(u+`└─ …+`+(p-h)+` more `+e,o))}}function K(e,t){if(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 wr(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!_r(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[br(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;Cr(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];Cr(e[d]??null,yr(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}const Tr=`child report`;function Er(e){return e===0?`[]`:`Array(${e})`}function Dr(e){let t=H(e).split(`
|
|
34
|
+
`).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:W(t,200)}function Or(e){let t=Number(e.cost.toFixed(4));return`in ${e.input} · out ${e.output} · cost ${t} · ${G(e.turns,`turn`)}`}function kr(e,t,n){let r=H(n).replace(/\n/g,` `).trim();return r.length<=150?`${e}${t}evidence: ${r}`:`${e}${t}evidence: ${r.slice(0,150)}… (truncated at 150 chars)`}function Ar(e,t){let n=[];return e.forEach((r,i)=>{let a=i===e.length-1&&t===0,o=`[${i}]`;n.push(`${a?`└─ `:`├─ `}${o} ${H(r.what).trim()}`.trimEnd()),n.push(kr(a?` `:`│ `,` `.repeat(o.length+2),r.evidence))}),t>0&&n.push(`└─ …+${t} more findings withheld (a report renders at most 20)`),n}function jr(e,t){let n=e.map((n,r)=>`${r===e.length-1&&t===0?`└─ `:`├─ `}[${r}] `+`${H(n).trim()}`.trimEnd());return t>0&&n.push(`└─ …+${t} more files withheld (a report renders at most 20)`),n}function Mr(e){let t=e===`none`?`no child report was returned — the child did not comply with the contract, so its prose below is unbacked by a report`:e===`opted-out`?`this agent opts out of the report contract, so none was asked for — the prose below is the whole of what it produced, and nothing is missing`:`the ${e} channel was announced but no report reached the host; the child's prose below is everything it produced`;return`${Tr} (channel: ${e})\n${or}${t}`}function Nr(e,t){if(e===void 0)return Mr(t);let n=e.findings.slice(0,20),r=e.findings.length-n.length,i=e.files_touched.slice(0,20),a=e.files_touched.length-i.length,o=[{label:`summary`,head:Dr(e.summary),rows:[]},{label:`findings`,head:Er(e.findings.length),rows:Ar(n,r)},{label:`files`,head:Er(e.files_touched.length),rows:jr(i,a)},{label:`usage`,head:Or(e.usage),rows:[]}],s=[`${Tr} (channel: ${t})`];return o.forEach((e,t)=>{let n=t===o.length-1,r=e.label.length>=8?`${e.label} `:e.label.padEnd(8);s.push(K(`${n?or:ar}${r}${e.head}`,200));let i=n?` `:sr;for(let t of e.rows)s.push(K(`${i}${t}`,200))}),s.join(`
|
|
35
|
+
`)}function Pr(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=fr(e.code??e.script??``),o=i.length>0?i:a??`(no description)`;return nr(new cr([{left:`└─ ${`${t.fg(`toolTitle`,t.bold(ir[n]))} ${t.fg(`accent`,o)}`}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??Fr,state:r.state??{}})}function Fr(){}function Ir(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return ur(t?.text??``)||`failed`}function Lr(e,t){if(e===`pi.dispatch`&&typeof t==`object`&&t){let e=t.agent;return typeof e==`string`&&e.trim().length>0?`→ ${e}`:e===void 0?`→ (generalist)`:`→ ${JSON.stringify(e)}`}if(typeof t==`object`&&t){let n=t,r=e=>typeof n[e]==`string`?n[e]:void 0,i=e===`read`?r(`path`):e===`bash`?r(`command`):e===`grep`||e===`find`?r(`pattern`):e===`ls`||e===`edit`||e===`write`?r(`path`):void 0;if(typeof i==`string`)return i}try{let e=JSON.stringify(t).replace(/\n/g,` `);return e.length>40?`${e.slice(0,39)}…`:e}catch{return String(t).slice(0,40)}}const Rr={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${dr(e.durationMs)}`,themeSlot:`accent`},error:{text:e=>`failed: ${e.errorMessage??`error`}`,themeSlot:`error`},cancelled:{text:()=>`cancelled`,themeSlot:`muted`},rejected:{text:e=>`rejected: ${e.errorMessage??`concurrency`}`,themeSlot:`warning`}};function zr(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=Lr(e.name,e.args),l=Rr[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 Br(e,t,n,r=!1,i=!1){let a=mr(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${Ir(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(_r(s))return wr(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=pr(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function Vr(e,t,n,r={}){let i=hr(e.details),a=[...Br({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...zr(i.subCalls,n)),new cr(a)}function Hr(e,t,n,r,i={}){let a=hr(e.details);if(n){let t=[...Br({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...zr(a.subCalls,r));let n=H(e.content?.find(e=>e.type===`text`)?.text??Ir(e));for(let e of n.split(`
|
|
36
|
+
`).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new cr(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
|
|
37
|
+
`).map(e=>W(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=>H(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=>H(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=>H(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=Br({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...zr(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...gr(o[e]??{label:``,lines:[]},t,r))}return new cr(u)}function Ur(e){return{renderCall(t,n,r){return Pr(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?Hr(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):Vr(e,r?.isError===!0,n,{isPartial:i})}}}const Wr=["Run a TypeScript program that composes pi's tools in one shot. Required arguments: `code` —","the body of an async function (top-level `return` and `await` work; type annotations are","advisory, the code runs type-stripped) — and `description`, a 5-10 word summary of what the",`program does.`,``,"Inside the program, call this session's enabled built-in tools as `tools.<name>(args)` — e.g.",'`await tools.read({ path: "src/index.ts" })`.',`The bound names are this session's active built-in tools, less any binding the install has not`,`explicitly opted in — this surface is narrower than the session's tool list on purpose;`,"independent calls may overlap under `Promise.all`.",``,"The parallel binding `pi.dispatch` is always available, registered under its literal dot name —",'call it with string indexing, e.g. `await tools["pi.dispatch"]({ agent: "reviewer", task: "..." })`;',"`tools.pi.dispatch` does not exist. It fans work out to child pi agents, and independent","foreground dispatches compose under `Promise.all` exactly like the built-in calls. The run's","actual bound names (this run, not a static list) are on the `ptcBindings` global, so the program",`never has to guess what is bound.`,``,En,``,"Only the program's return value and its `console.log` output come back. This surface has no","helpers: `log` / `phase` / `parallel` / `pipeline` exist only in `ptc_workflow`.",``,"Image-bearing tool results inside the program (a `tools.read` on a PNG, say) are attached to you",`after the run, so never return image data as the completion value — that only spends your context`,`on base64.`].join(`
|
|
38
|
+
`),Gr=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 Kr(e={}){return g({name:`ptc_run_code`,label:`PTC Run Code`,exposure:e.exposure,description:Wr,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:Gr,async execute(t,n,r,i,a){let o=qn(a),s=U(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=Jn({surface:`run_code`,startedAt:c,onUpdate:i}),p;try{p=await Cn({code:n.code,surface:`run_code`,cwd:o,bindings:dn({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 Zn({outcome:p,surface:`run_code`,durationMs:Date.now()-c})},...Ur(`run_code`)})}const qr=[`Run a structured TypeScript workflow: a named plan that reports phases and narration as it`,"goes. `script` is the body of an async function, `meta` names it (`{ name, description, phases? }`,","where `phases` is the ordered plan), and optional `args` is plain-JSON input bound to the","program's `args` global.",``,"Helpers inside the script: `log(message)` narrates progress; `phase(title)` frames the workflow","(titles outside `meta.phases` are reported as warnings); `parallel(thunks)` runs thunks","concurrently, a failed item becoming `null`; `pipeline(items, ...stages)` chains stages per item","with the same per-item `null` on failure. There is no `agent()` helper.",``,"Tools are reachable as `tools.<name>(args)` exactly as in `ptc_run_code`, and the bound names",`are this session's enabled built-ins less any binding the install has not opted in. The parallel`,"binding `pi.dispatch` is always available under",'its literal dot name — call it with string indexing: `await tools["pi.dispatch"]({ agent, task })`;',"the run's actual bound names are on the `ptcBindings` global. What comes back is the script's","return value, its `log`/`phase` narration and its `console.log` output.",``,En,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
|
|
39
|
+
`),Jr=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 Yr(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=Xr(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function Xr(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=Xr(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=Xr(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function Zr(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 Qr(e={}){return g({name:`ptc_workflow`,label:`PTC Workflow`,exposure:e.exposure,description:qr,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...Gn],parameters:Jr,async execute(t,n,r,i,a){Yr(n.args);let o=qn(a),s=U(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=Jn({surface:`workflow`,startedAt:c,onUpdate:i}),p;try{p=await Cn({code:n.script,surface:`workflow`,cwd:o,bindings:dn({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 Zn({outcome:p,surface:`workflow`,warnings:Zr(p,m),durationMs:Date.now()-c})},...Ur(`workflow`)})}var $r=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 ei(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var ti=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await he(this.#t(e),`utf8`)}catch(e){if(ei(e))return null;throw e}}async writeOutput(e,t){let n=k(this.#e,`tasks`,e);await me(n,{recursive:!0}),await ye(k(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return k(this.#e,`tasks`,e,`output.log`)}};function ni(e,t){return An(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}const ri={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},ii={running:`●`,stopping:`◐`,succeeded:`✓`,failed:`✗`,lost:`◌`,canceled:`⊘`};var q=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>ai(e,t))}};function ai(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 oi(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function si(e){return oi((H(e).split(`
|
|
40
|
+
`).find(e=>e.trim().length>0)??``).trim(),120)}function ci(e){return typeof e==`object`&&e?e:{}}function li(e){return e===`running`||e===`stopping`}function ui(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 di(e,t){if(li(e.status))return ui(t-e.createdAt);if(e.durationMs!==void 0)return ui(e.durationMs);if(e.finishedAt!==void 0)return ui(e.finishedAt-e.createdAt)}function fi(e,t){let{state:n}=t;t.isLive?n.interval??=setInterval(()=>t.requestInvalidate(),1e3):n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0);let r=e;return r.dispose=()=>{n.interval!==void 0&&(clearInterval(n.interval),n.interval=void 0)},e}function pi(){}function mi(e,t,n){return new q([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function hi(e,t,n){let r=ci(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 mi(`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 mi(`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=${H(r.reason)}`:``;return mi(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function gi(e,t,n,r){let i=ri[e.status]??`muted`,a=n.fg(i,ii[e.status]??`?`),o=oi(H(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,H(e.agentName))],c=di(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 _i(e,t){let n=ci(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return fi(new q([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>li(e.status)),a=r.slice(0,32),o=r.length-a.length,s=a.map((e,n)=>gi(e,n===a.length-1&&o===0,t.theme,t.now));return o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),fi(new q(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function vi(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 yi(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function bi(e,t){let n=ci(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=vi(i,a,t.theme),c=[];if(r.length>0){let e=H(r).split(`
|
|
41
|
+
`),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,oi(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:yi(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:yi(o,t.theme),...s===void 0?{}:{right:s}});return new q(c)}function xi(e,t){let n=ci(e),r=n.task;if(typeof r!=`object`||!r)return new q([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=ri[r.status]??`muted`,a=t.theme.fg(i,ii[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`,H(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${H(r.stopReason)}`)),new q([{left:` ${c.join(` `)}`}])}function Si(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=si(n?.text??``)||`failed`;return new q([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function Ci(e,t,n){switch(e){case`task-list`:return _i(t.details,n);case`task-output`:return bi(t.details,n);case`task-stop`:return xi(t.details,n)}}function wi(e){return{renderCall(t,n){return hi(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?Si(t,r):Ci(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??pi,state:i?.state??{},now:Date.now()})}}}const Ti=[`Use ptc_task_list to see the background tasks this session dispatched and their live status.`,`Use ptc_task_output to read a task's captured output (it is tail-truncated; the footer names the full-output file). A succeeded task's child report is rendered there, ahead of the prose.`,`Use ptc_task_stop to ask a running task to stop; the dispatcher delivers the actual signal, so the task transitions through stopping to canceled.`,`These background-task tools stay callable when PTC mode is off — /ptc off only blocks new dispatches.`],Ei=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),Di=x.Object({status:x.Optional(x.Array(Ei,{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.`}))}),Oi=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 ki(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 Ai(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,H(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${H(e.errorMessage)}`),t.join(` `)}function ji(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(`
|
|
42
|
+
`),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...Ti],parameters:Di,outputSchema:Oi,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=>Ai(e)).join(`
|
|
43
|
+
`),a={tasks:r.map(e=>ki(e)),count:r.length};return{content:[{type:`text`,text:i}],details:{tasks:r,count:r.length},structuredContent:a}},...wi(`task-list`)})}async function Mi(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}function Ni(e){let t=e.reportChannel;if(t===void 0)return;if(t===`none`)return`<child-report channel="none">the child produced no report; it did not comply with the report contract. What follows is its prose, unbacked by a report.</child-report>`;if(t===`opted-out`)return`<child-report channel="opted-out">this agent opts out of the report contract, so none was asked for; the prose below is the whole of what it produced, and nothing is missing.</child-report>`;let n=e.report;if(n===void 0)return`<child-report channel="${t}">the record names channel ${t} but carries no report.</child-report>`;let r=[`<child-report channel="${t}">`,`summary: ${n.summary}`],i=n.findings.slice(0,20),a=n.findings.length-i.length;r.push(`findings (${String(n.findings.length)}):`);for(let[e,t]of i.entries())r.push(` ${String(e+1)}. ${t.what} — evidence: ${t.evidence}`);return a>0&&r.push(` …+${String(a)} more findings not shown`),r.push(n.files_touched.length===0?`files_touched: (none)`:`files_touched: ${n.files_touched.join(`, `)}`),r.push(`usage: input=${String(n.usage.input)} output=${String(n.usage.output)} cost=${String(n.usage.cost)} turns=${String(n.usage.turns)}`),r.push(`</child-report>`),r.join(`
|
|
44
|
+
`)}const Pi=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.`}))}),Fi=x.Object({task_id:x.String({description:`The background task id that was asked for.`}),status:x.String({description:`The task's status at read time (ADR-0022 §2's six states), so a polling script does not need a second ptc_task_list call.`}),output:x.String({description:`The page the model reads: the stored output's tail, ADR-0015-truncated.`}),output_bytes:x.Number({description:`Total bytes stored for the task, regardless of sinceBytes or ADR-0015 truncation.`}),output_preview:x.Optional(x.String({description:`The complete stored output; present only at or below the 2048-byte preview ceiling (ADR-0022 §7).`})),output_truncated:x.Boolean({description:"Whether ADR-0015 cut anything out of `output`."}),output_full_path:x.Optional(x.String({description:"A file holding the complete output; present only when `output_truncated` is true (ADR-0015 §2)."})),report_channel:x.Optional(x.String({description:"Which channel delivered the child's report: `tool`, `prompt-json`, or `none` when the child ignored the contract (ADR-0032). Absent until the task succeeds — a running or failed task carries no report claim at all."})),report:x.Optional(x.Object({summary:x.String({description:`The child's own one-line summary.`}),findings:x.Array(x.Object({what:x.String({description:`The claim the child makes.`}),evidence:x.String({description:`The evidence that claim rests on.`})}),{description:`One entry per claim the child made.`}),files_touched:x.Array(x.String(),{description:`Paths the child says it touched.`}),usage:x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})})}))});function Ii(e,t){return g({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`A succeeded task also renders its child report (summary, findings, files touched, usage) ahead of the prose, and says which channel delivered it; a channel of "none" means the child ignored the report contract.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
|
|
45
|
+
`),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...Ti],parameters:Pi,outputSchema:Fi,async execute(n,r){let i=r.taskId,a=await Mi(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=ni(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f=Ni(a),p={taskId:i,output:u.text,outputBytes:s,...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath},...a.report===void 0?{}:{report:a.report},...a.reportChannel===void 0?{}:{reportChannel:a.reportChannel}},m=p.output.length>0?p.output:`(no output yet; task ${i} is ${a.status})`,h=f===void 0?m:`${f}\n${m}`,g={task_id:i,status:a.status,output:u.text,output_bytes:s,...d===void 0?{}:{output_preview:d},output_truncated:u.truncated,...u.fullPath===void 0?{}:{output_full_path:u.fullPath},...a.reportChannel===void 0?{}:{report_channel:a.reportChannel},...a.report===void 0?{}:{report:a.report}};return{content:[{type:`text`,text:h}],details:p,structuredContent:g}},...wi(`task-output`)})}const Li=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 zi(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(`
|
|
46
|
+
`),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...Ti],parameters:Li,outputSchema:Ri,async execute(t,n){let i=n.taskId,a=await Mi(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=${H(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}},...wi(`task-stop`)})}var Bi=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=ze(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Re(),r=new mn({buildWorkerUrl:_n,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:pn({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 Vi={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var Hi=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??Vi,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 Ui={mkdir:(e,t)=>me(e,t),readFile:(e,t)=>he(e,t),writeFile:(e,t,n)=>ye(e,t,n),appendFile:(e,t,n)=>pe(e,t,n),rename:(e,t)=>_e(e,t),unlink:e=>ve(e),readdir:e=>ge(e)};function Wi(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function Gi(e){return e instanceof Error?e.message:String(e)}function Ki(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var qi=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??Ui}async loadTask(e){return await this.#r(this.#f(e))}async saveTask(e){se(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){se(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||Ki(r[t-1],e)<=0)?r:[...r].sort(Ki)).map(e=>JSON.stringify(e)).join(`
|
|
47
47
|
`)+`
|
|
48
|
-
`;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(
|
|
49
|
-
`)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+
|
|
50
|
-
`);return`${`<bg-task-notifications batch-id="${Y(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function
|
|
48
|
+
`;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(Ki);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(Wi(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+`: `+Gi(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(Wi(e))return[];throw e}let n=[];for(let r of t.split(`
|
|
49
|
+
`)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+Gi(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(ie(e),{recursive:!0});let n=e+`.tmp-`+N();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(Wi(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(Wi(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 Ji(e,t){return new qi(e,t)}const Yi=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Xi=/* @__PURE__ */ new Set([`running`,`stopping`]),Zi=2**53-1,Qi={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function J(e){return e instanceof Error?e.message:String(e)}function $i(e){return e===void 0||e.length===0?`<in-memory>`:e}function ea(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var ta=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()}},na=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)}},ra=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)}},ia=class{#e;#t=/* @__PURE__ */ new Set;#n=/* @__PURE__ */ new Map;constructor(e){this.#e=e}isLive(e){return this.#t.has(e)}trackReapCancel(e,t){this.#n.set(e,t)}spawn(e,t){let n=this.#e.spawn(e,t);return this.#t.add(n),n}kill(e,t){this.#e.kill(e,t)}events(e){return this.#e.events(e)}async exit(e){try{return await this.#e.exit(e)}finally{this.#t.delete(e);let t=this.#n.get(e);t!==void 0&&(this.#n.delete(e),t())}}stderr(e){return this.#e.stderr(e)}liveHandles(){return[...this.#t]}},aa=class{registry;outputStorage;pipeline;slots;lifecycle;dispatchDeps;clock;#e;#t;#n;#r;#i;#a=!1;constructor(e){this.clock=e.clock??(()=>Date.now()),this.#e=e.logger??Qi,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??Xe,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new nt:Ji(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new $r:new ti(e));let t=(e.createInitialStorage??(()=>new nt))(),n=$e(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new Hi(t,{now:this.clock,logger:this.#e});this.registry=new ta(n),this.outputStorage=new na(new $r),this.pipeline=new ra(r),this.lifecycle=new ia((e.createLifecycle??(()=>new Fe({logger:this.#e})))()),this.slots=new it(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||Yi.has(e.status)&&this.pipeline.notifyIdle(t.subscriptionId,e.id).catch(t=>{this.#e.warn(`terminal notification wake for task `+e.id+` failed: `+J(t))})};async bindSession(e,t){let n,r;try{n=this.#t(e),r=this.#n(e)}catch(n){return this.#s(`background runtime: session storage for `+$i(e)+` is unavailable: `+J(n),t),[]}let i=$e(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new Hi(n,{now:this.clock,logger:this.#e});this.registry.setCurrent(i),this.outputStorage.setCurrent(r),this.pipeline.setCurrent(a),this.#a=!1;try{return await i.reconcileLostTasks()}catch(e){return this.#s(`background runtime: startup reconcile failed; stale running tasks were not all marked lost (reconcile is not per-record tolerant yet): `+J(e),t),[]}finally{this.registry.onTransition(this.#o)}}async drainNotifications(e){let t;try{t=await this.registry.query({limit:Zi})}catch(t){return this.#e.warn(`drainNotifications: could not list tasks for subscriber `+e+`: `+J(t)),{items:[],acks:[]}}let n=[],r=[],i=this.pipeline.current();for(let a of t){if(a.spawnSource.callerId!==e)continue;let t;try{t=await i.drainPending(e,a.id)}catch(t){this.#e.warn(`drainNotifications: task `+a.id+` for subscriber `+e+`: `+J(t));continue}for(let e of t)n.push({event:e,record:a});let o=t[t.length-1];o!==void 0&&r.push({subscriberId:e,taskId:a.id,cursor:o.eventId,sink:i})}return{items:n,acks:r}}async acknowledgeNotifications(e){for(let t of e)try{await t.sink.acknowledgeEvents(t.subscriberId,t.taskId,t.cursor)}catch(e){this.#e.warn(`acknowledgeNotifications: could not acknowledge task `+t.taskId+`: `+J(e))}}async shutdown(e){if(this.#a)return[];this.#a=!0;let t;try{t=await this.registry.query({limit:Zi})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+J(e)),t=[]}let n=[];for(let r of t)if(Xi.has(r.status)&&Ye(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:ea(r),logger:this.#e});n.push(t.record)}catch(e){this.#e.warn(`shutdown: could not mark task `+r.id+` lost: `+J(e))}for(let e of this.lifecycle.liveHandles()){let t=pt(this.lifecycle,e,{isDone:()=>!this.lifecycle.isLive(e),unref:!0});this.lifecycle.trackReapCancel(e,t)}for(let e of n)this.slots.release(e.id);return n}#s(e,t){if(this.#e.warn(e),t!==void 0)try{t(e)}catch(e){this.#e.warn(`bindSession reporter threw: `+J(e))}}};function oa(e={}){return new aa(e)}const sa=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function ca(e){return sa.has(e.status)}function la(e,t){if(e.length===0)return``;let n=e.map(da).join(`
|
|
50
|
+
`);return`${`<bg-task-notifications batch-id="${Y(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function ua(e,t=102400){let n=[],r=[],i=0,a=t-pa;for(let t of e){let e=fa(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 da(e){let{event:t,record:n}=e,r=t.outputBytes??n.outputBytes,i=r??0,a=t.outputPreview??n.outputPreview,o=[` <bg-task-notification`,` id="${Y(t.type)}"`,` task-id="${Y(t.taskId)}"`,` subscription-id="${Y(t.subscriptionId)}"`,` status="${Y(t.status)}"`,` label="${Y(n.label)}"`,` agent-name="${Y(n.agentName)}"`,` depth="${n.depth}"`,` duration-ms="${n.durationMs??0}"`,` transition-at-ms="${t.transitionAtMs}">`,` <output-bytes>${i}</output-bytes>`];return n.outputRef!==void 0&&o.push(` <output-ref>${Y(n.outputRef)}</output-ref>`),r!==void 0&&r<=2048&&a!==void 0&&o.push(` <output-preview>${Y(a)}</output-preview>`),o.push(` </bg-task-notification>`),o.join(`
|
|
51
51
|
`)}function Y(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`"`,`"`).replaceAll(` `,`	`).replaceAll(`
|
|
52
|
-
`,` `).replaceAll(`\r`,` `)}function
|
|
52
|
+
`,` `).replaceAll(`\r`,` `)}function fa(e){return Buffer.byteLength(da(e),`utf8`)}const pa=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),ma=[`ptc_run_code`,`ptc_workflow`],ha=[`read`,`bash`,`edit`,`write`],ga=`ptc-mode`,_a=`ptc-mode`,va=`ptc.json`,ya=`builtins-only`;function ba(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function xa(e){let t=k(e,va),n;try{n=T(t,`utf8`)}catch{return{defaultMode:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch(e){return{defaultMode:!0,source:`invalid`,error:`${t} is not valid JSON (${e instanceof Error?e.message:String(e)})`}}if(typeof r!=`object`||!r||Array.isArray(r))return{defaultMode:!0,source:`invalid`,error:`${t} must contain a JSON object`};let i=r.defaultMode;return i===void 0?{defaultMode:!0,source:`default`}:typeof i==`boolean`?{defaultMode:i,source:`file`}:{defaultMode:!0,source:`invalid`,error:`${t}: "defaultMode" must be a boolean, received ${typeof i}`}}function Sa(e){let t=k(e,va),n;try{n=T(t,`utf8`)}catch{return{optInBindings:[],source:`default`}}let r;try{r=JSON.parse(n)}catch{return{optInBindings:[],source:`default`}}if(typeof r!=`object`||!r||Array.isArray(r))return{optInBindings:[],source:`default`};let i=r.optInBindings;if(i===void 0)return{optInBindings:[],source:`default`};if(!Array.isArray(i))return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" must be an array of binding names, received ${typeof i}`};let a=i.find(e=>typeof e!=`string`);if(a!==void 0)return{optInBindings:[],source:`invalid`,error:`${t}: "optInBindings" entries must be strings, received ${typeof a}`};try{return{optInBindings:an(i),source:`file`}}catch(e){return{optInBindings:[],source:`invalid`,error:`${t}: ${e instanceof Error?e.message:String(e)}`}}}const X=`builtin:codemode`;function Z(e){return e.split(M).join(`/`)}function Ca(e){return Z(e.startsWith(`./`)||e.startsWith(`.\\`)?e.slice(2):e)}function wa(e,t,n){let r=Z(A(n,e)),i=re(e),a=Z(e);return t.some(e=>{let t=Z(e);return be(r,t)||be(i,t)||be(a,t)})}function Ta(e,t,n){if(t.length===0)return!1;let r=Z(A(n,e)),i=Z(e);return t.some(e=>{let t=Ca(e);return t===r||t===i})}function Ea(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 Da(e,t){if(!Array.isArray(e))return;let n;for(let{sign:r,target:i}of Ea(e)){let e=r!==`-`&&r!==`!`;(r===`+`||r===`-`?Ta(X,[i],t):wa(X,[i],t))&&(n=e?`enabled`:`disabled`)}return n}function Oa(e,t){if(!Array.isArray(e))return;let n=Ea(e),r=e=>n.filter(t=>t.sign===e).map(e=>e.target),i=r(`!`),a=r(`+`),o=r(`-`),s;return wa(X,i,t)&&(s=`disabled`),Ta(X,a,t)&&(s=`enabled`),Ta(X,o,t)&&(s=`disabled`),s}function ka(e){for(let t=0;t<e.length;t+=1){let n=e[t];if((n===`-e`||n===`--extension`)&&e[t+1]===X)return!0}return!1}function Aa(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 ja(e,t,n,r={project:process.cwd(),user:process.cwd()}){let i=e.slice(1);if(ka(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=Da(a,r.project);if(o!==void 0)return{switch:o,source:`project`};let s=n?.extensions,c=Oa(s,r.user);return c===void 0?{switch:`absent`,source:`default`}:{switch:c,source:`user`}}function Ma(e,t,n=process.argv){let r=Aa(k(t,`.pi`,`settings.json`)),i=Aa(k(e,`settings.json`)),a=ja(n,r.value,i.value,{project:k(t,`.pi`),user:e}),o=r.error??i.error;return o===void 0?a:{...a,source:`invalid`,error:o}}function Na(e){return{activation:e.includes(`codemode`)?`active`:`inactive`,source:`loadout`}}function Pa(e,t,n){return qa(Na(n),Ka(e,t))}const Fa=[`codemode`,`deferred`,`direct`,`hidden`],Ia={"codemode-deferred":`codemode`},La=/^[A-Za-z0-9_-]+$/;function Ra(e){return typeof e==`string`?Ia[e]??e:e}function za(e){return typeof e==`string`&&Fa.includes(e)}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Ba(e){return Q(e)&&Object.values(e).every(e=>typeof e==`string`)}function Va(e){return URL.canParse(e)?/^https?:$/.test(new URL(e).protocol):!1}function Ha(e,t){if(!La.test(e)||!Q(t))return;let n=Ra(t.exposure),r=Q(t.toolExposure)?Object.fromEntries(Object.entries(t.toolExposure).map(([e,t])=>[e,Ra(t)])):t.toolExposure;if(n!==void 0&&!za(n)||r!==void 0&&(!Q(r)||!Object.values(r).every(e=>za(e)))||t.enabled!==void 0&&typeof t.enabled!=`boolean`||t.description!==void 0&&typeof t.description!=`string`||t.timeout!==void 0&&(typeof t.timeout!=`number`||!(t.timeout>0))||t.type===`sse`)return;let i={enabled:t.enabled,exposure:n,toolExposure:r},a=t.type;if(typeof t.url==`string`&&(a===void 0||a===`http`||a===`streamable-http`))return!Va(t.url)||t.headers!==void 0&&!Ba(t.headers)?void 0:i;if(typeof t.command==`string`&&(a===void 0||a===`stdio`))return t.args!==void 0&&!(Array.isArray(t.args)&&t.args.every(e=>typeof e==`string`))||t.env!==void 0&&!Ba(t.env)||t.cwd!==void 0&&typeof t.cwd!=`string`?void 0:i}function Ua(e,t){e.error=e.error===void 0?t:`${e.error}; ${t}`}function Wa(e,t,n,r,i){if(t===void 0){n!==void 0&&Ua(i,n);return}let a;try{a=JSON.parse(t)}catch(t){Ua(i,`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`);return}if(!Q(a)||a.mcpServers!==void 0&&!Q(a.mcpServers)){Ua(i,`${e} must contain a JSON object with an "mcpServers" object`);return}typeof a.autoEnableCodemode==`boolean`?i.autoEnableCodemode=a.autoEnableCodemode:a.autoEnableCodemode!==void 0&&Ua(i,`${e}: autoEnableCodemode must be a boolean`);for(let[e,t]of Object.entries(a.mcpServers??{})){let n=Ha(e,t);if(n===void 0||r===`project`&&Q(t)&&`url`in t&&t.auth)continue;let a=`mcp__${e.replace(/-/g,`_`)}`;[...i.servers.entries()].some(([t,n])=>t!==e&&n.namespace===a)||i.servers.set(e,{namespace:a,server:n})}}function Ga(e,t){let n={autoEnableCodemode:void 0,servers:/* @__PURE__ */ new Map,error:void 0};Wa(e.path,e.raw,e.readError,`global`,n),Wa(t.path,t.raw,t.readError,`project`,n);let r=[...n.servers.values()].some(({server:e})=>e.enabled!==!1&&(/* @__PURE__ */ new Set([e.exposure??`codemode`,...Object.values(e.toolExposure??{})])).has(`codemode`));return{autoEnablesCodemode:n.autoEnableCodemode!==!1&&r,...n.error===void 0?{}:{error:n.error}}}function Ka(e,t){let n=e=>{try{return{path:e,raw:T(e,`utf8`)}}catch(t){return t.code===`ENOENT`?{path:e,raw:void 0}:{path:e,raw:void 0,readError:`${e} could not be read (${t instanceof Error?t.message:String(t)})`}}};return Ga(n(k(e,`mcp.json`)),n(k(t,`.pi`,`mcp.json`)))}function qa(e,t){let n=t.error===void 0?e:{...e,mcpError:t.error};return e.activation===`active`||!t.autoEnablesCodemode?n:{...e,activation:`active`,source:`mcp`,...t.error===void 0?{}:{mcpError:t.error}}}function Ja(e,t,n){return!e.present||t===`disabled`||n!==`active`?`full`:`subagents`}function Ya(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=ie(n);for(let e of Xa){let t=k(r,...e);try{if(E(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const Xa=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function Za(e,t,n,r,i,a=process.cwd()){let o=n??Ya(),s=r??Ma(e,a),c=i??Pa(e,a,t);return{surfaceMode:Ja(o,s.switch,c.activation),codemode:o,codemodeSwitch:s,codemodeActivation:c}}function Qa(e){let t=k(e,va),n;try{n=T(t,`utf8`)}catch{return}let r;try{r=JSON.parse(n)}catch{return}if(typeof r!=`object`||!r||Array.isArray(r))return;let i=r.surfaceMode;return i===void 0?void 0:{path:t,value:i}}function $a(e){return[...new Set(e)]}function eo(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 to(e,t){let n=e=>ma.includes(e);if(t===`all-but-ptc`)return $a(e.filter(n));let r=new Set(L);return $a(e.filter(e=>n(e)||!r.has(e)))}function no(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:ma.some(e=>r.includes(e))?!i&&ha.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:$a(r),loadout:to(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function ro(e,t){return e.enabled&&e.base!==void 0?e.base:t}function io(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!eo(e.ourLoadout,t)}function ao(e,t){let n=t.length>0&&t.every(e=>ma.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function oo(e,t){let n=t===`all-but-ptc`?`Every built-in tool is hidden from you, and so are other extensions' tools.`:`The built-in tools (read, bash, edit, write, grep, find, ls) are hidden from you.`,r=e.map(e=>`tools.${e}(args)`),i=e.slice(0,2).map(e=>e===`read`?`await tools.read({ path: "src/index.ts" })`:e===`bash`?`await tools.bash({ command: "pnpm test" })`:`await tools.${e}({ /* … */ })`).join(`
|
|
53
53
|
`);return[`[PTC MODE ACTIVE]`,`This session runs in PTC mode. `+n,``,`Work by writing one TypeScript program per task and running it:`,` - ptc_run_code for a plain program (its return value and console.log come back to you)`,` - ptc_workflow when the task has named phases and you want narration (log / phase /`,` parallel / pipeline are available there)`,``,`The program body is an async function. Available inside it: ${r.join(`, `)}, plus the`,'parallel binding `tools["pi.dispatch"](args)` — always bound, and its dot name needs string',"indexing (`tools.pi.dispatch` does not exist). The run's actual bound names are on the","`ptcBindings` global, so a program never has to guess what is bound this run.",i.length>0?`Examples:\n${i}`:``,``,`Batch a task's steps into ONE program instead of issuing many tool calls — gathering`,`intermediate output yourself and returning only what matters is the point of this mode.`,`Image-bearing tool results inside a program are attached to you after the run — never return`,`base64 image data as your program's value.`,`If the PTC surfaces cannot express what you need, say so and the user can run /ptc off.`].filter(e=>e.length>0).join(`
|
|
54
|
-
`)}const
|
|
55
|
-
`),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:
|
|
54
|
+
`)}const so=[`read`,`bash`],co=`Use the read tool to load a skill's file when the task matches its description.`,lo=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function uo(e){return!so.some(t=>e.includes(t))}function fo(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(co)?n.replace(co,lo):`${lo}\n\n${n}`}const po=x.Object({task_id:x.Optional(x.String({description:`Id of the background task to poll with ptc_task_output. Present ONLY for a background call; absent once the call has already finished.`})),status:x.String({description:`"background" when this call returned a handle to poll, otherwise the dispatcher's own outcome status ("fulfilled").`}),report_channel:x.String({description:'Which channel delivered the child report: "prompt-json" (a fenced JSON block on the child\'s final message), "tool" (the child called the report tool), "none" (no report arrived — either the child did not comply with the contract, or this is a background handle that has not finished), or "opted-out" (the agent\'s frontmatter set `childReport: false`, so it was never asked). ALWAYS present, so an absent `report` key is never ambiguous — "none" and "opted-out" are different claims about the child.'}),exit_code:x.Optional(x.Number({description:`The child's exit code. Present ONLY for a call that already finished.`})),report:x.Optional(x.Object({summary:x.String({description:`One line, in the child's own words, of what it concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim.`})})),files_touched:x.Array(x.String({description:`A path the child created or modified.`})),usage:x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})})}))});function mo(e){let t=e.taskId;return typeof t==`string`?t:void 0}function ho(e){let t=jt({cwd:e.cwd,agentScope:e.agentRosterScope??`both`,...e.homeDir===void 0?{}:{homeDir:e.homeDir}});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.`,"`agent` is optional — omit it and the child is a fresh generalist pi, with pi's own system prompt and pi's full toolset. Name one to narrow the child instead: an agent is a markdown file at ~/.pi/agent/agents/<name>.md for your machine, or <project>/.pi/agents/<name>.md for one project, and naming one can restrict the child's tools, pin its model, or append a role. A name with no file behind it is refused; the refusal lists what IS registered and how to write one.",t].join(`
|
|
55
|
+
`),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:cn,outputSchema:po,async execute(t,n){let r=await tn(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId}},e.getDispatchDeps?.()??{}),i=mo(r),a=i===void 0?{taskId:void 0,status:r.status,exitCode:r.exitCode}:{taskId:i,status:`background`,exitCode:void 0};if(i!==void 0){let e={task_id:i,status:a.status,report_channel:`none`};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=r.report,s=a.exitCode===void 0?{status:a.status,report_channel:r.reportChannel}:o===void 0?{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel}:{status:a.status,exit_code:a.exitCode,report_channel:r.reportChannel,report:o};return{content:[{type:`text`,text:[Nr(o,r.reportChannel),r.text].filter(e=>e.length>0).join(`
|
|
56
56
|
|
|
57
|
-
`)}],details:a,structuredContent:s}}})}function
|
|
58
|
-
`);function
|
|
59
|
-
`)}function
|
|
57
|
+
`)}],details:a,structuredContent:s}}})}function go(e){return e.length<=200?e:`…`+e.slice(-199)}const _o=x.Object({summary:x.String({description:`One line, in your own words, of what you concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim — what you read, ran or checked. Not the claim restated.`})})),files_touched:x.Array(x.String({description:`A path you created or modified. Empty if you touched nothing.`}))}),vo=[`Hand the host a child report: what you did in this run, in the shape it can read without parsing English.`,`Call it once, at the end. The exact shape is stated in your instructions, which also tell you what to do if this tool is unavailable to you.`,`Evidence is the point of a finding. Put in the independent thing you read, ran or checked — the claim restated is not evidence, and a finding with none is worse than no finding.`,`files_touched lists only paths you actually created or modified; leave it empty rather than guessing.`,`Your prose answer is kept alongside this report and is never replaced by it, so still answer in words.`,`Do not report usage or token counts — those are measured by the host, and anything you send under them is discarded.`].join(`
|
|
58
|
+
`);function yo(e){return g({name:Ie,label:`Child Report`,description:vo,promptSnippet:`Hand the host a child report when you finish`,promptGuidelines:[`Call ptc_child_report once before you finish, even when the answer is "I changed nothing": a child that reports an empty result is a different thing from a child that never reported, and only the first one says so.`],parameters:_o,outputSchema:_o,defaultActive:e,renderCall(e,t){let n=e,r=typeof n?.summary==`string`?n.summary:``;return new q([{left:t.fg(`toolTitle`,t.bold(`Child report`))+(r===``?``:` `+t.fg(`dim`,go(r)))}])},renderResult(){return new q([{left:`child report recorded`}])},async execute(e,t){let n={summary:t.summary,findings:t.findings.map(e=>({what:e.what,evidence:e.evidence})),files_touched:[...t.files_touched]};return{content:[{type:`text`,text:`child report recorded (`+String(n.findings.length)+` findings)`}],details:void 0,structuredContent:n}}})}const $=ya;function bo(e,t,n){return[`PTC mode on — ${t===`all-but-ptc`?`all other tools`:`built-in tools (now reachable only as tools.<name> inside a program)`} hidden.`,`Bindings available inside a program: ${U(e,n).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
|
|
59
|
+
`)}function xo(e,t={}){let n=ba(),r,i=!1,a=new Bi,o=()=>ro(n,e.getActiveTools()),s=Sa(y()),c=s.optInBindings,l=()=>c,u=Un(),d=Wn(),f=t.backgroundRuntime??oa({concurrency:ze({}).dispatchConcurrency}),p=!1,m=e=>{console.warn(`[pi-ptc.background] `+e)},h=t=>{if(t.length!==0){if(p){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},g=async e=>{let{items:t,acks:n}=await f.drainNotifications(e),r=t.filter(e=>ca(e.record));for(let e of ua(r))h(la(e,{batchId:De(),deliveredAtMs:f.clock()}));await f.acknowledgeNotifications(n)},_=async()=>{let e=await f.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},v=async()=>{for(let e of await _())await g(e)},b=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await g(e)};f.pipeline.onIdleWake(e=>{g(e).catch(e=>{m(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})});function x(t){if(t.surfaceMode===`full`||t.surfaceMode===`subagents`){let n=t.surfaceMode===`full`?`direct`:`codemode`;e.registerTool(Kr({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`run_code`),depth:u,exposure:n,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps})),e.registerTool(Qr({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`workflow`),depth:u,exposure:n,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps}))}t.surfaceMode===`subagents`&&e.registerTool(ho({cwd:process.cwd(),depth:u,maxDispatchDepth:I.maxDispatchDepth,...d===void 0?{}:{parentTaskId:d},getDispatchDeps:()=>f.dispatchDeps})),e.registerTool(ji(f.registry)),e.registerTool(Ii(f.registry,f.outputStorage)),e.registerTool(zi(f.registry,f.lifecycle,{clock:f.clock})),e.registerTool(yo(u>0))}let S=!1,C=t=>{S||r.codemodeActivation.activation===`inactive`&&e.getActiveTools().includes(`codemode`)&&(S=!0,t.ui.notify(`pi-ptc-subagents: pi's codemode is active in this session, but nothing this package reads predicted it — no tool list names it and no readable mcp.json auto-enables it — so the surface defaulted to full, and your model is being offered two orchestration tools. pi activates codemode at runtime in ways no settings file records (its MCP extension is one). Run pi with codemode active (-t codemode, or add it to defaultTools) to get the subagents surface instead.`,`warning`))};e.on(`turn_start`,async(e,t)=>{p=!0,C(t)}),e.on(`agent_settled`,async()=>{p=!1;try{await v()}catch(e){m(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new Bi,await e.drain()});let w=e=>{let t=[];n.enabled&&t.push(e.ui.theme.fg(`accent`,`PTC`)),e.ui.setStatus(_a,t.length>0?t.join(` `):void 0)},T=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(ga,{enabled:!0,base:[...t]}),w(a),a.ui.notify(o,`info`)},ee=(t,r)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,i=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(r.customType,{enabled:!1}),w(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},E=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}ee(r,{announce:!0,customType:ga});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${U(n.base,c).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=no({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:$});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}T(a.base,a.loadout,r,bo(a.base,$,c))}}),e.on(`session_start`,async(n,i)=>{r=Za(y(),e.getActiveTools(),t.codemode,t.codemodeSwitch,t.codemodeActivation),x(r),p=!1;let a=await f.bindSession(i.sessionManager?.getSessionDir?.(),e=>i.ui.notify(e,`warning`));try{await b(a)}catch(e){m(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let o=xa(y());o.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${o.error}`,`warning`),s.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${s.error}. No opt-in binding was granted, so the PTC surface stays narrowed. Opt-in bindings: ${nn.join(`, `)}.`,`warning`);let l=Qa(y());l!==void 0&&i.ui.notify(`pi-ptc-subagents: `+l.path+` still has a "surfaceMode" key (`+JSON.stringify(l.value)+"), and it is no longer read: the surface is detected from what pi is, and no key pins it. To keep this package out of your sessions entirely, turn it off in pi -- run `pi config` and disable this package's extensions there (its `extensions` entry set to [] stops pi loading it at all). To silence this notice, delete the key.",`warning`);let u=r.codemode;u.present||i.ui.notify(`pi-ptc-subagents: the codemode probe reported `+u.how+`, so the surface is full. That is the safe direction, not an error.`,`info`),r.codemodeSwitch?.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.codemodeActivation?.mcpError!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeActivation.mcpError}`,`warning`);{let t=e.getAllTools().some(e=>e.name===`codemode`);!u.present&&t&&i.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+u.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Enable codemode for real (-t codemode) to get the subagents surface instead.`,`warning`),u.present&&!t&&i.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions), so the surface is `+JSON.stringify(r.surfaceMode)+(r.surfaceMode===`subagents`?` with no orchestrator: ptc_run_code and ptc_workflow are reachable only from codemode, and this session has none. Launch with codemode active (pi -t codemode), or turn this package off with pi config.`:`.`),`warning`)}if(r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)){let t=e.getActiveTools();t.includes(`ptc_run_code`)||t.includes(`ptc_workflow`)||i.ui.notify(`pi-ptc-subagents: the detected surface is subagents, but codemode is not active in this session, so there is no orchestration tool. Add codemode to your pi tool list (the --tools flag or the default tools setting), or turn this package off with pi config.`,`warning`)}C(i);let d=E(i),{base:h,restoreFirst:g}=ao(d,e.getActiveTools());g&&e.setActiveTools([...h]);let _=no({mode:i.mode,defaultMode:o.defaultMode,active:h,manual:!1,hide:$}),v=d?.enabled??_.enter;if(_.enter&&v){T(h,_.loadout,i,bo(h,$,c));return}w(i),!_.enter&&_.reason!==`not-tui`&&d===void 0&&_.reason===`restricted-session`&&i.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{p=!1;try{await f.shutdown(`session_ended_while_running`)}catch(e){m(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let te=!1,D=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){te&&=(delete e.sections.skills,!1);return}let r=fo(e.skills);r.length!==0&&(e.sections.skills=r,te=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(D(a,uo(e.getActiveTools())),n.enabled){if(io(n,e.getActiveTools())){ee(r,{announce:!1,customType:ga}),D(a,uo(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:oo(U(n.base,c),$),display:!1}}}})}export{L as BUILTIN_BINDING_NAMES,on as DEFAULT_BINDING_NAMES,I as DEFAULT_CONFIG,ya as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,jn as MAX_LINE_CHARS,ha as MODE_REQUIRED_TOOL_NAMES,nn as OPT_IN_BINDING_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,va as PTC_MODE_CONFIG_FILE,ga as PTC_MODE_ENTRY_TYPE,_a as PTC_MODE_STATUS_KEY,ma as PTC_MODE_TOOL_NAMES,lo as PTC_SKILL_LOAD_INSTRUCTION,so as SKILL_READING_TOOL_NAMES,Bi as TurnPools,Le as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,mn as WorkerPool,ro as bindingSource,oo as buildModeInstruction,fo as buildPtcSkillsSection,dn as createBuiltinBindings,Re as createWorkerEnv,no as decideModeEntry,xo as default,io as detectExternalLoadoutChange,Za as detectSurfaceMode,Be as effectiveTimeoutMs,ba as initialModeState,rn as isOptInBindingName,to as modeLoadout,Ya as probeCodemodePresence,Ma as readCodemodeSwitch,xa as readDefaultModeConfig,Qa as readLegacySurfaceKey,Sa as readOptInBindingsConfig,Hn as renderModelValue,ao as resolveBaseOnStart,Na as resolveCodemodeActivation,ja as resolveCodemodeSwitch,ze as resolveConfig,an as resolveOptInBindingNames,Cn as runPtcProgram,eo as sameToolSet,H as sanitizeText,uo as skillsSectionDropped,Nn as stripAnsi};
|
|
60
60
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ptc-subagents",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Programmable tool calling (PTC) and subagent fan-out for pi — the model writes JS/TS programs that call pi's tools, or fans out to a fresh pi subprocess per subagent task",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|