pi-ptc-subagents 4.0.0 → 5.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 +75 -0
- package/README.md +29 -2
- package/dist/index.d.ts +71 -2
- package/dist/index.js +52 -52
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,81 @@ 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
|
+
## [5.0.0] - 2026-10-19
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **A dispatch reports the model its child actually ran.** The model used to be resolved inside the
|
|
13
|
+
child and never came back: neither `pi.dispatch`'s `DispatchResult` nor a background
|
|
14
|
+
`TaskRecord` said which provider or model served the call, so a wrong-model delegation could
|
|
15
|
+
only be inferred from a failure after the fact. Both now carry an optional observed-model pair —
|
|
16
|
+
observed by the host from the child's own assistant turns (last turn wins), not taken from the
|
|
17
|
+
request — and the model-facing surfaces state the same fact as a `model: provider/id` line on
|
|
18
|
+
`ptc_subagent` and `ptc_task_output` and as a `model=` fact in a refusal. A transcript that
|
|
19
|
+
carries only a model id reports the id alone; the absence of both means no observed assistant turn
|
|
20
|
+
named the pair — no turn, a supported pi that does not report it, or an old record — not "the
|
|
21
|
+
model is unknown". A background record gains the pair at the same terminal close that writes
|
|
22
|
+
`usage`, so a failed or canceled close that named a model still states it. The pair is named
|
|
23
|
+
`observedProvider` / `observedModel` (ADR-0045): the result's `model` input is the requested
|
|
24
|
+
model, and two different facts no longer share a name. Records written before the rename are
|
|
25
|
+
still read (the field rename itself is breaking for program-visible result shapes — see the
|
|
26
|
+
rename entry under Changed). The rendered value is stripped of ANSI escape sequences and
|
|
27
|
+
control characters and head-capped at 200 characters before it enters model-facing text,
|
|
28
|
+
because the pair is untrusted child wire data. See
|
|
29
|
+
ADR-0044, ADR-0016 §"The child's model", and ADR-0022 §3 as amended.
|
|
30
|
+
- **The `ptc_subagent` call row states the model a generalist dispatch will inherit.** When the
|
|
31
|
+
call names no model and no agent (a generalist child, where a definition cannot pin the tier),
|
|
32
|
+
the request row says `model=inherit` and its expanded view names the provider/id the caller's
|
|
33
|
+
session is on; a named agent gets no such claim, and a pinned `model` is stated as before. This
|
|
34
|
+
is a request fact captured at the call's first render, so a later model switch does not change
|
|
35
|
+
an already-rendered row — and it is not the observed model, which still appears only after the
|
|
36
|
+
child ran. ADR-0044.
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
|
|
40
|
+
- **BREAKING — the observed-model fields are named `observedProvider` / `observedModel`.**
|
|
41
|
+
`DispatchResult.provider` / `model` and `TaskRecord.provider` / `model` carried the observed
|
|
42
|
+
model, while the input's `model` is the requested model; the shared name made two different
|
|
43
|
+
facts look comparable. The output fields are renamed, the input keeps its name, the child wire
|
|
44
|
+
and the model-facing `model:` text are unchanged, and a record written before the rename is
|
|
45
|
+
normalized on read so its observation is not lost. No aliases: the old result keys are removed,
|
|
46
|
+
which is why this is breaking for program-visible result shapes. See ADR-0045.
|
|
47
|
+
- **BREAKING — a dispatch that names no model now runs on the caller session's current model, not
|
|
48
|
+
pi's global default.** `pi.dispatch` and `ptc_subagent` resolve the child's model first match
|
|
49
|
+
wins: the dispatch's `model` argument, then the agent definition's frontmatter `model:`, then
|
|
50
|
+
the calling session's **current** model, then pi's configured default. A session that switched
|
|
51
|
+
provider or model mid-conversation now carries that switch into its next dispatched child — the
|
|
52
|
+
background-dispatch guide previously said the opposite, and that statement is what this changes.
|
|
53
|
+
Resolution is a snapshot at spawn: a model switched after the child starts does not change it, a
|
|
54
|
+
nested dispatch inherits the child's own session model, and re-running the dispatch is how a
|
|
55
|
+
caller picks up a new model. Tiers 1–2 are unchanged, so pinning the model at the call site or in
|
|
56
|
+
the definition is the explicit opt-out; no config key and no `model: "inherit"` sentinel is
|
|
57
|
+
added. A direct library caller with no context model, an older pi, or a session started without a
|
|
58
|
+
model all fall through to pi's default exactly as before — the session read is structural, so
|
|
59
|
+
the declared 0.86.0 floor gains no new pi type dependency. See ADR-0044 for the decision and its
|
|
60
|
+
rejected alternatives.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- **A failed foreground dispatch no longer loses the child's own failure.** The child is a pi
|
|
65
|
+
subprocess: a rate limit or a model error can make it exit 0 after writing
|
|
66
|
+
`stopReason: "error"` and an `errorMessage` on its assistant turn. The foreground loop
|
|
67
|
+
discarded that text and reported the generic `dispatch produced no final text`, while the
|
|
68
|
+
background registry already recorded the child's reason (issue #70's rule). The close decision now
|
|
69
|
+
returns the child's reported error verbatim, using the background registry's rule — the child's
|
|
70
|
+
own error outranks the exit-code and truncation inference — with cancellation still first:
|
|
71
|
+
cancelled, then exit-0-with-text (fulfilled), then the child's error, then exit-0-without-text,
|
|
72
|
+
then truncation. It logs one warning on that newly diagnosed path only. `stderr` is no longer
|
|
73
|
+
described as guaranteed; `errorMessage` is the structured failure channel. This is
|
|
74
|
+
foreground/background parity: one verdict and one sentence for one failure. See ADR-0044
|
|
75
|
+
Decision 3 and ADR-0016 §Decision 3.
|
|
76
|
+
- **`ptc_subagent refused the call: undefined` is gone.** A rejected dispatch without an
|
|
77
|
+
`errorMessage` used to render the literal string `undefined`, telling the model nothing the
|
|
78
|
+
dispatcher knew. The refusal now states the cause plus bounded facts the result already carries —
|
|
79
|
+
whether a child ran or the harness declined to start, the exit code, turns, report channel, and
|
|
80
|
+
the observed model when there is one — tail-bounded to 800 characters so a provider's actionable
|
|
81
|
+
status code survives the cut. See ADR-0044 Decision 3.
|
|
82
|
+
|
|
8
83
|
## [4.0.0] - 2026-10-19
|
|
9
84
|
|
|
10
85
|
### Added
|
package/README.md
CHANGED
|
@@ -79,11 +79,12 @@ const result = await tools["pi.dispatch"]({
|
|
|
79
79
|
// result.status: "fulfilled" | "rejected" (the binding never throws)
|
|
80
80
|
// result.text: final assistant text
|
|
81
81
|
// result.usage: { input, output, cacheRead, cacheWrite, cost, turns }
|
|
82
|
+
// result.observedProvider?, result.observedModel?: the provider/model the child actually ran
|
|
82
83
|
// result.exitCode, result.durationMs, result.stderr?, result.errorMessage?
|
|
83
84
|
```
|
|
84
85
|
|
|
85
86
|
**Fan out in parallel** with the rest of PTC's tools — dispatch is a binding, not a
|
|
86
|
-
model-
|
|
87
|
+
model-facing lifecycle tool, so the dispatcher handles concurrency the same way it does for
|
|
87
88
|
any other tool call:
|
|
88
89
|
|
|
89
90
|
```ts
|
|
@@ -116,6 +117,32 @@ at 20 findings with the withheld count stated in-band.
|
|
|
116
117
|
- `signal` — when the parent run is cancelled, every in-flight child gets `SIGTERM` then
|
|
117
118
|
`SIGKILL` after a 5-second grace window.
|
|
118
119
|
|
|
120
|
+
### The child's model
|
|
121
|
+
|
|
122
|
+
A dispatched child is a fresh `pi` subprocess and resolves its own model, first match wins:
|
|
123
|
+
|
|
124
|
+
1. the dispatch's `model` argument;
|
|
125
|
+
2. the named agent definition's frontmatter `model:`;
|
|
126
|
+
3. **the caller session's current model** — read from the pi session that spawns the child;
|
|
127
|
+
4. pi's configured default.
|
|
128
|
+
|
|
129
|
+
Tier 3 is the behaviour change of [ADR-0044](./docs/adr/0044-a-dispatch-inherits-the-session-model.md):
|
|
130
|
+
a session that switched provider or model mid-conversation carries that switch into the children it
|
|
131
|
+
dispatches, instead of silently running them on pi's global default. Resolution happens once, at
|
|
132
|
+
spawn — a model switched afterwards does not change a child that is already running, and a nested
|
|
133
|
+
dispatch inherits the child's own session model. Pin the model at the call site or in the agent
|
|
134
|
+
definition to opt out; there is no config key for it, and a direct library caller (or a pi that
|
|
135
|
+
exposes no session model) falls back to pi's default exactly as before.
|
|
136
|
+
|
|
137
|
+
The result says which model the child actually ran: `observedProvider` / `observedModel` on a foreground
|
|
138
|
+
`DispatchResult`, the same optional pair on a background task record (which `ptc_task_output`
|
|
139
|
+
renders as a line), and a `model: provider/id` line in `ptc_subagent`'s text. Absence means no
|
|
140
|
+
observed assistant turn named the pair — no turn, a supported pi that does not report it, or an
|
|
141
|
+
old record — never "unknown model". When the child reported its own failure, a
|
|
142
|
+
rejected dispatch now states that error verbatim as `errorMessage` instead of the generic
|
|
143
|
+
`dispatch produced no final text`, so the foreground failure path matches the background one. Full
|
|
144
|
+
guide: [`docs/usage/bgdispatch.md`](./docs/usage/bgdispatch.md#which-model-the-child-runs).
|
|
145
|
+
|
|
119
146
|
### Background dispatch
|
|
120
147
|
|
|
121
148
|
Foreground `pi.dispatch` blocks the program until the child exits. Pass `background: true` to
|
|
@@ -205,7 +232,7 @@ Which model-facing tools this package registers is **detected, not configured**
|
|
|
205
232
|
setting for it ([ADR-0034](./docs/adr/0034-surface-is-detected-not-set.md)). The short version:
|
|
206
233
|
a pi whose `codemode` is loaded _and_ callable by the model gets the `subagents` surface
|
|
207
234
|
(`ptc_subagent` on top; the program pair underneath at `codemode` reach); every other pi gets
|
|
208
|
-
`full` (`ptc_run_code` / `ptc_workflow` model-
|
|
235
|
+
`full` (`ptc_run_code` / `ptc_workflow` model-facing). To use the `subagents` surface, put
|
|
209
236
|
`codemode` in your tool list (`pi --tools read,bash,edit,write,codemode`, or `"defaultTools":
|
|
210
237
|
["read", "bash", "edit", "write", "+codemode"]`). To keep this package out of your sessions
|
|
211
238
|
entirely, run `pi config` and disable its extensions there.
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,14 @@ interface ParsedAgentEvent {
|
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
39
|
model?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Provider that served this assistant turn. pi >= 1.0.0 puts the resolved provider on the
|
|
42
|
+
* assistant message, so a host can report which model actually ran the child (dispatches
|
|
43
|
+
* otherwise run on pi's configured default, which the caller never sees). Optional and
|
|
44
|
+
* structurally read -- the 0.86.0 floor's type surface may not declare it, and an absent
|
|
45
|
+
* field must mean "not observed" rather than a parse failure.
|
|
46
|
+
*/
|
|
47
|
+
provider?: string;
|
|
40
48
|
stopReason?: string;
|
|
41
49
|
errorMessage?: string;
|
|
42
50
|
};
|
|
@@ -218,11 +226,13 @@ interface TaskSpawnSource {
|
|
|
218
226
|
* Session-level row tracking the lifecycle of one background child. 20 pre-ownership fields since
|
|
219
227
|
* the 2026-10-16 #199 amendment (19 ADR-0022 §3 originals — its "21 fields" heading is an
|
|
220
228
|
* authoring miscount — plus `usage`), two optional ADR-0023 owner-identity fields, two ADR-0032
|
|
221
|
-
* report fields
|
|
229
|
+
* report fields, ADR-0041's `readOnlyTier`, ADR-0043's `whySuppressed` and the host-observed
|
|
230
|
+
* `observedProvider` / `observedModel` pair (ADR-0045); 28 today, persisted as-is. Optional fields are
|
|
222
231
|
* absent on records still `running` (e.g. `finishedAt` / `exitCode` / `outputRef` are written at
|
|
223
232
|
* transition time, not at spawn) and `ownerPid` / `ownerBootMs` are absent on pre-upgrade
|
|
224
233
|
* legacy records. The `report` / `reportChannel` pair is absent unless the record reached
|
|
225
|
-
* `succeeded` (ADR-0032); `usage`
|
|
234
|
+
* `succeeded` (ADR-0032); `usage` and the observed-model pair are written on every terminal
|
|
235
|
+
* close once a child started.
|
|
226
236
|
*/
|
|
227
237
|
interface TaskRecord {
|
|
228
238
|
id: ULID;
|
|
@@ -315,6 +325,27 @@ interface TaskRecord {
|
|
|
315
325
|
* Absent on records written before this field existed, and on children that never started.
|
|
316
326
|
*/
|
|
317
327
|
usage?: DispatchUsage;
|
|
328
|
+
/**
|
|
329
|
+
* The provider that actually served this child, observed by the pump off the child's assistant
|
|
330
|
+
* `message_end` events (last turn wins). Persisted at the terminal close, on every outcome the
|
|
331
|
+
* close can produce -- a failed or canceled child still ran a model, and that is the fact the
|
|
332
|
+
* model-observability fix exists to state. Named `observedProvider` because the input's `model`
|
|
333
|
+
* is the requested model, not this one (ADR-0045).
|
|
334
|
+
*
|
|
335
|
+
* ABSENT means no assistant turn NAMED a provider -- not "the child ran on an unknown
|
|
336
|
+
* provider". It covers a child with no observed assistant turn, a supported older pi that
|
|
337
|
+
* does not report the pair on assistant messages (the wire field arrives with pi 1.0.0; the
|
|
338
|
+
* declared floor is 0.86.0), and a record written before these fields existed. A background
|
|
339
|
+
* dispatch that names no model runs on pi's configured default; `ptc_task_output` projects
|
|
340
|
+
* this pair back so a caller can finally see which default that was.
|
|
341
|
+
*/
|
|
342
|
+
observedProvider?: string;
|
|
343
|
+
/**
|
|
344
|
+
* The model id the child actually ran, observed like {@link observedProvider}. Present even
|
|
345
|
+
* when `observedProvider` is absent: a transcript may carry a model without a provider, and a
|
|
346
|
+
* half-observation is still an observation.
|
|
347
|
+
*/
|
|
348
|
+
observedModel?: string;
|
|
318
349
|
}
|
|
319
350
|
/**
|
|
320
351
|
* Per-subscriber cursor for one TaskRecord (ADR-0022 §5). Cursor is per-subscriber (not per-task)
|
|
@@ -425,6 +456,9 @@ type TaskCommand = {
|
|
|
425
456
|
report?: ChildReport;
|
|
426
457
|
reportChannel: ChildReportChannel;
|
|
427
458
|
usage?: DispatchUsage;
|
|
459
|
+
/** ADR-0045: the observed model names; a legacy on-disk record is normalized on read. */
|
|
460
|
+
observedProvider?: string;
|
|
461
|
+
observedModel?: string;
|
|
428
462
|
};
|
|
429
463
|
/** Outcome of one successful command: the persisted record, emitted events, and cursor. */
|
|
430
464
|
interface TransitionResult {
|
|
@@ -492,6 +526,26 @@ interface OutputStorage {
|
|
|
492
526
|
outputRef(taskId: ULID): string;
|
|
493
527
|
}
|
|
494
528
|
//#endregion
|
|
529
|
+
//#region src/runtime/session-model.d.ts
|
|
530
|
+
/**
|
|
531
|
+
* The caller session's current model, as a dispatch can learn it.
|
|
532
|
+
*
|
|
533
|
+
* ADR-0044: a dispatch that names no model at the call site and whose agent markdown names
|
|
534
|
+
* none inherits the model the caller's session is currently running. That fact lives on pi's
|
|
535
|
+
* tool-execution context (`ctx.model`) rather than in this package, so this module is the one
|
|
536
|
+
* structural reader of it -- kept separate so 0.86.0's type surface (which may not declare the
|
|
537
|
+
* field) cannot turn the read into a compile error on the declared floor.
|
|
538
|
+
*
|
|
539
|
+
* The value is a SNAPSHOT taken when the dispatch starts: a model switch after the spawn does
|
|
540
|
+
* not retro-change a child that is already running, and a nested dispatch inherits the child's
|
|
541
|
+
* own context model (which is what the child runs with, not the grandparent's).
|
|
542
|
+
*/
|
|
543
|
+
/** One provider + model id pair, e.g. `deepseek` + `deepseek-flash`. */
|
|
544
|
+
interface SessionModel {
|
|
545
|
+
readonly provider: string;
|
|
546
|
+
readonly id: string;
|
|
547
|
+
}
|
|
548
|
+
//#endregion
|
|
495
549
|
//#region src/runtime/dispatch.d.ts
|
|
496
550
|
/**
|
|
497
551
|
* Per-run in-flight `pi.dispatch` counter (ADR-0016 §2 + ADR-0022 §9). The dispatcher's
|
|
@@ -742,6 +796,13 @@ interface BindingContext {
|
|
|
742
796
|
* output storage) so the binding's `dispatch()` call shares them.
|
|
743
797
|
*/
|
|
744
798
|
dispatchDeps?: DispatchDeps;
|
|
799
|
+
/**
|
|
800
|
+
* ADR-0044: the caller session's current model, read by the host off pi's tool-execution
|
|
801
|
+
* context. The `pi.dispatch` binding forwards it into the `DispatchContext` so a dispatch
|
|
802
|
+
* that names no model explicitly inherits the session's. Absent for direct library callers
|
|
803
|
+
* and for a pi too old to pass `ctx.model`: both keep the pre-ADR-0044 behaviour.
|
|
804
|
+
*/
|
|
805
|
+
sessionModel?: SessionModel;
|
|
745
806
|
}
|
|
746
807
|
interface Binding {
|
|
747
808
|
readonly name: string;
|
|
@@ -1666,6 +1727,14 @@ interface RunPtcProgramOptions {
|
|
|
1666
1727
|
* against this run's `dispatchConcurrency` for their whole lifetime.
|
|
1667
1728
|
*/
|
|
1668
1729
|
dispatchDeps?: DispatchDeps;
|
|
1730
|
+
/**
|
|
1731
|
+
* ADR-0044: the caller session's current model, read by the entrypoint off pi's
|
|
1732
|
+
* tool-execution context. Threaded to every binding call's context so `pi.dispatch` can
|
|
1733
|
+
* inherit it when the call site and the agent markdown both name no model. Absent means
|
|
1734
|
+
* no inheritance -- exactly the pre-ADR-0044 behaviour, which is what every direct library
|
|
1735
|
+
* caller and every pi too old to pass `ctx.model` gets.
|
|
1736
|
+
*/
|
|
1737
|
+
sessionModel?: SessionModel;
|
|
1669
1738
|
/**
|
|
1670
1739
|
* Optional worker pool (ADR-0017). Absent = spawn a fresh worker and terminate it
|
|
1671
1740
|
* at run end (the original cold-start path). Present = the dispatcher acquires a
|
package/dist/index.js
CHANGED
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,realpathSync as E,statSync as D,writeFileSync as ee}from"node:fs";import*as
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./protocol-CfOgxz3u.js";import{DEFAULT_MAX_BYTES as s,DEFAULT_MAX_LINES as c,createBashTool as l,createEditTool as u,createFindTool as d,createGrepTool as f,createLsTool as p,createReadTool as m,createWriteTool as h,defineTool as g,formatSize as _,formatSkillsForPrompt as v,getAgentDir as y,truncateTail as b}from"@earendil-works/pi-coding-agent";import{Type as x}from"typebox";import{validateToolArguments as S}from"@earendil-works/pi-ai";import*as C from"node:fs";import{existsSync as w,readFileSync as T,realpathSync as E,statSync as D,writeFileSync as ee}from"node:fs";import*as te from"node:os";import{homedir as O,tmpdir as k}from"node:os";import*as A from"node:path";import{basename as ne,dirname as j,join as M,relative as N,resolve as P,sep as re}from"node:path";import{spawn as ie}from"node:child_process";import{randomBytes as ae,randomUUID as oe}from"node:crypto";import{ok as F}from"node:assert/strict";import{MessageChannel as se,Worker as ce}from"node:worker_threads";import le from"node:diagnostics_channel";import{fileURLToPath as ue,pathToFileURL as de}from"node:url";import{truncateToWidth as I,visibleWidth as L}from"@earendil-works/pi-tui";import{appendFile as fe,mkdir as pe,readFile as me,readdir as he,rename as ge,unlink as _e,writeFile as ve}from"node:fs/promises";import{minimatch as ye}from"minimatch";function R(e){return g(e)}const be=`0123456789ABCDEFGHJKMNPQRSTVWXYZ`;function xe(e){let t=``,n=Math.max(0,Math.floor(e));for(let e=0;e<10;e++)t=(be[n%32]??`0`)+t,n=Math.floor(n/32);return t}function Se(e){let t=``,n=0,r=0;for(let i=0;i<e.length&&t.length<16;i++)for(n=n<<8|(e[i]??0),r+=8;r>=5&&t.length<16;)r-=5,t+=be[n>>>r&31];return t.padEnd(16,`0`)}function Ce(e){let t=new Uint8Array(e);for(let e=t.length-1;e>=0;e--){if((t[e]??0)<255)return t[e]=(t[e]??0)+1,t;t[e]=0}return t}function we(e){let t=e.randomBytes??(e=>new Uint8Array(ae(e))),n=-1,r=/* @__PURE__ */ new Uint8Array(10);return{next(){let i=Math.max(0,Math.floor(e.now())),a=i>n?i:n,o=a===n?Ce(r):t(10);return n=a,r=o,xe(a)+Se(o)}}}const Te=we({now:()=>Date.now()});function Ee(){return Te.next()}function De(e){let t=e.trim();if(t.length===0)return null;try{return JSON.parse(t)}catch{return null}}function Oe(e,t){if(e.pid===void 0)return!1;try{return e.kill(t),!0}catch{return!1}}function ke(e,t){if(e.eventWaiters.length>0){let n=e.eventWaiters.shift();n&&n(t);return}e.events.push(t)}function Ae(e,t){if(e.exited)return;e.exited=!0,e.exitValue=t;for(let n of e.exitWaiters)n(t);e.exitWaiters=[];let n=e.eventWaiters;e.eventWaiters=[];for(let e of n)e(null);for(let t of e.stderrWaiters)t(e.stderr);e.stderrWaiters=[]}function je(e,t){let n=t.sessionDir===void 0?[...e]:e.filter(e=>e!==`--no-session`);return t.sessionDir!==void 0&&(n.push(`--session-dir`,t.sessionDir),t.sessionId!==void 0&&n.push(`--session-id`,t.sessionId),t.sessionName!==void 0&&n.push(`--name`,t.sessionName)),n}const Me={warn:e=>{console.warn(`[pi-ptc.lifecycle] `+e)}};function Ne(e){return e.length<=200?e:e.slice(0,200)+`…`}var Pe=class{#e;constructor(e={}){this.#e=e.logger??Me}spawn(e,t){if(e.length===0)throw TypeError(`RealChildProcessLifecycle.spawn: argv must include the command`);let n=je(e,t),r=n[0],i=n.slice(1),a=ie(r,i,{cwd:t.cwd,shell:!1,stdio:[`ignore`,`pipe`,`pipe`],env:t.env}),o={proc:a,events:[],eventWaiters:[],exited:!1,exitValue:null,stderrWaiters:[],exitWaiters:[],stderr:``,lineBuffer:``},s={id:Ee(),opaque:o},c=a.stdout;c&&c.on(`data`,e=>{o.lineBuffer+=e.toString(`utf-8`);let t=o.lineBuffer.indexOf(`
|
|
2
2
|
`);for(;t>=0;){let e=o.lineBuffer.slice(0,t);o.lineBuffer=o.lineBuffer.slice(t+1);let n=De(e);n?ke(o,n):e.trim().length>0&&this.#t(s,e),t=o.lineBuffer.indexOf(`
|
|
3
3
|
`)}});let l=a.stderr;return l&&l.on(`data`,e=>{o.stderr+=e.toString(`utf-8`)}),a.on(`close`,(e,t)=>{let n=o.lineBuffer.trim();if(n.length>0){let e=De(n);e?ke(o,e):this.#t(s,n),o.lineBuffer=``}Ae(o,{code:e,signal:t})}),a.on(`error`,e=>{o.stderr+=`[spawn-error] `+e.message+`
|
|
4
|
-
`,o.exited||Ae(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Oe(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Ne(t))}};const Fe=`ptc_child_report`,z=Object.freeze({timeoutMs:12e4,maxTimeoutMs:6e5,maxOutputBytes:67108864,maxMessageBytes:134217728,maxPendingCalls:128,maxParallelSubCalls:10,dispatchConcurrency:8,maxDispatchDepth:3,maxItemsPerCall:4096,graceMs:3e3,maxOldGenerationSizeMb:512,maxYoungGenerationSizeMb:64,poolSize:4,poolAcquireTimeoutMs:3e4,drainGraceMs:5e3}),Ie=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Le(e=process.env){let t={};for(let n of Ie){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function Re(e={}){let t={...z};for(let n of Object.keys(z)){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0)throw TypeError(`invalid PTC config override for ${n}: ${String(r)}`);t[n]=r}}return t}function ze(e,t=z){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Be={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ve=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),He=/* @__PURE__ */ new Set([`running`,`stopping`]);function Ue(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.stderrDiagnostic!==void 0)return t.stderrDiagnostic;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function We(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Ge(e){return typeof e==`string`&&e.length>0}const Ke=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function qe(e){return typeof e==`string`&&Ke.has(e)}function Je(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Ye(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Xe(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ze=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??Ye,this.#a=we({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Ge(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())He.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Ge(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!We(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!qe(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=(e.outputBytes??0)>0,i=n.status===`stopping`?`canceled`:e.exitCode===0&&r?`succeeded`:`failed`;return this.#v(n,i),this.#m(n,i,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview,errorMessage:Ue(n,e,i,r),usage:e.usage,...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!He.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};Ve.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.usage!==void 0&&(a.usage=r.usage),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=Be[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Ge(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Xe(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function Qe(e,t){return new Ze(e,t)}function $e(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function et(e){for(let t=1;t<e.length;t++)if($e(e[t-1],e[t])>0)return!1;return!0}var tt=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){F(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){F(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=et(t)?[...t]:[...t].sort($e),i=n.length===0?void 0:n[n.length-1]?.eventId,a=r[0]?.eventId;if(i===void 0||a!==void 0&&i<=a){for(let e of r)n.push(structuredClone(e));this.#r.set(e,n);return}let o=[...n,...r.map(e=>structuredClone(e))];o.sort($e),this.#r.set(e,o)}async*loadEvents(e,t){if(!this.#a(e))throw Error(`loadEvents: unknown subscriptionId ${e}`);let n=this.#r.get(e)??[],r=0;if(t!==void 0){let e=0,i=n.length;for(;e<i;){let r=e+i>>>1;(n[r]?.eventId??``)<=t?e=r+1:i=r}r=e}for(let e=r;e<n.length;e++)yield structuredClone(n[e])}};const nt=new Pe;var rt=class{limit;#e;#t=/* @__PURE__ */ new Set;constructor(e){if(!Number.isInteger(e)||e<0)throw TypeError(`DispatchSlotCounter: limit must be a non-negative integer, got ${String(e)}`);this.limit=e,this.#e=0}get active(){return this.#e}tryAcquire(e){return e!==void 0&&this.#t.has(e)||this.#e>=this.limit?!1:(e!==void 0&&this.#t.add(e),this.#e+=1,!0)}release(e){if(e!==void 0){if(!this.#t.delete(e))return;--this.#e;return}this.#e>this.#t.size&&--this.#e}};const it=new rt(z.dispatchConcurrency);let at;function ot(e,t){return e.taskRegistry===void 0?(at??=new Ze(new tt,{clock:t}),at):e.taskRegistry}const st={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},ct=[`read`,`grep`,`find`,`ls`];function B(e){return e===`strict`||e===`lenient`?e:void 0}function lt(e){return e==null||e===`strict`||e===`lenient`}function ut(e){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`invalid readOnly value: `+(typeof e==`object`&&e?JSON.stringify(e):String(e))+` (readOnly accepts "strict" or "lenient"; null and undefined ask for no tier)`}}function dt(e,t){return t===void 0?e:{...e,readOnlyTier:t}}function ft(e,t){let n=typeof e==`string`?e.trim():``;return n.length===0?{why:void 0,suppressed:!1}:t?{why:n,suppressed:!1}:{why:void 0,suppressed:!0}}function pt(e,t){return t?{...e,whySuppressed:!0}:e}const mt=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function ht(e,t,n,r={}){let i=r.reportContract!==!1,a=B(r.readOnly),o=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],...a===`lenient`?[`You were dispatched read-only: do not create, modify or delete files, and do not run commands that would. Your tools are otherwise all still available to you — this is an instruction, not a restriction, so a task that genuinely needs to write is worth saying so rather than failing quietly.`]:[],`</pi-ptc-context>`].join(`
|
|
5
|
-
`),s=
|
|
4
|
+
`,o.exited||Ae(o,{code:null,signal:null})}),s}kill(e,t){let n=e.opaque;Oe(n.proc,t)}events(e){let t=e.opaque;return{async*[Symbol.asyncIterator](){for(;;){if(t.events.length>0){let e=t.events.shift();e!==void 0&&(yield e);continue}if(t.exited)return;let e=await new Promise(e=>{t.eventWaiters.push(e)});if(e===null)return;yield e}}}}exit(e){let t=e.opaque;return t.exited&&t.exitValue?Promise.resolve(t.exitValue):new Promise(e=>{t.exitWaiters.push(e)})}stderr(e){let t=e.opaque;return t.exited?Promise.resolve(t.stderr):new Promise(e=>{t.stderrWaiters.push(e)})}#t(e,t){this.#e.warn(`child ${e.id}: dropped a non-JSON stdout line (${t.length} chars): `+Ne(t))}};const Fe=`ptc_child_report`,z=Object.freeze({timeoutMs:12e4,maxTimeoutMs:6e5,maxOutputBytes:67108864,maxMessageBytes:134217728,maxPendingCalls:128,maxParallelSubCalls:10,dispatchConcurrency:8,maxDispatchDepth:3,maxItemsPerCall:4096,graceMs:3e3,maxOldGenerationSizeMb:512,maxYoungGenerationSizeMb:64,poolSize:4,poolAcquireTimeoutMs:3e4,drainGraceMs:5e3}),Ie=Object.freeze([`PATH`,`PATHEXT`,`SYSTEMROOT`,`WINDIR`,`TEMP`,`TMP`]);function Le(e=process.env){let t={};for(let n of Ie){let r=e[n];typeof r==`string`&&r.length>0&&(t[n]=r)}return t}function Re(e={}){let t={...z};for(let n of Object.keys(z)){let r=e[n];if(r!==void 0){if(typeof r!=`number`||!Number.isFinite(r)||r<=0)throw TypeError(`invalid PTC config override for ${n}: ${String(r)}`);t[n]=r}}return t}function ze(e,t=z){return e===void 0||!Number.isFinite(e)||e<=0?t.timeoutMs:Math.min(e,t.maxTimeoutMs)}const Be={running:[`stopping`,`succeeded`,`failed`,`canceled`,`lost`],stopping:[`succeeded`,`failed`,`canceled`],succeeded:[],failed:[],canceled:[],lost:[]},Ve=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),He=/* @__PURE__ */ new Set([`running`,`stopping`]);function Ue(e,t,n,r){if(n!==`canceled`&&n!==`succeeded`){if(t.childError!==void 0)return t.childError;if(t.stderrDiagnostic!==void 0)return t.stderrDiagnostic;if(t.exitCode===0&&!r)return`dispatch produced no final text`}}function We(e){return e===`running`||e===`stopping`||e===`succeeded`||e===`failed`||e===`canceled`||e===`lost`}function Ge(e){return typeof e==`string`&&e.length>0}const Ke=/* @__PURE__ */ new Set([`session_ended_while_running`,`user_killed_via_esc`,`lost_on_session_restart`]);function qe(e){return typeof e==`string`&&Ke.has(e)}function Je(e,t){return e.ownerPid===t.pid&&e.ownerBootMs===t.bootMs}function Ye(e){try{return process.kill(e,0),!0}catch(e){let t=e?.code;if(t===`ESRCH`)return!1;if(t===`EPERM`)return!0;throw e}}function Xe(e,t){let n=`task:${e}`;return t===`running`||t===`stopping`?`${n}:${t}`:`${n}:->${t}`}var Ze=class{#e;#t;#n;#r;#i;#a;#o=/* @__PURE__ */ new Set;#s=Promise.resolve();constructor(e,t){this.#e=e,this.#t=t.clock,this.#n=t.logger,this.#r=t.owner,this.#i=t.isPidAlive??Ye,this.#a=we({now:()=>this.#t()})}async transition(e,t){let n=await this.#h(()=>this.#c(e,t)),r=n.events[n.events.length-1];return r!==void 0&&this.#g(n.record,r,t.logger),n}onTransition(e){this.#o.add(e);let t=!0;return()=>{t&&(t=!1,this.#o.delete(e))}}async#c(e,t){switch(e.kind){case`spawn`:return this.#l(e,t);case`transition`:return this.#u(e,t);case`stop`:return this.#d(e,t);case`reconcile-lost`:return this.#p(e,t);case`resolve-exit`:return this.#f(e,t)}throw Error(`transition: unknown command kind ${String(e.kind)}`)}async get(e){return Ge(e)?await this.#e.loadTask(e):null}async query(e){let t=e.limit??100;if(!Number.isInteger(t)||t<0)throw Error(`query: limit must be a non-negative integer, got ${String(e.limit)}`);let n=e.orderBy??`createdAt-desc`,r=e.label===void 0?void 0:{label:e.label},i=[];for await(let t of this.#e.listTasks(r))(e.status===void 0||e.status.includes(t.status))&&i.push(t);return i.sort((e,t)=>n===`createdAt-asc`?e.createdAt-t.createdAt:t.createdAt-e.createdAt),i.slice(0,t)}async reconcileLostTasks(){let e=[];for await(let t of this.#e.listTasks())He.has(t.status)&&this.#_(t)&&e.push(t);let t=[];for(let n of e){let e=await this.transition({kind:`reconcile-lost`,taskId:n.id,reason:`lost_on_session_restart`},{clock:this.#t,callerId:this.#S(n),logger:this.#n});t.push(e.record)}return this.#n?.info(`reconcileLostTasks: marked ${t.length} task(s) lost`),t}async#l(e,t){let n=Math.max(0,Math.floor(t.clock())),r=e.handle;if(r==null)throw Error(`spawn: handle is required`);if(r.status!==`running`)throw Error(`spawn: handle.status must be "running", got ${String(r.status)}`);let i=Ge(r.taskId),a=i?r.taskId:this.#a.next();if(await this.#e.loadTask(a)!==null)throw Error(`spawn: task ${a} already exists (duplicate spawn)`);let o={...e.record,id:a,label:e.record.label.length>0?e.record.label:r.label,status:`running`,createdAt:n,startedAt:n,finishedAt:void 0,durationMs:void 0,transitionAt:n,parentTaskId:e.parentTaskId??e.record.parentTaskId};this.#r!==void 0&&(o.ownerPid=this.#r.pid,o.ownerBootMs=this.#r.bootMs),i||(r.taskId=a);let s=t.callerId,c=this.#x(a,s,`running`,n,o);return await this.#e.saveSubscription({subscriberId:s,taskId:a,cursor:c.eventId,status:`active`,createdAt:n}),await this.#e.appendEvents(s,[c]),await this.#e.saveTask(o),(t.logger??this.#n)?.info(`spawn: task ${a} (${o.label}) running for subscriber ${s}`),{record:o,events:[c],cursor:c.eventId}}async#u(e,t){if(!We(e.to))throw Error(`transition: unknown target state ${String(e.to)}`);let n=await this.#y(e.taskId);if(this.#v(n,e.to),e.to===`lost`&&!qe(e.reason))throw Error(`transition: to "lost" requires a LostReason (session_ended_while_running | user_killed_via_esc | lost_on_session_restart)`+(e.reason===void 0?``:`, got ${String(e.reason)}`));return this.#m(n,e.to,t,{reason:e.reason,stopReason:e.stopReason,errorMessage:e.errorMessage,exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview})}async#d(e,t){let n=await this.#y(e.taskId);return n.status===`stopping`?{record:n,events:[],cursor:(await this.#e.loadSubscription(t.callerId,n.id))?.cursor??n.id,fromStatus:n.status}:(this.#v(n,`stopping`),this.#m(n,`stopping`,t,{stopReason:e.reason}))}async#f(e,t){let n=await this.#y(e.taskId);if(n.status!==`running`&&n.status!==`stopping`)throw Error(`resolve-exit: task ${n.id} is terminal (${n.status}); the single terminal writer refuses to overwrite it`);let r=(e.outputBytes??0)>0,i=n.status===`stopping`?`canceled`:e.exitCode===0&&r?`succeeded`:`failed`;return this.#v(n,i),this.#m(n,i,t,{exitCode:e.exitCode,outputRef:e.outputRef,outputBytes:e.outputBytes,outputPreview:e.outputPreview,errorMessage:Ue(n,e,i,r),usage:e.usage,observedProvider:e.observedProvider,observedModel:e.observedModel,...i===`succeeded`?{report:e.report,reportChannel:e.reportChannel}:{}})}async#p(e,t){let n=await this.#y(e.taskId);if(!He.has(n.status))throw Error(`reconcile-lost: task ${n.id} is terminal (${n.status}); only running/stopping tasks can be reconciled`);return this.#m(n,`lost`,t,{errorMessage:e.reason})}async#m(e,t,n,r){let i=Math.max(0,Math.floor(n.clock())),a={...e,status:t,transitionAt:i};Ve.has(t)&&(a.finishedAt=i,a.durationMs=i-e.startedAt),r.stopReason!==void 0&&(a.stopReason=r.stopReason),r.errorMessage!==void 0&&(a.errorMessage=r.errorMessage),r.exitCode!==void 0&&(a.exitCode=r.exitCode),r.outputRef!==void 0&&(a.outputRef=r.outputRef),r.outputBytes!==void 0&&(a.outputBytes=r.outputBytes),r.outputPreview!==void 0&&(a.outputPreview=r.outputPreview),r.report!==void 0&&(a.report=r.report),r.reportChannel!==void 0&&(a.reportChannel=r.reportChannel),r.usage!==void 0&&(a.usage=r.usage),r.observedProvider!==void 0&&(a.observedProvider=r.observedProvider),r.observedModel!==void 0&&(a.observedModel=r.observedModel),r.reason!==void 0&&((t===`stopping`||t===`canceled`)&&a.stopReason===void 0&&(a.stopReason=r.reason),(t===`failed`||t===`lost`)&&a.errorMessage===void 0&&(a.errorMessage=r.reason));let o=n.callerId,s=this.#x(e.id,o,t,i,a);return await this.#b(o,e.id,i,s.eventId),await this.#e.appendEvents(o,[s]),await this.#e.saveTask(a),(n.logger??this.#n)?.info(`transition: task ${e.id} ${e.status} -> ${t} (subscriber ${o})`),{record:a,events:[s],cursor:s.eventId,fromStatus:e.status}}async#h(e){let t=this.#s.then(e,e);return this.#s=t.then(()=>void 0,()=>void 0),await t}#g(e,t,n){for(let r of this.#o)try{r(e,t)}catch(t){let r=t instanceof Error?t.message:String(t),i=`transition observer threw for task ${e.id}: ${r}`,a=n??this.#n;a===void 0?console.warn(`[task-registry] `+i):a.warn(i)}}#_(e){return e.ownerPid===void 0||!this.#i(e.ownerPid)}#v(e,t){let n=Be[e.status];if(!n.includes(t)){let r=n.length===0?`<terminal>`:n.join(`, `);throw Error(`illegal transition for task ${e.id}: ${e.status} -> ${t} (allowed from ${e.status}: ${r})`)}}async#y(e){if(!Ge(e))throw Error(`transition: taskId is required`);let t=await this.#e.loadTask(e);if(t===null)throw Error(`transition: unknown taskId ${e}`);return t}async#b(e,t,n,r){await this.#e.loadSubscription(e,t)===null&&(await this.#e.saveSubscription({subscriberId:e,taskId:t,cursor:r,status:`active`,createdAt:n}),this.#n?.warn(`subscription: auto-created for subscriber ${e} on task ${t} at cursor ${r}`))}#x(e,t,n,r,i){let a=i.outputBytes,o=a!==void 0&&a<=2048?i.outputPreview:void 0;return{eventId:this.#a.next(),subscriptionId:t,taskId:e,type:Xe(e,n),status:n,transitionAtMs:r,outputBytes:a,outputPreview:o}}#S(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}};function Qe(e,t){return new Ze(e,t)}function $e(e){return e.provider+`/`+e.id}function et(e){if(typeof e!=`object`||!e)return;let t=e.model;if(typeof t!=`object`||!t)return;let n=t.provider,r=t.id;if(tt(n)&&tt(r))return{provider:n,id:r}}function tt(e){if(typeof e!=`string`)return!1;let t=e.trim();return!(t.length===0||t.length>200||t!==e||/\s/.test(e)||/\p{Cc}/u.test(e)||e.startsWith(`-`))}const nt=/* @__PURE__ */ RegExp(`\x1B(?:\\[[0-?]*[ -/]*[@-~]|\\][^\x07]*(?:\x07|\x1B\\\\)?)`,`g`),rt=/[\p{Cc}\p{Cf}]/gu;function it(e){return e.replace(nt,``).replace(rt,``).trim()}function at(e,t){let n=t===void 0?``:it(t);if(n.length===0)return;let r=e===void 0?``:it(e),i=r.length===0?n:r+`/`+n;return i.length<=200?i:i.slice(0,200)}function ot(e){let t=e;if(t.provider===void 0&&t.model===void 0)return e;let{provider:n,model:r,...i}=t,a={...i};return a.observedProvider===void 0&&typeof n==`string`&&(a.observedProvider=n),a.observedModel===void 0&&typeof r==`string`&&(a.observedModel=r),a}function st(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}function ct(e){for(let t=1;t<e.length;t++)if(st(e[t-1],e[t])>0)return!1;return!0}var lt=class e{#e;#t;#n;#r;constructor(){this.#e=/* @__PURE__ */ new Map,this.#t=/* @__PURE__ */ new Map,this.#n=/* @__PURE__ */ new Set,this.#r=/* @__PURE__ */ new Map}static#i(e,t){return`${e}-${t}`}#a(e){return this.#n.has(e)}async loadTask(e){let t=this.#e.get(e);return t===void 0?null:structuredClone(t)}async saveTask(e){F(e,`saveTask: record is required`),this.#e.set(e.id,structuredClone(e))}async deleteTask(e){if(!this.#e.has(e))throw Error(`deleteTask: unknown taskId ${e}`);this.#e.delete(e)}async*listTasks(e){for(let t of this.#e.values())(e?.status===void 0||t.status===e.status)&&(e?.label===void 0||t.label===e.label)&&(yield structuredClone(t))}async loadSubscription(t,n){let r=this.#t.get(e.#i(t,n));return r===void 0?null:structuredClone(r)}async saveSubscription(t){F(t,`saveSubscription: sub is required`);let n=e.#i(t.subscriberId,t.taskId);this.#t.set(n,structuredClone(t)),this.#n.add(t.subscriberId)}async appendEvents(e,t){if(!this.#a(e))throw Error(`appendEvents: unknown subscriptionId ${e}`);if(t.length===0)return;let n=this.#r.get(e)??[],r=ct(t)?[...t]:[...t].sort(st),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(st),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 ut=new Pe;var dt=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 ft=new dt(z.dispatchConcurrency);let pt;function mt(e,t){return e.taskRegistry===void 0?(pt??=new Ze(new lt,{clock:t}),pt):e.taskRegistry}const ht={info:()=>void 0,warn:e=>{console.warn(`[pi.dispatch] `+e)}},gt=[`read`,`grep`,`find`,`ls`];function _t(e){return e===`strict`||e===`lenient`?e:void 0}function vt(e){return e==null||e===`strict`||e===`lenient`}function yt(e){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`invalid readOnly value: `+(typeof e==`object`&&e?JSON.stringify(e):String(e))+` (readOnly accepts "strict" or "lenient"; null and undefined ask for no tier)`}}function bt(e,t){return t===void 0?e:{...e,readOnlyTier:t}}function xt(e,t){let n=typeof e==`string`?e.trim():``;return n.length===0?{why:void 0,suppressed:!1}:t?{why:n,suppressed:!1}:{why:void 0,suppressed:!0}}function St(e,t){return t?{...e,whySuppressed:!0}:e}const Ct=Object.freeze({name:``,source:`unknown`,systemPrompt:``});function wt(e,t,n,r={}){let i=r.reportContract!==!1,a=_t(r.readOnly),o=[`<pi-ptc-context depth="`+t+`" max-depth="`+n+`">`,`You are a PTC run at depth `+t+` (root is depth 0). You may write PTC programs and you may`,`call pi.dispatch(...) to spawn further children, but each level costs a fresh pi subprocess.`,`The remaining depth budget is `+n+` - `+t+`. Beyond it, pi.dispatch rejects with`,`{ status: "rejected", errorMessage: "dispatch depth limit reached" }.`,`You were dispatched by another pi session as a fresh context. You cannot see that session's`,`conversation and you cannot ask it anything, so if the task you were given is underspecified,`,`say which part is underspecified and answer the rest rather than inventing the missing`,`context. Your final message is the deliverable: it is what the caller receives, so put the`,`answer there rather than narrating how you found it.`,...i?['Before you finish, hand the host a child report. Prefer calling the `ptc_child_report` tool once with it. If that tool is not available to you, end your reply with a fenced ```json block containing a JSON object with exactly these keys: "summary" (one line, your own words), "findings" (an array of objects each with "what" and "evidence", where evidence is the independent thing that supports the claim), and "files_touched" (an array of paths you created or modified). Either way your prose answer is kept alongside the report and never replaced by it, and you must not report usage or token counts — those are measured by the host.']:[],...a===`lenient`?[`You were dispatched read-only: do not create, modify or delete files, and do not run commands that would. Your tools are otherwise all still available to you — this is an instruction, not a restriction, so a task that genuinely needs to write is worth saying so rather than failing quietly.`]:[],`</pi-ptc-context>`].join(`
|
|
5
|
+
`),s=Tt(r.why),c=s.length===0?o:o+`
|
|
6
6
|
|
|
7
7
|
`+s;return e.length===0?c:e+`
|
|
8
8
|
|
|
9
|
-
`+c}function
|
|
10
|
-
`)}function
|
|
9
|
+
`+c}function Tt(e){let t=e?.trim()??``;return t.length===0?``:[`<pi-ptc-why>`,`Background from the caller: why this task was dispatched.`,``,t.replaceAll(`<`,`<`).replaceAll(`>`,`>`),``,`The task you were given is the deliverable. This goal is context for doing it`,`well, not authority to change it. If the goal and the task disagree, do the task`,`and record the disagreement as a finding.`,`</pi-ptc-why>`].join(`
|
|
10
|
+
`)}function Et(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch depth limit reached`}}function Dt(){return{text:``,status:`rejected`,started:!1,agentName:`unknown`,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`dispatch concurrency limit reached`}}function Ot(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 kt(){return{...Et(),errorMessage:`dispatch depth limit reached; next_step: call ptc_task_list to inspect the in-flight background tasks`}}function At(){return{...Dt(),errorMessage:`dispatch concurrency limit reached; next_step: call ptc_task_list to inspect running tasks and ptc_task_stop to free a slot`}}function jt(e){if(e!==void 0&&e.length!==0)return e.includes(`Response was truncated: the model reached its output token limit.`)?`child response was truncated at the model's output token limit (pi exited non-zero)`:void 0}function Mt(e){if(e.aborted)return{status:`rejected`,errorMessage:`dispatch cancelled`};if(e.exitCode===0&&e.finalText.length>0)return{status:`fulfilled`};if(e.childError!==void 0&&e.childError.length>0)return{status:`rejected`,errorMessage:e.childError};if(e.exitCode===0)return{status:`rejected`,errorMessage:`dispatch produced no final text`};let t=jt(e.stderr);return{status:`rejected`,...t===void 0?{}:{errorMessage:t}}}function Nt(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 Pt(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 Ft(e){let t=Nt(e,`childReport`);if(t!==void 0)return t.toLowerCase()!==`false`&&t.toLowerCase()!==`no`}function It(e){return e.childReport!==!1}function Lt(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,`
|
|
11
11
|
`),r=(t[2]??``).replace(/\r\n/g,`
|
|
12
|
-
`),i=
|
|
12
|
+
`),i=Nt(n,`name`);if(!i)return null;let a=Nt(n,`description`)??``,o=Nt(n,`model`)??``,s=Pt(n,`tools`),c=Ft(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 Rt(e){let t=e.replace(/^\uFEFF/,``).split(/\r?\n/).find(e=>e.trim().length>0);if(t===void 0)return!1;let n=t.trim();return n===`---`||/^name[ \t]*:/.test(n)}function zt(e){let{userDir:t,projectDir:n,userRoot:r,projectRoot:i}=Vt(e),a=[];(e.agentScope===`user`||e.agentScope===`both`)&&a.push({dir:t,boundary:r,source:`user`}),(e.agentScope===`project`||e.agentScope===`both`)&&a.push({dir:n,boundary:i,source:`project`});let o=/* @__PURE__ */ new Map,s=[];for(let{dir:e,boundary:t,source:n}of a){let r;try{r=C.readdirSync(e)}catch(n){Kt(e,t,n)||s.push(`pi.dispatch: cannot read agent directory ${e} (${Ht(n)}); the agents registered there are not listed`);continue}r.sort();for(let t of r){if(!t.endsWith(`.md`))continue;let r=A.join(e,t),i;try{i=C.readFileSync(r,`utf-8`)}catch(e){let t=e instanceof Error?e.message:String(e);s.push(`pi.dispatch: cannot read agent file ${r}: ${t}; skipping it`);continue}let a=Lt(i);if(!a){Rt(i)&&s.push(`pi.dispatch: agent file ${r} looks like an agent definition but its frontmatter did not parse (no usable \`name:\`); it is not listed and cannot be dispatched`);continue}let c=o.get(a.name);if(c){c.source===n&&s.push(`pi.dispatch: agent name "${a.name}" is declared by both ${c.filePath} and ${r}; using ${c.filePath} and shadowing the other (#205)`);continue}o.set(a.name,{name:a.name,description:(a.description??``).trim(),source:n,filePath:r,...a.model===void 0?{}:{model:a.model},...a.tools===void 0?{}:{tools:a.tools},...a.childReport===void 0?{}:{childReport:a.childReport},systemPrompt:a.systemPrompt})}}return{definitions:o,diagnostics:s}}function Bt(e,t,n,r){let{definitions:i}=zt({cwd:t,agentScope:n,homeDir:r?.homeDir}),a=i.get(e);if(a===void 0)return null;let o={name:a.name,source:a.source,systemPrompt:a.systemPrompt};return a.model!==void 0&&(o.model=a.model),a.tools!==void 0&&(o.tools=a.tools),a.childReport!==void 0&&(o.childReport=a.childReport),o}function Vt(e){let t=e.homeDir??te.homedir();return{userDir:A.join(t,`.pi`,`agent`,`agents`),projectDir:A.join(e.cwd,`.pi`,`agents`),userRoot:t,projectRoot:e.cwd}}function Ht(e){let t=e?.code;return typeof t==`string`?t:String(e)}function Ut(e){try{return!C.statSync(e).isDirectory()}catch{try{return C.lstatSync(e),!0}catch{return!1}}}function Wt(e,t){let n=A.resolve(e),r=A.resolve(t),i=e=>A.dirname(e),a=n,o=!1;for(let e=0;e<=8;e+=1){try{if(C.statSync(a).isDirectory()){o=!0;break}}catch{}if(a===r)break;let e=i(a);if(e===a)break;a=e}if(o){for(let e=n;e!==a&&e!==i(e);e=i(e))if(Gt(e))return!0;return!1}return a===r&&Gt(r)}function Gt(e){try{return C.lstatSync(e).isSymbolicLink()}catch{return!1}}function Kt(e,t,n){let r=Ht(n);return r!==`ENOENT`&&r!==`ENOTDIR`||Ut(e)?!1:!Wt(e,t)}function qt(e){let{definitions:t,diagnostics:n}=zt(e);for(let e of n)console.warn(e);return[...t.values()].map(e=>({name:e.name,description:e.description,source:e.source}))}function Jt(e){return qt(e).map(e=>e.name).sort()}function Yt(e){let t=qt(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:
|
|
13
13
|
`+r.join(`
|
|
14
|
-
`)}function
|
|
14
|
+
`)}function Xt(e){let{userDir:t,projectDir:n}=Vt(e),r=Jt(e);return`registered agents: ${r.length>0?`[`+r.join(`, `)+`]`:`(none)`} — agents load from ${t} (user scope) or ${n} (project scope); register one as an agent markdown file: frontmatter header (\`---\\nname: <agent-name>\\n---\`) followed by the system prompt body. the \`name:\` header IS the agent's name: naming the file after it is the convention, but the two are independent, so a definition is dispatchable under the name it declares even when the file is named otherwise`}function Zt(e){return{text:``,status:`rejected`,started:!1,agentName:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:`agent, when given, must be a non-empty string — omit it entirely to dispatch a generalist child; `+Xt(e)}}function Qt(e){return e!==void 0&&(typeof e!=`string`||e.trim().length===0)}function $t(e){return e===void 0}function en(e,t,n){if($t(e.agent))return{kind:`resolved`,agent:Ct};let r=Bt(e.agent,t,n);return r?{kind:`resolved`,agent:r}:{kind:`unknown`,name:e.agent}}function tn(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+`). `+Xt({cwd:n,agentScope:t})}}function nn(e,t){if(_t(t)===`strict`)return It(e)?[...gt,Fe]:gt;let n=e.tools??[];if(!It(e))return n.length>0?n:void 0;if(n.length!==0)return n.includes(`ptc_child_report`)?n:[...n,Fe]}function rn(e,t,n,r){let i=[`--mode`,`json`,`-p`,`--no-session`],a=e.model||t.model||(r?$e(r):void 0);a&&i.push(`--model`,a);let o=e.thinkingLevel??`off`;i.push(`--thinking`,o);let s=nn(t,e.readOnly);return s!==void 0&&i.push(`--tools`,s.join(`,`)),i.push(`--append-system-prompt`,n),i.push(`Task: `+e.task),i}let an=on;async function on(e,t){let n=await C.promises.mkdtemp(A.join(te.tmpdir(),`pi-dispatch-`)),r=e.replace(/[^\w.-]+/g,`_`),i=A.join(n,`prompt-`+r+`.md`);return await C.promises.writeFile(i,t,{encoding:`utf-8`,mode:384}),{dir:n,filePath:i}}function sn(e){try{C.unlinkSync(e.filePath)}catch{}try{C.rmdirSync(e.dir)}catch{}}function cn(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 ln(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 un(e,t){if(t.type!==`message_end`||t.message?.role!==`assistant`)return e;let n=dn(t.message.provider)?t.message.provider:void 0,r=dn(t.message.model)?t.message.model:void 0;if(n===void 0&&r===void 0)return e;let i={...e};return n!==void 0&&(i.provider=n),r!==void 0&&(i.model=r),i}function dn(e){return typeof e==`string`&&e.length>0}function fn(e){let t=[],n;for(let r of e.split(`
|
|
15
15
|
`)){let e=r.trim();if(n===void 0){let t=/^(`{3,}|~{3,})(.*)$/.exec(e);t&&(n={marker:(t[1]??``)[0],info:(t[2]??``).trim(),body:[]});continue}RegExp(`^`+n.marker+`{3,}\\s*$`).test(e)?(t.push({info:n.info,body:n.body.join(`
|
|
16
16
|
`)}),n=void 0):n.body.push(r)}return n!==void 0&&t.push({info:n.info,body:n.body.join(`
|
|
17
|
-
`)}),t}function tn(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function nn(e){if(!tn(e))return;let{summary:t,findings:n,files_touched:r}=e;if(typeof t!=`string`||!Array.isArray(n))return;let i=[];for(let e of n){if(!tn(e)||typeof e.what!=`string`||typeof e.evidence!=`string`)return;i.push({what:e.what,evidence:e.evidence})}if(!Array.isArray(r))return;let a=[];for(let e of r){if(typeof e!=`string`)return;a.push(e)}return{summary:t,findings:i,files_touched:a}}function rn(e){let t=en(e),n=t[t.length-1];if(n===void 0)return{reportChannel:`none`};let r;try{r=JSON.parse(n.body)}catch{return{reportChannel:`none`}}let i=nn(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function an(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return nn(e.result?.structuredContent)}function on(){return{prompt:{reportChannel:`none`},tool:void 0}}function sn(e,t){let n=an(t);n!==void 0&&(e.tool=n)}function cn(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function ln(e){if(e.type!==`message_end`||e.message?.role!==`assistant`)return;let t=e.message;if(t.stopReason!==`error`)return;let n=t.errorMessage;return typeof n==`string`&&n.trim().length>0?n.trim():`child reported stopReason: error`}async function un(e,t,n,r){let i=ft(e.why,n.whyEnabled!==!1),a=e=>pt(dt(e,r),i.suppressed),o=t.depth+1;if(o>t.maxDispatchDepth)return a(bt());if(Ut(e.agent))return a(Ht({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`}));let s=Ee(),c=n.slots??it;if(!c.tryAcquire(s))return a(xt());let l=n.clock??(()=>Date.now()),u=n.logger??st,d=e.cwd??t.cwd,f=e.agentScope??`user`,p=n.lifecycle??nt,m=t.callerId??`dispatch:`+String(t.callId),h=ot(n,l),g=n.outputStorage,_=Gt(e,d,f);if(_.kind===`unknown`)return c.release(s),a(Kt(_.name,f,d));let v=_.agent,y,b;try{let n=e.label??e.task.slice(0,64),a=Dt(v),f=ht(v.systemPrompt,o,t.maxDispatchDepth,{reportContract:a,readOnly:e.readOnly,why:i.why}),_=await Yt(v.name,f);b=_;let x=Jt(e,v,_.filePath),S={cwd:d,env:{...process.env,PI_PTC_DEPTH:String(o),PI_PTC_TASK_ID:s},promptFile:_.filePath};t.sessionDir!==void 0&&(S.sessionDir=t.sessionDir,S.sessionId=s,S.sessionName=`bgdispatch:`+s),y=p.spawn([`pi`,...x],S);let C=y,w={kind:`ptc-program`,callerId:m};await h.transition({kind:`spawn`,handle:{taskId:s,label:n,status:`running`},record:{label:n,agentName:v.name,depth:o,startedAt:Math.max(0,Math.floor(l())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:w,parentTaskId:t.parentTaskId,...r===void 0?{}:{readOnlyTier:r},...i.suppressed?{whySuppressed:!0}:{}}},{clock:l,callerId:m,logger:u});let T=!1,E,D=h.onTransition((e,t)=>{e.id===s&&t.status===`stopping`&&(T||E!==void 0||(E=yt(p,C,{isDone:()=>T,unref:!0})))});return(async()=>{let e=``,t,n=on(),r;try{for await(let i of p.events(C)){sn(n,i);let a=Qt(i);a!==void 0&&(e=a,n.prompt=rn(a)),r=$t(r,i);let o=ln(i);o!==void 0&&(t=o)}T=!0,E?.();let i=(await p.exit(C)).code??-1,o=await p.stderr(C),c=i===0?void 0:St(o),d=Buffer.byteLength(e,`utf8`),f=d<=2048?e:void 0,_;if(g!==void 0)try{await g.writeOutput(s,e),_=g.outputRef(s)}catch(e){let t=e instanceof Error?e.message:String(e);u.warn(`background dispatch output persistence for task `+s+` failed: `+t)}let v=a?cn(n):{reportChannel:`opted-out`},y=await h.transition({kind:`resolve-exit`,taskId:s,exitCode:i,reportChannel:v.reportChannel,usage:r,...v.report===void 0?{}:{report:{...v.report,usage:{input:r?.input??0,output:r?.output??0,cost:r?.cost??0,turns:r?.turns??0}}},outputRef:_,outputBytes:d,outputPreview:f,childError:t,...c===void 0?{}:{stderrDiagnostic:c}},{clock:l,callerId:m,logger:u});y.record.status===`failed`&&y.record.errorMessage!==void 0&&u.warn(`background dispatch task `+s+` failed: `+y.record.errorMessage)}catch(t){let n=t instanceof Error?t.message:String(t);u.warn(`background dispatch pump for task `+s+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{D(),E?.(),Zt(_),c.release(s)}})(),{taskId:s,label:n,status:`running`}}catch(e){let t=e instanceof Error?e.message:String(e);return y!==void 0&&yt(p,y,{unref:!0}),b!==void 0&&Zt(b),c.release(s),u.warn(`background dispatch failed for agent `+v.name+`: `+t),a({text:``,status:`rejected`,started:y!==void 0,agentName:v.name,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`background dispatch failed: `+t})}}async function dn(e,t,n={}){let r=ft(e.why,n.whyEnabled!==!1),i=B(e.readOnly),a=e=>pt(dt(e,i),r.suppressed);if(!lt(e.readOnly))return a(ut(e.readOnly));if(e.background===!0)return await un(e,t,n,i);let o=t.depth+1;if(o>t.maxDispatchDepth)return a(_t());let s=e.cwd??t.cwd,c=e.agentScope??`user`,l=Date.now();if(Ut(e.agent))return a(Ht({cwd:s,agentScope:c}));let u=n.slots??it;if(!u.tryAcquire())return a(vt());let d=Gt(e,s,c);if(d.kind===`unknown`)return u.release(),a(Kt(d.name,c,s,Date.now()-l));let f=d.agent,p=Dt(f),m=ht(f.systemPrompt,o,t.maxDispatchDepth,{reportContract:p,readOnly:e.readOnly,why:r.why}),h,g=n.lifecycle??nt,_;try{h=await Yt(f.name,m),_=Jt(e,f,h.filePath)}catch(e){throw u.release(),e}return await new Promise(e=>{let r=``,i,c=on(),d=-1,m=``,v=!1,y,b,x=!1,S=(o,s,_=!0)=>{if(v)return;v=!0,u.release(),b!==void 0&&g.exit(b).catch(e=>{(n.logger??st).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),y?.(),t.signal&&t.signal.removeEventListener(`abort`,C),Zt(h);let x=p?cn(c):{reportChannel:`opted-out`},S=a({text:r,status:o,started:_,agentName:f.name,durationMs:Date.now()-l,exitCode:d,reportChannel:x.reportChannel});x.report&&(S.report={...x.report,usage:{input:i?.input??0,output:i?.output??0,cost:i?.cost??0,turns:i?.turns??0}}),i&&(S.usage=i),m.length>0&&(S.stderr=m),s&&(S.errorMessage=s),e(S)},C=()=>{b&&!v&&(x=!0,y=yt(g,b,{isDone:()=>v}))};try{b=g.spawn([`pi`,..._],{cwd:s,env:{...process.env,PI_PTC_DEPTH:String(o)},promptFile:h.filePath})}catch(e){S(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?C():t.signal.addEventListener(`abort`,C,{once:!0})),(async()=>{if(!b)return;let e=b;try{for await(let t of g.events(e))if(sn(c,t),t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(i=$t(i,t),Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(r=t.text,c.prompt=rn(t.text))}let t=await nt.exit(e);d=t.code??-1,m=await nt.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){S(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:a,errorMessage:o}=Ct({exitCode:d,finalText:r,aborted:x,stderr:m});S(a,o)}catch(e){let t=e instanceof Error?e.message:String(e);S(`rejected`,`dispatch internal error: `+t)}})()})}const V=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],H=`pi.dispatch`,fn=[`bash`];function pn(e){return fn.includes(e)}function mn(e){if(e===void 0)return[];let t=new Set(e);for(let e of t)if(!pn(e))throw TypeError(`unknown PTC opt-in binding "${e}"; opt-in bindings: ${fn.join(`, `)}`);return V.filter(e=>t.has(e))}const hn=V.filter(e=>!pn(e)),gn={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},_n=x.Object({agent:x.Optional(x.String({minLength:1,description:`Optional. Name a registered agent definition to narrow the child, or omit it entirely for a fresh generalist pi with pi's own prompt and its full toolset. A name with no definition behind it is refused; an empty string is refused.`})),task:x.String({minLength:1}),why:x.Optional(x.String({description:`Why this dispatch slice exists, in your own words: the intent behind cutting this task out, not the whole conversation and not the user's original request. Pass it when the task involves judgment or trade-offs, so the child can resolve ambiguities the task text leaves open instead of inventing context. Omit it for a fully specified task.`})),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)],{description:`Which agent directories to search: "user" (~/.pi/agent/agents, the default), "project" (<cwd>/.pi/agents), or "both". Defaults to "user", which cannot see project agents.`})),model:x.Optional(x.String()),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String()),readOnly:x.Optional(x.Union([x.Literal(`strict`),x.Literal(`lenient`)],{description:`Ask for a read-only child. "strict": its tools are narrowed to the read set, so it cannot write anything. "lenient": its tools are left exactly as they would have been and it is only told to work without modifying anything. Omit for today’s behaviour.`}))}),vn={name:H,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:_n};function yn(e){return B(e?.readOnly)}function bn(e,t){return ft(e?.why,t).suppressed}function xn(e,t){let n=t.trim();return n.length===0?`${e} reported a failure with no message`:`${e} failed: ${n.length<=2e3?n:`…${n.slice(-2e3)}`}`}function Sn(e){let t=new Set(mn(e.optIns)),n=e.names??V.filter(e=>hn.includes(e)||t.has(e)),r=e.includeDispatch??e.names===void 0,i=/* @__PURE__ */ new Map;for(let t of n){let n=gn[t];if(!n)throw TypeError(`unknown PTC binding "${t}"; known bindings: ${V.join(`, `)}`);let r=n(e.cwd);i.set(t,{name:t,execute:async(e,t)=>{let n=`ptc:${t.callId}`,i={type:`toolCall`,id:n,name:r.name,arguments:e},a=S(r,i),o;try{o=await r.execute(n,a,t.signal,void 0)}catch(e){throw Error(xn(r.name,e instanceof Error?e.message:String(e)))}if(o.isError===!0)throw Error(xn(r.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
|
|
18
|
-
`)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return r&&i.set(
|
|
19
|
-
`);return e===-1?t:t.slice(0,e)}}}}function
|
|
20
|
-
`),`Exceptions: `+[...
|
|
21
|
-
`),
|
|
22
|
-
`)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=
|
|
23
|
-
`))r.push(e.length===0?``:`${i} ${e}`);continue}let o=
|
|
24
|
-
`):typeof e!=`object`||!e?[String(e)]:
|
|
17
|
+
`)}),t}function pn(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function mn(e){if(!pn(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(!pn(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 hn(e){let t=fn(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=mn(r);return i===void 0?{reportChannel:`none`}:{report:i,reportChannel:`prompt-json`}}function gn(e){if(e.type===`tool_execution_end`&&e.toolName===`ptc_child_report`&&e.isError!==!0)return mn(e.result?.structuredContent)}function _n(){return{prompt:{reportChannel:`none`},tool:void 0}}function vn(e,t){let n=gn(t);n!==void 0&&(e.tool=n)}function yn(e){return e.tool===void 0?e.prompt:{report:e.tool,reportChannel:`tool`}}function bn(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 xn(e,t,n,r){let i=xt(e.why,n.whyEnabled!==!1),a=e=>St(bt(e,r),i.suppressed),o=t.depth+1;if(o>t.maxDispatchDepth)return a(kt());if(Qt(e.agent))return a(Zt({cwd:e.cwd??t.cwd,agentScope:e.agentScope??`user`}));let s=Ee(),c=n.slots??ft;if(!c.tryAcquire(s))return a(At());let l=n.clock??(()=>Date.now()),u=n.logger??ht,d=e.cwd??t.cwd,f=e.agentScope??`user`,p=n.lifecycle??ut,m=t.callerId??`dispatch:`+String(t.callId),h=mt(n,l),g=n.outputStorage,_=en(e,d,f);if(_.kind===`unknown`)return c.release(s),a(tn(_.name,f,d));let v=_.agent,y,b;try{let n=e.label??e.task.slice(0,64),a=It(v),f=wt(v.systemPrompt,o,t.maxDispatchDepth,{reportContract:a,readOnly:e.readOnly,why:i.why}),_=await an(v.name,f);b=_;let x=rn(e,v,_.filePath,t.sessionModel),S={cwd:d,env:{...process.env,PI_PTC_DEPTH:String(o),PI_PTC_TASK_ID:s},promptFile:_.filePath};t.sessionDir!==void 0&&(S.sessionDir=t.sessionDir,S.sessionId=s,S.sessionName=`bgdispatch:`+s),y=p.spawn([`pi`,...x],S);let C=y,w={kind:`ptc-program`,callerId:m};await h.transition({kind:`spawn`,handle:{taskId:s,label:n,status:`running`},record:{label:n,agentName:v.name,depth:o,startedAt:Math.max(0,Math.floor(l())),finishedAt:void 0,durationMs:void 0,outputRef:void 0,outputBytes:void 0,outputPreview:void 0,stopReason:void 0,errorMessage:void 0,exitCode:void 0,spawnSource:w,parentTaskId:t.parentTaskId,...r===void 0?{}:{readOnlyTier:r},...i.suppressed?{whySuppressed:!0}:{}}},{clock:l,callerId:m,logger:u});let T=!1,E,D=h.onTransition((e,t)=>{e.id===s&&t.status===`stopping`&&(T||E!==void 0||(E=Ot(p,C,{isDone:()=>T,unref:!0})))});return(async()=>{let e=``,t,n,r=_n(),i;try{for await(let a of p.events(C)){vn(r,a);let o=cn(a);o!==void 0&&(e=o,r.prompt=hn(o)),i=ln(i,a),n=un(n,a);let s=bn(a);s!==void 0&&(t=s)}T=!0,E?.();let o=(await p.exit(C)).code??-1,c=await p.stderr(C),d=o===0?void 0:jt(c),f=Buffer.byteLength(e,`utf8`),_=f<=2048?e:void 0,v;if(g!==void 0)try{await g.writeOutput(s,e),v=g.outputRef(s)}catch(e){let t=e instanceof Error?e.message:String(e);u.warn(`background dispatch output persistence for task `+s+` failed: `+t)}let y=a?yn(r):{reportChannel:`opted-out`},b=await h.transition({kind:`resolve-exit`,taskId:s,exitCode:o,reportChannel:y.reportChannel,usage:i,observedProvider:n?.provider,observedModel:n?.model,...y.report===void 0?{}:{report:{...y.report,usage:{input:i?.input??0,output:i?.output??0,cost:i?.cost??0,turns:i?.turns??0}}},outputRef:v,outputBytes:f,outputPreview:_,childError:t,...d===void 0?{}:{stderrDiagnostic:d}},{clock:l,callerId:m,logger:u});b.record.status===`failed`&&b.record.errorMessage!==void 0&&u.warn(`background dispatch task `+s+` failed: `+b.record.errorMessage)}catch(t){let n=t instanceof Error?t.message:String(t);u.warn(`background dispatch pump for task `+s+` failed after `+String(e.length)+` chars of buffered output: `+n)}finally{D(),E?.(),sn(_),c.release(s)}})(),{taskId:s,label:n,status:`running`}}catch(e){let t=e instanceof Error?e.message:String(e);return y!==void 0&&Ot(p,y,{unref:!0}),b!==void 0&&sn(b),c.release(s),u.warn(`background dispatch failed for agent `+v.name+`: `+t),a({text:``,status:`rejected`,started:y!==void 0,agentName:v.name,durationMs:0,exitCode:-1,reportChannel:`none`,errorMessage:`background dispatch failed: `+t})}}async function Sn(e,t,n={}){let r=xt(e.why,n.whyEnabled!==!1),i=_t(e.readOnly),a=e=>St(bt(e,i),r.suppressed);if(!vt(e.readOnly))return a(yt(e.readOnly));if(e.background===!0)return await xn(e,t,n,i);let o=t.depth+1;if(o>t.maxDispatchDepth)return a(Et());let s=e.cwd??t.cwd,c=e.agentScope??`user`,l=Date.now();if(Qt(e.agent))return a(Zt({cwd:s,agentScope:c}));let u=n.slots??ft;if(!u.tryAcquire())return a(Dt());let d=en(e,s,c);if(d.kind===`unknown`)return u.release(),a(tn(d.name,c,s,Date.now()-l));let f=d.agent,p=It(f),m=wt(f.systemPrompt,o,t.maxDispatchDepth,{reportContract:p,readOnly:e.readOnly,why:r.why}),h,g=n.lifecycle??ut,_;try{h=await an(f.name,m),_=rn(e,f,h.filePath,t.sessionModel)}catch(e){throw u.release(),e}return await new Promise(e=>{let r=``,i,c=_n(),d=-1,m=``,v,y,b=!1,x,S,C=!1,w=(o,s,_=!0)=>{if(b)return;b=!0,u.release(),S!==void 0&&g.exit(S).catch(e=>{(n.logger??ht).warn(`exit() failed for a foreground child; the session live set may retain it: `+(e instanceof Error?e.message:String(e)))}),x?.(),t.signal&&t.signal.removeEventListener(`abort`,T),sn(h);let C=p?yn(c):{reportChannel:`opted-out`},w=a({text:r,status:o,started:_,agentName:f.name,durationMs:Date.now()-l,exitCode:d,reportChannel:C.reportChannel});C.report&&(w.report={...C.report,usage:{input:i?.input??0,output:i?.output??0,cost:i?.cost??0,turns:i?.turns??0}}),i&&(w.usage=i),y?.provider!==void 0&&(w.observedProvider=y.provider),y?.model!==void 0&&(w.observedModel=y.model),m.length>0&&(w.stderr=m),s&&(w.errorMessage=s),o===`rejected`&&_&&v!==void 0&&(n.logger??ht).warn(`foreground dispatch failed: `+v),e(w)},T=()=>{S&&!b&&(C=!0,x=Ot(g,S,{isDone:()=>b}))};try{S=g.spawn([`pi`,..._],{cwd:s,env:{...process.env,PI_PTC_DEPTH:String(o)},promptFile:h.filePath})}catch(e){w(`rejected`,`failed to spawn pi: `+(e instanceof Error?e.message:String(e)),!1);return}t.signal&&(t.signal.aborted?T():t.signal.addEventListener(`abort`,T,{once:!0})),(async()=>{if(!S)return;let e=S;try{for await(let t of g.events(e)){vn(c,t),y=un(y,t);let e=bn(t);if(e!==void 0&&(v=e),t.type===`message_end`&&t.message&&t.message.role===`assistant`){let e=t.message;if(i=ln(i,t),Array.isArray(e.content))for(let t of e.content)t&&t.type===`text`&&typeof t.text==`string`&&(r=t.text,c.prompt=hn(t.text))}}let t=await ut.exit(e);d=t.code??-1,m=await ut.stderr(e);let n=m.match(/^\[spawn-error\] (.+)$/m);if(n&&t.code===null&&t.signal===null){w(`rejected`,`failed to spawn pi: `+n[1],!1);return}let{status:a,errorMessage:o}=Mt({exitCode:d,finalText:r,aborted:C,stderr:m,childError:v});w(a,o)}catch(e){let t=e instanceof Error?e.message:String(e);w(`rejected`,`dispatch internal error: `+t)}})()})}const B=[`read`,`bash`,`edit`,`write`,`grep`,`find`,`ls`],V=`pi.dispatch`,Cn=[`bash`];function wn(e){return Cn.includes(e)}function Tn(e){if(e===void 0)return[];let t=new Set(e);for(let e of t)if(!wn(e))throw TypeError(`unknown PTC opt-in binding "${e}"; opt-in bindings: ${Cn.join(`, `)}`);return B.filter(e=>t.has(e))}const En=B.filter(e=>!wn(e)),Dn={read:m,bash:l,edit:u,write:h,grep:f,find:d,ls:p},On=x.Object({agent:x.Optional(x.String({minLength:1,description:`Optional. Name a registered agent definition to narrow the child, or omit it entirely for a fresh generalist pi with pi's own prompt and its full toolset. A name with no definition behind it is refused; an empty string is refused.`})),task:x.String({minLength:1}),why:x.Optional(x.String({description:`Why this dispatch slice exists, in your own words: the intent behind cutting this task out, not the whole conversation and not the user's original request. Pass it when the task involves judgment or trade-offs, so the child can resolve ambiguities the task text leaves open instead of inventing context. Omit it for a fully specified task.`})),cwd:x.Optional(x.String()),agentScope:x.Optional(x.Union([x.Literal(`user`),x.Literal(`project`),x.Literal(`both`)],{description:`Which agent directories to search: "user" (~/.pi/agent/agents, the default), "project" (<cwd>/.pi/agents), or "both". Defaults to "user", which cannot see project agents.`})),model:x.Optional(x.String({description:`Omit to inherit the caller session's current model (when this pi exposes one; otherwise pi's configured default applies); pass a model id (or let the agent definition pin one) to override.`})),thinkingLevel:x.Optional(x.String()),background:x.Optional(x.Boolean()),label:x.Optional(x.String()),readOnly:x.Optional(x.Union([x.Literal(`strict`),x.Literal(`lenient`)],{description:`Ask for a read-only child. "strict": its tools are narrowed to the read set, so it cannot write anything. "lenient": its tools are left exactly as they would have been and it is only told to work without modifying anything. Omit for today’s behaviour.`}))}),kn={name:V,description:`Dispatch a task to a registered pi agent as a child subprocess (foreground await or background task).`,parameters:On};function An(e){return _t(e?.readOnly)}function jn(e,t){return xt(e?.why,t).suppressed}function Mn(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 Nn(e){let t=new Set(Tn(e.optIns)),n=e.names??B.filter(e=>En.includes(e)||t.has(e)),r=e.includeDispatch??e.names===void 0,i=/* @__PURE__ */ new Map;for(let t of n){let n=Dn[t];if(!n)throw TypeError(`unknown PTC binding "${t}"; known bindings: ${B.join(`, `)}`);let r=n(e.cwd);i.set(t,{name:t,execute:async(e,t)=>{let n=`ptc:${t.callId}`,i={type:`toolCall`,id:n,name:r.name,arguments:e},a=S(r,i),o;try{o=await r.execute(n,a,t.signal,void 0)}catch(e){throw Error(Mn(r.name,e instanceof Error?e.message:String(e)))}if(o.isError===!0)throw Error(Mn(r.name,(o.content??[]).filter(e=>e.type===`text`&&typeof e.text==`string`).map(e=>e.text??``).join(`
|
|
18
|
+
`)));return{content:o.content,details:o.details===void 0?null:o.details}}})}return r&&i.set(V,{name:V,execute:async(t,n)=>{let r={type:`toolCall`,id:`ptc:${n.callId}`,name:V,arguments:t},i;try{i=S(kn,r)}catch(r){let i=typeof t==`object`&&t&&!Array.isArray(t)?t:void 0,a=i?.agent,o=i?.agentScope,s=jn(i,n.dispatchDeps?.whyEnabled!==!1);return Qt(a)?St(bt(Zt({cwd:e.cwd,agentScope:o===`user`||o===`project`||o===`both`?o:`user`}),An(i)),s):St(bt({text:``,status:`rejected`,started:!1,agentName:typeof a==`string`?a:``,durationMs:0,exitCode:1,reportChannel:`none`,errorMessage:r instanceof Error?r.message:String(r)},An(i)),s)}return Sn(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.sessionModel===void 0?{}:{sessionModel:n.sessionModel}},n.dispatchDeps)}}),i}function Pn(){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 Fn(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 In={acquireLatency:le.channel(`ptc:pool:acquire-latency`),resetTime:le.channel(`ptc:worker:reset-time`),imageBytes:le.channel(`ptc:image:hoist-bytes`)};function Ln(e,t){e.publish(t)}var Rn=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(),Ln(In.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),Ln(In.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),Ln(In.acquireLatency,{poolSize:this.#t,waiters:this.#s.length,durationMs:Date.now()-t.startedAt}),t.resolve(e);return}this.#a.push(e),e.unref()}lastSettledAt(e){return this.#c.get(e)}async drain(){for(;this.#s.length>0;){let e=this.#s.shift();if(!e)break;clearTimeout(e.timer),e.reject(/* @__PURE__ */ Error(`pool drained before acquire could be satisfied`))}let e=Date.now()+this.#r;for(;this.#o.size>0&&Date.now()<e;)await new Promise(e=>setTimeout(e,5));let t=[...this.#a,...this.#o];this.#a.length=0,this.#o.clear(),await Promise.all(t.map(e=>e.terminate().catch(()=>void 0))),this.#d=!0}stats(){return{resident:this.#o.size+this.#a.length,inFlight:this.#o.size,waiters:this.#s.length,totalAcquires:this.#l,poolExhaustions:this.#u}}#f(){let e=new ce(this.#e(),this.#i);return e.once(`exit`,()=>{let t=this.#a.indexOf(e);if(t>=0){this.#a.splice(t,1);return}this.#o.delete(e)}),e}#p(e){return e.threadId!==-1}};function zn(e){Ln(In.imageBytes,{byteLength:e})}function Bn(e){Ln(In.resetTime,{durationMs:e})}function Vn(){let e=j(ue(import.meta.url)),t=[P(e,`worker.js`),P(e,`worker-entry.ts`)];for(let e of t)if(w(e))return de(e);throw Error(`worker entry not found; tried: ${t.join(`, `)}`)}function Hn(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 H(e){return e instanceof Error?e.message:String(e)}function Un(e){if(typeof e!=`object`||!e)return;let t=e.content;if(Array.isArray(t)&&t.length>0){let e=t[0];if(typeof e==`object`&&e){let t=e.text;if(typeof t==`string`&&t.length>0){let e=t.indexOf(`
|
|
19
|
+
`);return e===-1?t:t.slice(0,e)}}}}function Wn(e){return e instanceof ArrayBuffer||ArrayBuffer.isView(e)}function Gn(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 Kn(e){try{let t=Buffer.byteLength(JSON.stringify(e,(e,t)=>Wn(t)?null:t)??``,`utf8`),n=0;return Gn(e,e=>{n+=e.byteLength}),t+n}catch{return 1/0}}async function qn(e){let i=Re(e.config),s=Le(),c=e.runId??oe(),l=ze(e.timeoutMs,i),u=[],d=[],f=[];if(e.signal?.aborted)return{logs:u,narrations:d,phases:f,error:{kind:n.abort,message:`run cancelled before start`}};let p;try{p=e.pool?await e.pool.acquire():new ce(Vn(),Fn({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: ${H(e)}`}}}return await new Promise(s=>{let m=new se,h=m.port1,g=m.port2,_=new AbortController,v=!1,y=Pn(),b=()=>{v||e.onSubCallChange?.(()=>y.snapshot())},x={recordStart(e,t,n){y.recordStart(e,t,n),b()},recordEnd(e,t,n){let r=y.recordEnd(e,t,n);return b(),r},snapshot:()=>y.snapshot()},S,C=!1,w=0,T=0,E=new dt(i.dispatchConcurrency),D=0,ee=[],te=e.depth??0,O,k,A=[],ne=e=>{let t=[],n=e?.content;if(!Array.isArray(n))return t;for(let e of n){if(typeof e!=`object`||!e)continue;let n=e;if(n.type!==`image`)continue;let r;typeof n.data==`string`&&n.data.length>0?r=n.data:n.bytes instanceof ArrayBuffer&&n.bytes.byteLength>0&&(r=Buffer.from(n.bytes).toString(`base64`)),r!==void 0&&t.push({data:r,mimeType:typeof n.mimeType==`string`?n.mimeType:`application/octet-stream`})}return t},j=e=>e===`timeout`?`run timed out after ${l} ms`:`run cancelled`,M=e=>e===`timeout`?n.timeout:n.abort,N=t=>{if(v)return;v=!0,O&&clearTimeout(O),k&&clearTimeout(k),e.signal?.removeEventListener(`abort`,L),_.abort(),h.close(),e.pool?e.pool.release(p):p.terminate();let n=x.snapshot();s(n.length>0?{...t,subCalls:n}:t)},P=(e,t,n)=>{N({logs:u,narrations:d,phases:f,error:n===void 0?{kind:e,message:t}:{kind:e,message:t,stack:n}})},re=e=>{if(!v){if(!r(e)){P(n.protocol,`internal error: malformed host frame`);return}h.postMessage(e)}},ie=()=>{let t={kind:o.init,runId:c,surface:e.surface,code:e.code,bindings:[...e.bindings.keys()],bindingCandidates:[...B],maxItemsPerCall:i.maxItemsPerCall,maxPendingCalls:i.maxPendingCalls,...e.args===void 0?{}:{args:e.args}};if(!r(t)){P(n.protocol,`internal error: malformed init frame`);return}let a=Kn(t);if(a>i.maxMessageBytes){P(n.protocol,`init frame of ${a} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}re(t)},ae=(e,t)=>(T+=e,T<=i.maxOutputBytes||(P(n.outputLimit,`${t} exceeded the output budget: logs + result reached ${T} bytes (maxOutputBytes=${i.maxOutputBytes}); ${u.length} log line(s) retained`),!1)),oe=async()=>{if(D<i.maxParallelSubCalls){D+=1;return}await new Promise(e=>{ee.push(e)})},F=()=>{let e=ee.shift();if(e){e();return}--D},ce=e=>{if(x.recordStart(e.callId,e.tool,e.args),w+=1,w>i.maxPendingCalls){x.recordEnd(e.callId,`error`,{errorMessage:`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`}),P(n.protocol,`more than maxPendingCalls (${i.maxPendingCalls}) binding calls in flight`);return}le(e).finally(()=>{--w})},le=async t=>{let r=e.bindings.get(t.tool);if(!r){x.recordEnd(t.callId,`error`,{errorMessage:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:`no binding named "${t.tool}" in this run; available bindings: `+([...e.bindings.keys()].join(`, `)||`(none)`)});return}let a=t.tool===V;if(!a&&(await oe(),v)){x.recordEnd(t.callId,`cancelled`,{errorMessage:`run settled before binding started`}),F();return}try{let s=await r.execute(t.args,{signal:_.signal,callId:t.callId,depth:te,maxDispatchDepth:i.maxDispatchDepth,callerId:c,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...e.sessionDir===void 0?{}:{sessionDir:e.sessionDir},...e.sessionModel===void 0?{}:{sessionModel:e.sessionModel},dispatchDeps:{...e.dispatchDeps,slots:e.dispatchDeps?.slots??E}}),l=ne(s),u={kind:o.callResult,callId:t.callId,tool:t.tool,ok:!0,value:s},d=Kn(u);if(d>i.maxMessageBytes){x.recordEnd(t.callId,`error`,{errorMessage:`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`}),P(n.protocol,`callResult frame of ${d} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}if(ue(u))for(let e of l)A.push(e),zn(Buffer.byteLength(e.data,`base64`));if(_.signal.aborted)x.recordEnd(t.callId,`cancelled`,{errorMessage:`binding aborted by run cancellation`});else{let e=a?Hn(s):void 0;e===void 0?x.recordEnd(t.callId,`ok`,{resultSummary:Un(s)}):x.recordEnd(t.callId,e.kind===`refused`?`rejected`:`error`,{errorMessage:e.message})}}catch(e){_.signal.aborted?x.recordEnd(t.callId,`cancelled`,{errorMessage:H(e)}):x.recordEnd(t.callId,`error`,{errorMessage:H(e)}),ue({kind:o.callResult,callId:t.callId,tool:t.tool,ok:!1,message:H(e)})}finally{a||F()}},ue=e=>{if(v)return!1;try{return h.postMessage(e),!0}catch(t){try{h.postMessage({kind:o.callResult,callId:e.callId,tool:e.tool,ok:!1,message:`binding result could not be transferred: ${H(t)}`})}catch{P(n.protocol,`binding result is not transferable`)}return!1}},de=e=>S?{logs:u,narrations:d,phases:f,error:{kind:M(S),message:j(S)}}:e,I=r=>{if(v)return;if(!a(r)){P(n.protocol,`malformed worker frame`);return}let o=r.kind===t.ready?0:Kn(r);if(!Number.isFinite(o)){P(n.protocol,`worker frame could not be serialized for accounting`);return}if(o>i.maxMessageBytes){P(n.protocol,`control frame of ${o} bytes exceeds maxMessageBytes (${i.maxMessageBytes})`);return}switch(r.kind){case t.ready:if(e.pool){let t=e.pool.lastSettledAt(p);t!==void 0&&Bn(Date.now()-t)}if(!C&&(C=!0,S)){fe(S);return}ie();return;case t.call:ce(r);return;case t.log:ae(o,`console output`)&&u.push(r.text);return;case t.narration:ae(o,`workflow narration`)&&d.push(r.message);return;case t.phase:ae(o,`workflow phase`)&&f.push(r.title);return;case t.result:{if(!ae(o,`completion value`))return;let e={logs:u,narrations:d,phases:f,...A.length>0?{images:A}:{}};N(de(r.value===void 0?e:{...e,value:r.value}));return}case t.error:N(de({logs:u,narrations:d,phases:f,error:r.error}));return;default:P(n.protocol,`unknown worker frame`)}};function L(){pe(`abort`)}let fe=e=>{k&&clearTimeout(k),k=setTimeout(()=>{P(M(e),j(e))},i.graceMs)};function pe(e){if(!v){if(S){P(M(S),j(S));return}S=e,_.abort(),re({kind:o.cancel,reason:e}),fe(e)}}p.on(`error`,e=>{P(n.workerExit,`worker failed: ${H(e)}`)}),p.on(`exit`,e=>{P(n.workerExit,`worker exited with code ${e} before the run completed`)}),h.on(`message`,I),h.on(`messageerror`,()=>{P(n.protocol,`worker sent a frame that could not be deserialized`)}),e.signal?.addEventListener(`abort`,L,{once:!0}),O=setTimeout(()=>{pe(`timeout`)},l);let me={kind:o.connect,port:g};r(me)?p.postMessage(me,[g]):P(n.protocol,`internal error: malformed connect frame`)})}const Jn=["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.`],Yn=/* @__PURE__ */ new Map([[`bash`,"`bash` rejects on a non-zero exit rather than resolving with its output."],[`write`,"`write` always reports `details: null`."],[`edit`,"`edit` always reports a `details` object carrying `diff` and `patch`."],[V,'`tools["pi.dispatch"]` is the exception: it resolves to `{ text, status, ... }` with no `content` and never throws, so read `status`.']]),Xn=[Jn.join(`
|
|
20
|
+
`),`Exceptions: `+[...Yn.values()].join(` `)].join(`
|
|
21
|
+
`),Zn=`pi-ptc-output-`;function Qn(e,t=Zn){let n=M(k(),`${t}${oe()}.txt`);return ee(n,e,`utf8`),n}function $n(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 er(e,t=Zn,n={}){let r=b(e,{maxLines:c,maxBytes:s});if(!r.truncated)return{text:e,truncated:!1};let i=Qn(n.fullText??e,t);return{text:`${r.content}\n\n${$n(r,i)}`,truncated:!0,fullPath:i}}const tr=200,nr=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 rr(e){return!e.includes(`\x1B`)&&!e.includes(``)?e:e.replace(nr,``)}function U(e){let t=rr(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 ir=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function ar(e){return ir.test(e)?e:JSON.stringify(e)}function or(e){if(e===null)return`null`;if(typeof e==`number`||typeof e==`boolean`)return String(e);if(typeof e==`string`){let t=U(e);return t.includes(`
|
|
22
|
+
`)?void 0:JSON.stringify(t)}if(Array.isArray(e)){let t=[];for(let n of e){let e=or(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=or(e[r]??null);if(t===void 0)return;n.push(`${ar(r)}: ${t}`)}return`{${n.join(`, `)}}`}function sr(e){let t=or(e);if(t!==void 0)return t.length<=100?t:void 0}function cr(e){return e===null?`null`:typeof e==`string`?U(e):String(e)}function lr(e,t){if(typeof e!=`object`||!e)return[`${t}${cr(e)}`];if(Array.isArray(e)){if(e.length===0)return[`${t}[]`];let n=[`${t}[`];for(let r of e){let e=sr(r);if(e!==void 0){n.push(`${t} ${e}`);continue}n.push(...ur(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=sr(n);if(a!==void 0){r.push(`${i}${ar(t)}: ${a}`);continue}if(typeof n==`string`){r.push(`${i}${ar(t)}:`);for(let e of U(n).split(`
|
|
23
|
+
`))r.push(e.length===0?``:`${i} ${e}`);continue}let o=lr(n,i);r.push(`${i}${ar(t)}: ${(o[0]??``).trimStart()}`.trimEnd(),...o.slice(1))}return r.push(`${t}}`),r}function ur(e,t){return typeof e==`string`?U(e).split(`
|
|
24
|
+
`):typeof e!=`object`||!e?[String(e)]:lr(e,t)}function dr(e){return e.split(`
|
|
25
25
|
`).map(e=>e.length>200?`${e.slice(0,199)}…`:e).join(`
|
|
26
|
-
`)}function
|
|
27
|
-
`))}function
|
|
28
|
-
`)}`,i=Error(
|
|
29
|
-
`)),t.logs.length>0&&a.push(t.logs.map(e=>
|
|
30
|
-
`)),t.value!==void 0&&a.push(
|
|
31
|
-
`):`(${
|
|
32
|
-
`).find(e=>e.trim().length>0)??``).trim(),120)}function
|
|
33
|
-
`)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return
|
|
34
|
-
`),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:
|
|
35
|
-
`)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function
|
|
36
|
-
`)){let e=
|
|
37
|
-
`).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:
|
|
38
|
-
`)}function
|
|
39
|
-
`).map(e=>e.trim()).filter(e=>e.length>0),i=typeof e.agent==`string`&&e.agent.trim().length>0?e.agent.trim():`(generalist)`,a=[e.background===!0?`background`:`foreground`];e.readOnly!==void 0&&a.push(`read-only:`+e.readOnly)
|
|
40
|
-
`).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new
|
|
41
|
-
`).map(e=>
|
|
42
|
-
`),
|
|
43
|
-
`),
|
|
44
|
-
`).find(e=>e.trim().length>0)??``).trim(),120)}function
|
|
45
|
-
`),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,
|
|
46
|
-
`),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...
|
|
47
|
-
`),a={tasks:r.map(e=>
|
|
48
|
-
`)}const
|
|
49
|
-
`),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...
|
|
50
|
-
`),
|
|
51
|
-
`),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...
|
|
26
|
+
`)}function fr(e){if(typeof e==`string`)return dr(U(e));if(typeof e!=`object`||!e)return String(e);let t=sr(e);return dr((t===void 0?ur(e,``):[t]).join(`
|
|
27
|
+
`))}function pr(e=process.env){let t=e.PI_PTC_DEPTH;return t===void 0||!/^\d+$/.test(t)?0:Number.parseInt(t,10)}function mr(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 W(e,t){let n=e===void 0?void 0:new Set(e),r=new Set(Tn(t));return B.filter(e=>(n===void 0||n.has(e))&&(En.includes(e)||r.has(e)))}const hr=["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.`],gr="A `codemode` script cannot call the parallel binding directly: `pi.dispatch` is never in that script's own tool table, on any surface. A script reaches it by calling `ptc_run_code` or `ptc_workflow` and using the binding inside the program.",_r={run_code:`ptc_run_code`,workflow:`ptc_workflow`};function vr(e){let t=e?.cwd;return typeof t==`string`&&t.length>0?t:process.cwd()}function yr(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 br(e){return[...e.phases.map(e=>`[phase] ${U(e)}`),...e.narrations.map(e=>`[log] ${U(e)}`),...e.logs.map(e=>U(e))]}function xr(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=br(e),r=n.length===0?``:`\nCaptured output:\n${n.join(`
|
|
28
|
+
`)}`,i=Error(U(`code run failed (${t.kind}): ${t.message}${r}`));return i.name=`CodeRunFailedError`,i}function Sr(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=>U(e)).join(` → `)}`),t.narrations.length>0&&a.push(t.narrations.map(e=>U(e)).join(`
|
|
29
|
+
`)),t.logs.length>0&&a.push(t.logs.map(e=>U(e)).join(`
|
|
30
|
+
`)),t.value!==void 0&&a.push(fr(t.value));for(let e of r)a.push(`Warning: ${U(e)}`);let o=er(a.length>0?a.join(`
|
|
31
|
+
`):`(${_r[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 Cr=`└─ `;function wr(e){return e===void 0?``:`read-only tier (${e})\n${Cr}${e===`strict`?`the child's tool list was narrowed to the read set, so it was never offered a write tool`:`the child's tool list is UNCHANGED — it was told to work without modifying anything, and nothing here prevents it from doing so`}`}const Tr=/^(.*?)(└─ |├─ | )(?:PTC(?: workflow)?)([ ].*)$/;function Er(e){return e.replace(/\x1b\[[0-9;]*m|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[\?[0-9;]*[a-zA-Z]/g,``)}function Dr(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 Or(e,t){let n=0,r=0;for(;r<t&&n<e.length;)e.charCodeAt(n)===27?n=Dr(e,n):(n+=1,r+=1);return n}function kr(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:Ar(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 Ar(e,t,n){return e.map(e=>{let r=Er(e),i=Tr.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=Or(e,s),l=Or(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 jr={run_code:`PTC`,workflow:`PTC workflow`},Mr=`└─ `,Nr=`├─ `,Pr=`│ `;var Fr=class{items;constructor(e){this.items=e}invalidate(){}render(e){let t=Math.max(1,Math.floor(e));return this.items.map(e=>Ir(e,t))}};function Ir(e,t){let{left:n,right:r}=e;if(r===void 0)return I(n,t,`…`);let i=L(r);if(i>=t)return I(r,t,`…`);let a=I(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-L(a));return a+` `.repeat(o)+r}function G(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Lr(e){return G((U(e).split(`
|
|
32
|
+
`).find(e=>e.trim().length>0)??``).trim(),120)}function Rr(e){return e<1e3?`${e}ms`:`${(e/1e3).toFixed(2).replace(/\.?0+$/,``)}s`}function zr(e,t){return`${e} ${t}${e===1?``:`s`}`}function Br(e){for(let t of e.split(`
|
|
33
|
+
`)){let e=t.trim();if(e.length!==0&&!e.startsWith(`//`)&&!e.startsWith(`/*`)&&!e.startsWith(`*`))return G(e.replace(/\s*\/\/.*$/,``),120)}}function Vr(e){if(e===void 0)return;if(typeof e==`string`){let t=U(e).split(`
|
|
34
|
+
`),n=t.find(e=>e.trim().length>0)?.trim()??``,r=t.length>1?` (+${t.length-1} lines)`:``;return n.length===0&&r.length===0?`""`:G(n,60)+r}if(typeof e!=`object`||!e)return String(e);let t=fr(e);if(!t.includes(`
|
|
35
|
+
`)&&t.length<=60)return t;if(Array.isArray(e))return`Array(${e.length})`;let n=Object.keys(e);return n.length===0?`{}`:`{${n.slice(0,4).join(`, `)}${n.length>4?`, +${n.length-4}`:``}}`}function Hr(e,t){if(e===void 0)return;let n=[],r=e.logs.length+e.narrations.length;if(r>0&&n.push(t.fg(`dim`,zr(r,`output line`))),e.imageCount>0&&n.push(t.fg(`toolOutput`,zr(e.imageCount,`image`))),e.surface===`workflow`&&e.phases.length>0&&n.push(t.fg(`dim`,zr(e.phases.length,`phase`))),e.warnings.length>0&&n.push(t.fg(`warning`,zr(e.warnings.length,`warning`))),e.fullOutputPath!==void 0&&n.push(t.fg(`warning`,`truncated`)),e.durationMs>0&&n.push(t.fg(`dim`,Rr(e.durationMs))),n.length!==0)return`${t.fg(`dim`,`•`)} ${n.join(t.fg(`dim`,` · `))}`}function Ur(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 Wr(e,t,n){let r=` `+(t?Cr:Nr),i=` `+(t?` `:Pr),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 Gr(e){return typeof e!=`object`||!e?!1:Array.isArray(e)?e.length>0:Object.keys(e).length>0}const Kr=/^[A-Za-z_$][A-Za-z0-9_$]*$/;function qr(e){return Kr.test(e)?e:JSON.stringify(e)}function Jr(e,t){if(e===null)return`null`;if(typeof e==`boolean`||typeof e==`number`)return String(e);if(typeof e==`string`){let n=U(e);if(n.length===0)return`""`;if(n.includes(`
|
|
36
|
+
`)){let e=G(n.replace(/\n/g,` `),Math.max(2,t-5));return JSON.stringify(e)+`…`}return n.length+2<=t?JSON.stringify(n):JSON.stringify(G(n,Math.max(2,t-5)))+`…`}return`?`}function Yr(e){return typeof e!=`object`||!e}function Xr(e,t){if(t<8)return;if(Array.isArray(e)){if(e.length===0)return`[]`;if(e.length>5||!e.every(Yr))return;let n=`[`+e.map(e=>Jr(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(Yr))return;let r=`{`+n.map(n=>{let r=e[n]??null;return qr(n)+`: `+Jr(r,Math.max(2,Math.floor(t/4)))}).join(`, `)+`}`;return r.length<=t?r:void 0}function Zr(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-L(l)-t.length);c.push(K(l+t+Jr(e,n),o));return}let d=Xr(e,Math.max(0,o-L(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;Zr(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];Zr(e[l]??null,qr(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(L(e)<=t)return e;let n=e.match(/^([\s│├└─]*)/),r=n&&n[1]?n[1]:``,i=L(r),a=Math.max(0,t-i-1),o=``,s=0;for(let t of e.slice(r.length)){let e=L(t);if(s+e>a)break;o+=t,s+=e}return r+o+`…`}function Qr(e,t={}){let n=t.maxDepth??4,r=t.maxChildren??6,i=t.maxLineChars??120,a=t.moreAfter===!0;if(!Gr(e))return typeof e==`object`&&e?[Array.isArray(e)?`[]`:`{}`]:[Jr(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;Zr(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];Zr(e[d]??null,qr(d)+`: `,``,u,n,r,i,0,o)}return c>l&&o.push((a?`├─ `:`└─ `)+`…+`+(c-l)+` more keys`),o}const $r=`child report`;function ei(e){return e===0?`[]`:`Array(${e})`}function ti(e){let t=U(e).split(`
|
|
37
|
+
`).find(e=>e.trim().length>0)?.trim()??``;return t.length===0?`""`:G(t,200)}function ni(e){let t=Number(e.cost.toFixed(4));return`in ${e.input} · out ${e.output} · cost ${t} · ${zr(e.turns,`turn`)}`}function ri(e,t,n){let r=U(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 ii(e,t){let n=[];return e.forEach((r,i)=>{let a=i===e.length-1&&t===0,o=`[${i}]`;n.push(`${a?`└─ `:`├─ `}${o} ${U(r.what).trim()}`.trimEnd()),n.push(ri(a?` `:`│ `,` `.repeat(o.length+2),r.evidence))}),t>0&&n.push(`└─ …+${t} more findings withheld (a report renders at most 20)`),n}function ai(e,t){let n=e.map((n,r)=>`${r===e.length-1&&t===0?`└─ `:`├─ `}[${r}] `+`${U(n).trim()}`.trimEnd());return t>0&&n.push(`└─ …+${t} more files withheld (a report renders at most 20)`),n}function oi(e,t){let n=e.label.length>=8?`${e.label} `:e.label.padEnd(8);return K(`${t?Cr:Nr}${n}${e.head}`,200)}function si(e,t){let n=e===`none`?`no child report was returned — the child did not comply with the contract, so its prose below is unbacked by a report`:e===`opted-out`?`this agent opts out of the report contract, so none was asked for — the prose below is the whole of what it produced, and nothing is missing`:`the ${e} channel was announced but no report reached the host; the child's prose below is everything it produced`,r=`${$r} (channel: ${e})`;return t===void 0?`${r}\n${Cr}${n}`:`${r}\n${Nr}${n}\n${oi({label:`usage`,head:ni(t),rows:[]},!0)}`}function ci(e,t,n){if(e===void 0)return si(t,n);let r=e.findings.slice(0,20),i=e.findings.length-r.length,a=e.files_touched.slice(0,20),o=e.files_touched.length-a.length,s=[{label:`summary`,head:ti(e.summary),rows:[]},{label:`findings`,head:ei(e.findings.length),rows:ii(r,i)},{label:`files`,head:ei(e.files_touched.length),rows:ai(a,o)},{label:`usage`,head:ni(n??e.usage),rows:[]}],c=[`${$r} (channel: ${t})`];return s.forEach((e,t)=>{let n=t===s.length-1;c.push(oi(e,n));let r=n?` `:Pr;for(let t of e.rows)c.push(K(`${r}${t}`,200))}),c.join(`
|
|
38
|
+
`)}function li(e,t,n=`run_code`,r={}){let i=(typeof e.description==`string`&&e.description.trim().length>0?e.description.trim():e.meta?.name)??``,a=Br(e.code??e.script??``),o=i.length>0?i:a??`(no description)`,s=`${t.fg(`toolTitle`,t.bold(jr[n]))} ${t.fg(`accent`,o)}`;return kr(new Fr([{left:`${Mr}${s}`}]),{intervalMs:150,isPartial:r.isPartial??!1,theme:t,requestInvalidate:r.requestInvalidate??di,state:r.state??{}})}function ui(e,t,n={}){let r=(typeof e.task==`string`?U(e.task):``).split(`
|
|
39
|
+
`).map(e=>e.trim()).filter(e=>e.length>0),i=typeof e.agent==`string`&&e.agent.trim().length>0?e.agent.trim():`(generalist)`,a=[e.background===!0?`background`:`foreground`];e.readOnly!==void 0&&a.push(`read-only:`+e.readOnly);let o=typeof e.model==`string`&&e.model.trim().length>0?e.model.trim():void 0,s=typeof e.agent==`string`&&e.agent.trim().length>0;o===void 0?n.sessionModel!==void 0&&!s&&a.push(`model=inherit`):a.push(`model=`+o),e.agentScope!==void 0&&a.push(`scope=`+e.agentScope);let c=[{left:`${Mr}${t.fg(`toolTitle`,t.bold(`subagent`))} ${t.fg(`accent`,`→ `+i)}`,right:t.fg(`dim`,a.join(` · `))}];if(n.expanded!==!0){let e=r[0];if(e!==void 0){c.push({left:` ${t.fg(`dim`,`│ `+e)}`});let n=r.length-1;n>0&&c.push({left:` ${t.fg(`dim`,` … 还有 `+n+` 行(ctrl+e 展开)`)}`})}}else{let i=e=>t.fg(`dim`,e.padEnd(8)),a=[];if(o===void 0&&!s&&n.sessionModel!==void 0&&a.push([`model`,`inherit → `+U($e(n.sessionModel))]),typeof e.label==`string`){let t=Lr(U(e.label));t.length>0&&a.push([`label`,t])}if(typeof e.why==`string`){let t=Lr(U(e.why));t.length>0&&a.push([`why`,t])}for(let[e,t]of a)c.push({left:` ${Nr}${i(e)}${t}`});let l=r[0]??`(empty)`;c.push({left:` ${Cr}${i(`task`)}${l}${r.length>1?` (`+String(r.length)+` 行)`:``}`});let u=r.slice(1,13),d=` `;for(let e of u)c.push({left:`${d}${t.fg(`dim`,e)}`});let f=r.length-1-u.length;f>0&&c.push({left:`${d}${t.fg(`dim`,`… +`+String(f)+` 行(ctrl+e 收起)`)}`})}return kr(new Fr(c),{intervalMs:150,isPartial:n.isPartial??!1,theme:t,requestInvalidate:n.requestInvalidate??di,state:n.state??{}})}function di(){}function fi(e){let t=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0);return Lr(t?.text??``)||`failed`}function pi(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 mi={running:{text:()=>`running`,themeSlot:`muted`},ok:{text:e=>e.durationMs===void 0?`ok`:`ok ${Rr(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 hi(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=pi(e.name,e.args),l=mi[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 gi(e,t,n,r=!1,i=!1){let a=Hr(e.details,n),o=e=>a===void 0?e:{...e,right:a};if(t)return[o({left:` ${n.fg(`error`,`failed: ${fi(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(Gr(s))return Qr(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=Vr(s);return c===void 0?[o({left:` ${n.fg(`muted`,`done`)}`})]:[o({left:` ${n.fg(`dim`,`→ ${c}`)}`})]}function _i(e,t,n,r={}){let i=Ur(e.details),a=[...gi({...e,details:i},t,n,!1,r.isPartial===!0)];return i?.subCalls!==void 0&&a.push(...hi(i.subCalls,n)),new Fr(a)}function vi(e,t,n,r,i={}){let a=Ur(e.details);if(n){let t=[...gi({...e,details:a},!0,r)];a?.subCalls!==void 0&&t.push(...hi(a.subCalls,r));let n=U(e.content?.find(e=>e.type===`text`)?.text??fi(e));for(let e of n.split(`
|
|
40
|
+
`).slice(0,12))t.push({left:` ${r.fg(`error`,e)}`});return new Fr(t)}let o=[],s=t.code??t.script??``;if(s.length>0){let e=s.split(`
|
|
41
|
+
`).map(e=>G(e,120)),t=e.slice(0,3);o.push({label:`code`,lines:t,...e.length>t.length?{more:e.length-t.length}:{}})}if(a!==void 0&&a.surface===`workflow`&&a.phases.length>0){let e=a.phases.slice(0,8),t=a.phases.length-e.length,n=t>0?` …+${t} more phases`:``;o.push({label:`phases`,lines:[`${e.join(` → `)}${n}`]})}if(a!==void 0&&a.narrations.length>0){let e=a.narrations.slice(0,12);o.push({label:`log`,lines:e.map(e=>U(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=>U(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=>U(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=gi({...e,details:a},!1,r,l,i.isPartial===!0);c!==void 0&&u.push(...hi(c,r));for(let e=0;e<o.length;e+=1){let t=e===o.length-1;u.push(...Wr(o[e]??{label:``,lines:[]},t,r))}return new Fr(u)}function yi(e){return{renderCall(t,n,r){return li(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?vi(e,r?.args??{},r?.isError===!0,n,{isPartial:i}):_i(e,r?.isError===!0,n,{isPartial:i})}}}const bi=["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.`,``,gr,``,Xn,``,"Only the program's return value and its `console.log` output come back. This surface has no","helpers: `log` / `phase` / `parallel` / `pipeline` exist only in `ptc_workflow`.",``,"Image-bearing tool results inside the program (a `tools.read` on a PNG, say) are attached to you",`after the run, so never return image data as the completion value — that only spends your context`,`on base64.`].join(`
|
|
42
|
+
`),xi=x.Object({code:x.String({description:`The program: the body of an async TypeScript function.`}),description:x.String({description:`Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI).`}),timeoutMs:x.Optional(x.Number({description:`Elapsed deadline in milliseconds for the whole run, including tool calls. Omit it (or pass 0) for the default of ${z.timeoutMs/1e3} s; anything above ${z.maxTimeoutMs/1e3} s is capped. The deadline bounds the whole run: if it expires, in-flight foreground dispatches spawned by the program are terminated with it.`}))});function Si(e={}){return R({name:`ptc_run_code`,label:`PTC Run Code`,exposure:e.exposure,description:bi,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:[...hr],parameters:xi,async execute(t,n,r,i,a){let o=vr(a),s=W(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=et(a),p=yr({surface:`run_code`,startedAt:c,onUpdate:i}),m;try{m=await qn({code:n.code,surface:`run_code`,cwd:o,bindings:Nn({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},...f===void 0?{}:{sessionModel:f},...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=>p.update(e)})}finally{p.cancel()}if(m.error!==void 0)throw xr(m);return Sr({outcome:m,surface:`run_code`,durationMs:Date.now()-c})},...yi(`run_code`)})}const Ci=[`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.",``,gr,``,Xn,``,`Image-bearing tool results inside the script are attached to you after the run — never return`,`image data as the script's value.`].join(`
|
|
43
|
+
`),wi=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 Ti(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=Ei(t[e],`args.${e}`,/* @__PURE__ */ new Set);if(n!==void 0)throw TypeError(`ptc_workflow args must be plain JSON: ${n}`)}}}function Ei(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=Ei(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=Ei(i[e],`${n}.${e}`,r);if(t!==void 0)return t}return}finally{r.delete(i)}}function Di(e,t){if(t===void 0||t.length===0)return[];let n=new Set(t),r=/* @__PURE__ */ new Set,i=[];for(let t of e.phases)n.has(t)||r.has(t)||(r.add(t),i.push(`phase "${t}" is not listed in meta.phases (declared: ${[...n].join(`, `)})`));return i}function Oi(e={}){return R({name:`ptc_workflow`,label:`PTC Workflow`,exposure:e.exposure,description:Ci,promptSnippet:`Run a structured TypeScript workflow with named phases, narration (log/phase) and structured concurrency (parallel/pipeline)`,promptGuidelines:[...hr],parameters:wi,async execute(t,n,r,i,a){Ti(n.args);let o=vr(a),s=W(e.getBindingSourceNames?.(),e.getOptInBindings?.()),c=Date.now(),l=e.getPool?.(),u=a.sessionManager?.getSessionDir?.(),d=e.getDispatchDeps?.(),f=et(a),p=yr({surface:`workflow`,startedAt:c,onUpdate:i}),m;try{m=await qn({code:n.script,surface:`workflow`,cwd:o,bindings:Nn({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},...f===void 0?{}:{sessionModel:f},...r===void 0?{}:{signal:r},...e.config===void 0?{}:{config:e.config},...l===void 0?{}:{pool:l},onSubCallChange:e=>p.update(e)})}finally{p.cancel()}if(m.error!==void 0)throw xr(m);let h=n.meta.phases?.map(e=>e.name);return Sr({outcome:m,surface:`workflow`,warnings:Di(m,h),durationMs:Date.now()-c})},...yi(`workflow`)})}var ki=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 Ai(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}var ji=class{#e;constructor(e){if(e.length===0)throw TypeError(`FileOutputStorage: baseDir is required`);this.#e=e}async readOutput(e){try{return await me(this.#t(e),`utf8`)}catch(e){if(Ai(e))return null;throw e}}async writeOutput(e,t){let n=M(this.#e,`tasks`,e);await pe(n,{recursive:!0}),await ve(M(n,`output.log`),t,`utf8`)}outputRef(e){return this.#t(e)}#t(e){return M(this.#e,`tasks`,e,`output.log`)}};function Mi(e,t){return er(e,`pi-ptc-task-output-`,t===void 0?{}:{fullText:t})}function Ni(e){return e===!0?"why suppressed\n└─ you passed a `why` and this session's `whyEnabled` switch is off, so the child's prompt carried no <pi-ptc-why> block. The child was never told your reason — it was not ignoring it. The value itself is not recorded anywhere.":``}const Pi={running:`accent`,stopping:`warning`,succeeded:`success`,failed:`error`,lost:`dim`,canceled:`muted`},Fi={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=>Ii(e,t))}};function Ii(e,t){let{left:n,right:r}=e;if(r===void 0)return I(n,t,`…`);let i=L(r);if(i>=t)return I(r,t,`…`);let a=I(n,Math.max(0,t-i-1),`…`),o=Math.max(1,t-i-L(a));return a+` `.repeat(o)+r}function Li(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Ri(e){return Li((U(e).split(`
|
|
44
|
+
`).find(e=>e.trim().length>0)??``).trim(),120)}function zi(e){if(typeof e!=`string`||e.length===0)return;let t=Ri(e);return t.length===0?void 0:t}function Bi(e){return typeof e==`object`&&e?e:{}}function Vi(e){return e===`running`||e===`stopping`}function Hi(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 Ui(e,t){if(Vi(e.status))return Hi(t-e.createdAt);if(e.durationMs!==void 0)return Hi(e.durationMs);if(e.finishedAt!==void 0)return Hi(e.finishedAt-e.createdAt)}function Wi(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 Gi(){}function Ki(e,t,n){return new q([{left:`└─ ${n.fg(`toolTitle`,n.bold(e))}${t.length>0?` ${t}`:``}`}])}function qi(e,t,n){let r=Bi(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 Ki(`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 Ki(`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=${U(r.reason)}`:``;return Ki(`PTC task stop`,e===void 0?n.fg(`muted`,`(unknown task)`):`${n.fg(`accent`,e)}${n.fg(`dim`,t)}`,n)}}}function Ji(e,t,n,r){let i=Pi[e.status]??`muted`,a=n.fg(i,Fi[e.status]??`?`),o=Li(U(e.label),48),s=[`${a} ${n.fg(`text`,o)}`,n.fg(`dim`,U(e.agentName))],c=Ui(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 Yi(e){if(e.status===`failed`||e.status===`lost`)return zi(e.errorMessage)}function Xi(e,t){let n=Bi(e),r=Array.isArray(n.tasks)?n.tasks:[];if(r.length===0)return Wi(new q([{left:` ${t.theme.fg(`muted`,`(no background tasks)`)}`}]),{isLive:!1,state:t.state,requestInvalidate:t.requestInvalidate});let i=r.some(e=>Vi(e.status)),a=r.slice(0,32),o=r.length-a.length,s=[];return a.forEach((e,n)=>{s.push(Ji(e,n===a.length-1&&o===0,t.theme,t.now));let r=Yi(e);r!==void 0&&s.push({left:` ${t.theme.fg(`error`,`error: ${r}`)}`})}),o>0&&s.push({left:` └─ ${t.theme.fg(`dim`,`…+${o} more tasks`)}`}),Wi(new q(s),{isLive:t.partial&&i,state:t.state,requestInvalidate:t.requestInvalidate})}function Zi(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 Qi(e,t){return` ${t.fg(`dim`,`full output: `)}${t.fg(`accent`,e)}`}function $i(e,t){let n=Bi(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=Zi(i,a,t.theme),c=[],l=zi(n.errorMessage);if(l!==void 0&&c.push({left:` ${t.theme.fg(`error`,`error: ${l}`)}`}),r.length>0){let e=U(r).split(`
|
|
45
|
+
`),n=e.slice(0,6);n.forEach((e,n)=>{let r=t.theme.fg(`toolOutput`,Li(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:Qi(o,t.theme)})}else if(o!==void 0)c.push({left:Qi(o,t.theme),...s===void 0?{}:{right:s}});else{let e=l===void 0?`(no output yet)`:`(no output)`;c.push({left:` ${t.theme.fg(`muted`,e)}`,...s===void 0?{}:{right:s}})}return new q(c)}function ea(e,t){let n=Bi(e),r=n.task;if(typeof r!=`object`||!r)return new q([{left:` ${t.theme.fg(`muted`,`(no task)`)}`}]);let i=Pi[r.status]??`muted`,a=t.theme.fg(i,Fi[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`,U(r.id))}`,t.theme.fg(i,s)];return typeof r.stopReason==`string`&&r.stopReason.length>0&&c.push(t.theme.fg(`dim`,`reason=${U(r.stopReason)}`)),new q([{left:` ${c.join(` `)}`}])}function ta(e,t){let n=e.content?.find(e=>e.type===`text`&&(e.text??``).length>0),r=Ri(n?.text??``)||`failed`;return new q([{left:` ${t.fg(`error`,`failed: ${r}`)}`}])}function na(e,t,n){switch(e){case`task-list`:return Xi(t.details,n);case`task-output`:return $i(t.details,n);case`task-stop`:return ea(t.details,n)}}function ra(e){return{renderCall(t,n){return qi(e,t,n)},renderResult(t,n,r,i){return i?.isError===!0?ta(t,r):na(e,t,{theme:r,partial:n?.isPartial===!0||i?.isPartial===!0,requestInvalidate:i?.invalidate??Gi,state:i?.state??{},now:Date.now()})}}}const ia=[`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.`],aa=x.Union([x.Literal(`running`),x.Literal(`stopping`),x.Literal(`succeeded`),x.Literal(`failed`),x.Literal(`canceled`),x.Literal(`lost`)]),oa=x.Object({status:x.Optional(x.Array(aa,{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.`}))}),sa=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 ca(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 la(e){let t=[e.id,e.status,`${e.agentName} depth=${e.depth}`,U(e.label)];return e.outputBytes!==void 0&&t.push(`${e.outputBytes}B`),e.errorMessage!==void 0&&t.push(`error=${U(e.errorMessage)}`),t.join(` `)}function ua(e){return R({name:`ptc_task_list`,label:`PTC Task List`,description:[`List the background tasks this session has dispatched (from pi.dispatch({ background: true })).`,`Returns each task's id, status, agent, depth, label and output size, newest first.`,`Filter with status (e.g. ["running"]); limit caps the row count (default 100).`].join(`
|
|
46
|
+
`),promptSnippet:`List background tasks and their live status (id, status, agent, label, output size)`,promptGuidelines:[...ia],parameters:oa,outputSchema:sa,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=>la(e)).join(`
|
|
47
|
+
`),a={tasks:r.map(e=>ca(e)),count:r.length};return{content:[{type:`text`,text:i}],details:{tasks:r,count:r.length},structuredContent:a}},...ra(`task-list`)})}async function da(e,t,n){let r=await e.get(t);if(r===null)throw Error(`${n}: unknown taskId ${t}`);return r}function fa(e){return{input:e.input,output:e.output,cost:e.cost,turns:e.turns}}function pa(e){return`usage: input=${String(e.input)} output=${String(e.output)} cost=${String(e.cost)} turns=${String(e.turns)}`}function ma(e,t,n){let r=`<child-report channel="${e}">${t}`;return n===void 0?`${r}</child-report>`:`${r}\n${pa(n)}\n</child-report>`}function ha(e){let t=e.reportChannel;if(t===void 0)return;let n=e.usage===void 0?void 0:fa(e.usage);if(t===`none`)return ma(t,`the child produced no report; it did not comply with the report contract. What follows is its prose, unbacked by a report.`,n);if(t===`opted-out`)return ma(t,`this agent opts out of the report contract, so none was asked for; the prose below is the whole of what it produced, and nothing is missing.`,n);let r=e.report;if(r===void 0)return ma(t,`the record names channel ${t} but carries no report.`,n);let i=[`<child-report channel="${t}">`,`summary: ${r.summary}`],a=r.findings.slice(0,20),o=r.findings.length-a.length;i.push(`findings (${String(r.findings.length)}):`);for(let[e,t]of a.entries())i.push(` ${String(e+1)}. ${t.what} — evidence: ${t.evidence}`);return o>0&&i.push(` …+${String(o)} more findings not shown`),i.push(r.files_touched.length===0?`files_touched: (none)`:`files_touched: ${r.files_touched.join(`, `)}`),i.push(pa(r.usage)),i.push(`</child-report>`),i.join(`
|
|
48
|
+
`)}const ga=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.`}))}),_a=x.Object({task_id:x.String({description:`The background task id that was asked for.`}),status:x.String({description:`The task's status at read time (ADR-0022 §2's six states), so a polling script does not need a second ptc_task_list call.`}),error_message:x.Optional(x.String({description:"The record's raw reason for a `failed` or `lost` task (ADR-0022 §2 / issue #70) — the string the text block prints as `error=…` after sanitizing it for display, and the same field `ptc_task_list` projects as `error_message`. Absent unless the record carries an error: a running task has no failure yet, and a `succeeded` or `canceled` close records no reason of its own."})),output:x.String({description:`The page the model reads: the stored output's tail, ADR-0015-truncated.`}),output_bytes:x.Number({description:`Total bytes stored for the task, regardless of sinceBytes or ADR-0015 truncation.`}),output_preview:x.Optional(x.String({description:`The complete stored output; present only at or below the 2048-byte preview ceiling (ADR-0022 §7).`})),output_truncated:x.Boolean({description:"Whether ADR-0015 cut anything out of `output`."}),output_full_path:x.Optional(x.String({description:"A file holding the complete output; present only when `output_truncated` is true (ADR-0015 §2)."})),report_channel:x.Optional(x.String({description:"Which channel delivered the child's report: `tool`, `prompt-json`, or `none` when the child ignored the contract (ADR-0032). Absent until the task succeeds — a running or failed task carries no report claim at all."})),read_only_tier:x.Optional(x.String({description:"The read-only tier the dispatch resolved to: `strict` or `lenient` (ADR-0041). Absent when the dispatch asked for no tier. Present from spawn onwards, including for a task that later failed — a failed read-only child was still dispatched read-only."})),why_suppressed:x.Optional(x.Boolean({description:"`true` when you passed a `why` and this session's `whyEnabled` switch was off, so the child's prompt carried no <pi-ptc-why> block (ADR-0043). ABSENT means no `why` was passed — that is the distinction the key exists to make. The child was never told your reason; it did not ignore one. The dropped value is not stored."})),report:x.Optional(x.Object({summary:x.String({description:`The child's own one-line summary.`}),findings:x.Array(x.Object({what:x.String({description:`The claim the child makes.`}),evidence:x.String({description:`The evidence that claim rests on.`})}),{description:`One entry per claim the child made.`}),files_touched:x.Array(x.String(),{description:`Paths the child says it touched.`}),usage:x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Host-observed input tokens (never the child's claim).`}),output:x.Number({description:`Host-observed output tokens.`}),cost:x.Number({description:`Host-observed cost.`}),turns:x.Number({description:`Host-observed assistant turns.`})},{description:"The host's own count for this child, in the same four fields `report.usage` carries (ADR-0032, issue #199). ABSENT when no top-level count was recorded: a `running` / `stopping` task has not closed yet, a `lost` record was never observed closing, and a record written before the field existed carries none — a pre-change record that has a report still renders the report's own host-stamped numbers. Present on every close outcome including `failed` and `canceled`, and independent of `report_channel` — so a child that reported nothing still accounts for what it cost. The text block states the same four numbers on the `usage: …` line."}))});function va(e,t){return R({name:`ptc_task_output`,label:`PTC Task Output`,description:[`Read a background task's captured output.`,`A succeeded task also renders its child report (summary, findings, files touched, usage) ahead of the prose, and says which channel delivered it; a channel of "none" means the child ignored the report contract.`,`A failed or lost task also states the record's error message — the reason it did not succeed — ahead of the output, so an empty output.log is not mistaken for an infrastructure fault.`,`The text is tail-truncated to pi's ADR-0015 limits (50 KB / 2000 lines); when anything is cut, outputFullPath names a file with the complete output.`,`Pass sinceBytes to skip a prefix of the stored output when paging.`].join(`
|
|
49
|
+
`),promptSnippet:`Read a background task's output (tail-truncated, with the full-output file path)`,promptGuidelines:[...ia],parameters:ga,outputSchema:_a,async execute(n,r){let i=r.taskId,a=await da(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=Mi(c===0?o:l.subarray(c).toString(`utf8`),o),d=s<=2048?o:void 0,f=ha(a),p=a.usage===void 0?void 0:fa(a.usage),m={taskId:i,output:u.text,outputBytes:s,...a.errorMessage===void 0?{}:{errorMessage:a.errorMessage},...d===void 0?{}:{outputPreview:d},outputTruncated:u.truncated,...u.fullPath===void 0?{}:{outputFullPath:u.fullPath},...a.report===void 0?{}:{report:a.report},...a.reportChannel===void 0?{}:{reportChannel:a.reportChannel},...a.readOnlyTier===void 0?{}:{readOnlyTier:a.readOnlyTier},...a.whySuppressed===void 0?{}:{whySuppressed:a.whySuppressed}},h=m.output.length>0?m.output:a.status===`running`||a.status===`stopping`?`(no output yet; task ${i} is ${a.status})`:`(no output; task ${i} is ${a.status})`,g=a.errorMessage===void 0?void 0:`error=${U(a.errorMessage)}`,_=f===void 0&&p!==void 0?pa(p):void 0,v=at(a.observedProvider,a.observedModel),y=[f,g,_,v===void 0?void 0:`model: `+v].filter(e=>e!==void 0),b=y.length===0?void 0:y.join(`
|
|
50
|
+
`),x=b===void 0?h:`${b}\n${h}`,S=wr(a.readOnlyTier),C=S.length===0?x:`${S}\n${x}`,w=Ni(a.whySuppressed),T=w.length===0?C:`${w}\n${C}`,E={task_id:i,status:a.status,...a.errorMessage===void 0?{}:{error_message:a.errorMessage},output:u.text,output_bytes:s,...d===void 0?{}:{output_preview:d},output_truncated:u.truncated,...u.fullPath===void 0?{}:{output_full_path:u.fullPath},...a.reportChannel===void 0?{}:{report_channel:a.reportChannel},...a.readOnlyTier===void 0?{}:{read_only_tier:a.readOnlyTier},...a.whySuppressed===void 0?{}:{why_suppressed:a.whySuppressed},...a.report===void 0?{}:{report:a.report},...p===void 0?{}:{usage:p}};return{content:[{type:`text`,text:T}],details:m,structuredContent:E}},...ra(`task-output`)})}const ya=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".`}))}),ba=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 xa(e,t,n={}){if(t==null)throw TypeError(`createPtcTaskStopTool: lifecycle is required`);let r=n.clock??(()=>Date.now());return R({name:`ptc_task_stop`,label:`PTC Task Stop`,description:[`Ask a running background task to stop.`,`The task moves to "stopping"; the dispatcher sends the signal and records the terminal "canceled" state when the child exits.`,`The call is idempotent when the task is already stopping, and errors when the task is already terminal.`].join(`
|
|
51
|
+
`),promptSnippet:`Ask a background task to stop (dispatcher delivers the signal)`,promptGuidelines:[...ia],parameters:ya,outputSchema:ba,async execute(t,n){let i=n.taskId,a=await da(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=${U(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}},...ra(`task-stop`)})}var Sa=class{#e;#t=/* @__PURE__ */ new Map;constructor(e={}){this.#e=Re(e.config)}get(e){let t=this.#t.get(e);if(t!==void 0)return t;let n=Le(),r=new Rn({buildWorkerUrl:Vn,size:this.#e.poolSize,acquireTimeoutMs:this.#e.poolAcquireTimeoutMs,drainGraceMs:this.#e.drainGraceMs,workerOptions:Fn({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 Ca={warn:e=>{console.warn(`[pi-ptc.notifications] `+e)}};var wa=class{#e;#t;#n;#r;#i;constructor(e,t={}){this.#e=e,this.#t=t.now??Date.now,this.#n=t.logger??Ca,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 Ta={mkdir:(e,t)=>pe(e,t),readFile:(e,t)=>me(e,t),writeFile:(e,t,n)=>ve(e,t,n),appendFile:(e,t,n)=>fe(e,t,n),rename:(e,t)=>ge(e,t),unlink:e=>_e(e),readdir:e=>he(e)};function Ea(e){return typeof e==`object`&&!!e&&e.code===`ENOENT`}function Da(e){return e instanceof Error?e.message:String(e)}function Oa(e,t){return e.eventId<t.eventId?-1:+(e.eventId>t.eventId)}var ka=class{#e;#t;constructor(e,t={}){if(e.length===0)throw TypeError(`FileTaskStorage: baseDir is required`);this.#e=e,this.#t=t.fs??Ta}async loadTask(e){let t=await this.#r(this.#f(e));return t===null?null:ot(t)}async saveTask(e){F(e,`saveTask: record is required`),await this.#o(this.#f(e.id),e)}async deleteTask(e){let t=this.#f(e);if(!await this.#c(t))throw Error(`deleteTask: unknown taskId `+e);await this.#t.unlink(t)}async*listTasks(e){let t=this.#l();for(let n of(await this.#s(t)).sort()){if(!n.endsWith(`.json`))continue;let r=await this.#r(M(t,n));if(r===null)continue;let i=ot(r);(e?.status===void 0||i.status===e.status)&&(e?.label===void 0||i.label===e.label)&&(yield i)}}async loadSubscription(e,t){return await this.#r(this.#p(e,t))}async saveSubscription(e){F(e,`saveSubscription: sub is required`),await this.#o(this.#p(e.subscriberId,e.taskId),e)}async appendEvents(e,t){if(t.length===0){if((await this.#n(e)).length===0)throw Error(`appendEvents: unknown subscriptionId `+e);return}let n=/* @__PURE__ */ new Map;for(let e of t){let t=n.get(e.taskId);t===void 0?n.set(e.taskId,[e]):t.push(e)}let r;for(let t of n.keys())if(await this.loadSubscription(e,t)===null){r=t;break}if(r!==void 0)throw(await this.#n(e)).length===0?Error(`appendEvents: unknown subscriptionId `+e):Error(`appendEvents: no subscription for subscriber `+e+` on task `+r);await this.#t.mkdir(this.#d(),{recursive:!0});for(let[t,r]of n){let n=(r.every((e,t)=>t===0||Oa(r[t-1],e)<=0)?r:[...r].sort(Oa)).map(e=>JSON.stringify(e)).join(`
|
|
52
52
|
`)+`
|
|
53
|
-
`;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(
|
|
54
|
-
`)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+
|
|
55
|
-
`);return`${`<bg-task-notifications batch-id="${
|
|
56
|
-
`)}function
|
|
57
|
-
`,` `).replaceAll(`\r`,` `)}function
|
|
53
|
+
`;await this.#t.appendFile(this.#m(e,t),n,{encoding:`utf8`})}}async*loadEvents(e,t){let n=await this.#n(e);if(n.length===0)throw Error(`loadEvents: unknown subscriptionId `+e);let r=[];for(let t of n)r.push(...await this.#a(this.#m(e,t.taskId)));r.sort(Oa);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(M(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(Ea(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+`: `+Da(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(Ea(e))return[];throw e}let n=[];for(let r of t.split(`
|
|
54
|
+
`)){let t=r.trim();if(t.length===0)continue;let i;try{i=JSON.parse(t)}catch(t){throw Error(`FileTaskStorage: corrupt event JSON in `+e+`: `+Da(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(j(e),{recursive:!0});let n=e+`.tmp-`+oe();await this.#t.writeFile(n,JSON.stringify(t,null,2),{encoding:`utf8`}),await this.#t.rename(n,e)}async#s(e){try{return await this.#t.readdir(e)}catch(e){if(Ea(e))return[];throw e}}async#c(e){try{return await this.#t.readFile(e,{encoding:`utf8`}),!0}catch(e){if(Ea(e))return!1;throw e}}#l(){return M(this.#e,`tasks`)}#u(){return M(this.#e,`subscriptions`)}#d(){return M(this.#e,`events`)}#f(e){return M(this.#l(),e+`.json`)}#p(e,t){return M(this.#u(),e+`-`+t+`.json`)}#m(e,t){return M(this.#d(),e+`-`+t+`.jsonl`)}};function Aa(e,t){return new ka(e,t)}const ja=/* @__PURE__ */ new Set([`succeeded`,`failed`,`canceled`,`lost`]),Ma=/* @__PURE__ */ new Set([`running`,`stopping`]),Na=2**53-1,Pa={info:()=>void 0,warn:e=>{console.warn(`[pi-ptc.background] `+e)}};function J(e){return e instanceof Error?e.message:String(e)}function Fa(e){return e===void 0||e.length===0?`<in-memory>`:e}function Ia(e){let t=e.spawnSource.callerId;return t.length>0?t:e.id}var La=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()}},Ra=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)}},za=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)}},Ba=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]}},Va=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??Pa,this.#r=e.owner??{pid:process.pid,bootMs:this.clock()},this.#i=e.isPidAlive??Ye,this.#t=e.createStorage??(e=>e===void 0||e.length===0?new lt:Aa(e)),this.#n=e.createOutputStorage??(e=>e===void 0||e.length===0?new ki:new ji(e));let t=(e.createInitialStorage??(()=>new lt))(),n=Qe(t,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),r=new wa(t,{now:this.clock,logger:this.#e});this.registry=new La(n),this.outputStorage=new Ra(new ki),this.pipeline=new za(r),this.lifecycle=new Ba((e.createLifecycle??(()=>new Pe({logger:this.#e})))()),this.slots=new dt(e.concurrency??z.dispatchConcurrency),this.dispatchDeps={taskRegistry:this.registry,lifecycle:this.lifecycle,slots:this.slots,outputStorage:this.outputStorage,clock:this.clock,logger:this.#e,...e.whyEnabled===void 0?{}:{whyEnabled:e.whyEnabled}},this.registry.onTransition(this.#o)}#o=(e,t)=>{this.#a||ja.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 `+Fa(e)+` is unavailable: `+J(n),t),[]}let i=Qe(n,{clock:this.clock,logger:this.#e,owner:this.#r,isPidAlive:this.#i}),a=new wa(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:Na})}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:Na})}catch(e){this.#e.warn(`shutdown: could not list tasks: `+J(e)),t=[]}let n=[];for(let r of t)if(Ma.has(r.status)&&Je(r,this.#r))try{let t=await this.registry.transition({kind:`reconcile-lost`,taskId:r.id,reason:e},{clock:this.clock,callerId:Ia(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=Ot(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 Ha(e={}){return new Va(e)}const Ua=/* @__PURE__ */ new Set([`succeeded`,`failed`,`lost`]);function Wa(e){return Ua.has(e.status)}function Ga(e,t){if(e.length===0)return``;let n=e.map(Ja).join(`
|
|
55
|
+
`);return`${`<bg-task-notifications batch-id="${Y(t.batchId)}" delivered-at-ms="${t.deliveredAtMs}">`}\n${n}\n</bg-task-notifications>`}function Ka(e,t=102400){let n=[],r=[],i=0,a=t-Xa;for(let t of e){let e=Ya(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 qa(e){let t=Array.from(e);return t.length<=1024?e:t.slice(0,1023).join(``)+`…`}function Ja(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.errorMessage!==void 0&&o.push(` <error-message>${Y(qa(n.errorMessage))}</error-message>`),n.reportChannel!==void 0&&o.push(` <report-channel>${Y(n.reportChannel)}</report-channel>`),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(`
|
|
56
|
+
`)}function Y(e){return e.replaceAll(`&`,`&`).replaceAll(`<`,`<`).replaceAll(`"`,`"`).replaceAll(` `,`	`).replaceAll(`
|
|
57
|
+
`,` `).replaceAll(`\r`,` `)}function Ya(e){return Buffer.byteLength(Ja(e),`utf8`)}const Xa=Buffer.byteLength(`<bg-task-notifications batch-id="${`0`.repeat(26)}" delivered-at-ms="${`9`.repeat(13)}">\n\n</bg-task-notifications>`,`utf8`),Za=[`ptc_run_code`,`ptc_workflow`],Qa=[`read`,`bash`,`edit`,`write`],$a=`ptc-mode`,eo=`ptc-mode`,to=`ptc.json`,no=`builtins-only`;function ro(){return{enabled:!1,base:void 0,ourLoadout:void 0}}function io(e){let t=M(e,to),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 ao(e){let t=M(e,to),n;try{n=T(t,`utf8`)}catch{return{whyEnabled:!0,source:`default`}}let r;try{r=JSON.parse(n)}catch{return{whyEnabled:!0,source:`default`}}if(typeof r!=`object`||!r||Array.isArray(r))return{whyEnabled:!0,source:`default`};let i=r.whyEnabled;return i===void 0?{whyEnabled:!0,source:`default`}:typeof i==`boolean`?{whyEnabled:i,source:`file`}:{whyEnabled:!0,source:`invalid`,error:`${t}: "whyEnabled" must be a boolean, received ${typeof i}`}}function oo(e){let t=M(e,to),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:Tn(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(re).join(`/`)}function so(e){return e===`~`?O():e.startsWith(`~/`)?M(O(),e.slice(2)):e.startsWith(`file://`)?ue(e):e}function co(e){return Z(so(e.startsWith(`./`)||e.startsWith(`.\\`)?e.slice(2):e))}function lo(e,t,n){let r=Z(N(n,e)),i=ne(e),a=Z(e);return t.some(e=>{let t=Z(so(e));return ye(r,t)||ye(i,t)||ye(a,t)})}function uo(e,t,n){if(t.length===0)return!1;let r=Z(N(n,e)),i=Z(e);return t.some(e=>{let t=co(e);return t===r||t===i})}function fo(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 po(e,t){if(!Array.isArray(e))return;let n;for(let{sign:r,target:i}of fo(e)){let e=r!==`-`&&r!==`!`;(r===`+`||r===`-`?uo(X,[i],t):lo(X,[i],t))&&(n=e?`enabled`:`disabled`)}return n}function mo(e,t){if(!Array.isArray(e))return;let n=fo(e),r=e=>n.filter(t=>t.sign===e).map(e=>e.target),i=r(`!`),a=r(`+`),o=r(`-`),s;return lo(X,i,t)&&(s=`disabled`),uo(X,a,t)&&(s=`enabled`),uo(X,o,t)&&(s=`disabled`),s}function ho(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 go(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 _o(e,t,n,r={project:process.cwd(),user:process.cwd()}){let i=e.slice(1);if(ho(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=po(a,r.project);if(o!==void 0)return{switch:o,source:`project`};let s=n?.extensions,c=mo(s,r.user);return c===void 0?{switch:`absent`,source:`default`}:{switch:c,source:`user`}}function vo(e,t,n=process.argv){let r=go(M(t,`.pi`,`settings.json`)),i=go(M(e,`settings.json`)),a=_o(n,r.value,i.value,{project:M(t,`.pi`),user:e}),o=r.error??i.error;return o===void 0?a:{...a,source:`invalid`,error:o}}function yo(e){return{activation:e.includes(`codemode`)?`active`:`inactive`,source:`loadout`}}function bo(e,t,n){return No(yo(n),Mo(e,t))}const xo=[`codemode`,`deferred`,`direct`,`hidden`],So={"codemode-deferred":`codemode`},Co=/^[A-Za-z0-9_-]+$/;function wo(e){return typeof e==`string`?So[e]??e:e}function To(e){return typeof e==`string`&&xo.includes(e)}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Eo(e){return Q(e)&&Object.values(e).every(e=>typeof e==`string`)}function Do(e){return URL.canParse(e)?/^https?:$/.test(new URL(e).protocol):!1}function Oo(e,t){if(!Co.test(e)||!Q(t))return;let n=wo(t.exposure),r=Q(t.toolExposure)?Object.fromEntries(Object.entries(t.toolExposure).map(([e,t])=>[e,wo(t)])):t.toolExposure;if(n!==void 0&&!To(n)||r!==void 0&&(!Q(r)||!Object.values(r).every(e=>To(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!Do(t.url)||t.headers!==void 0&&!Eo(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&&!Eo(t.env)||t.cwd!==void 0&&typeof t.cwd!=`string`?void 0:i}function ko(e,t){e.error=e.error===void 0?t:`${e.error}; ${t}`}function Ao(e,t,n,r,i){if(t===void 0){n!==void 0&&ko(i,n);return}let a;try{a=JSON.parse(t)}catch(t){ko(i,`${e} is not valid JSON (${t instanceof Error?t.message:String(t)})`);return}if(!Q(a)||a.mcpServers!==void 0&&!Q(a.mcpServers)){ko(i,`${e} must contain a JSON object with an "mcpServers" object`);return}typeof a.autoEnableCodemode==`boolean`?i.autoEnableCodemode=a.autoEnableCodemode:a.autoEnableCodemode!==void 0&&ko(i,`${e}: autoEnableCodemode must be a boolean`);for(let[e,t]of Object.entries(a.mcpServers??{})){let n=Oo(e,t);if(n===void 0||r===`project`&&Q(t)&&`url`in t&&t.auth)continue;let a=`mcp__${e.replace(/-/g,`_`)}`;[...i.servers.entries()].some(([t,n])=>t!==e&&n.namespace===a)||i.servers.set(e,{namespace:a,server:n})}}function jo(e,t){let n={autoEnableCodemode:void 0,servers:/* @__PURE__ */ new Map,error:void 0};Ao(e.path,e.raw,e.readError,`global`,n),Ao(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 Mo(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 jo(n(M(e,`mcp.json`)),n(M(t,`.pi`,`mcp.json`)))}function No(e,t){let n=t.error===void 0?e:{...e,mcpError:t.error};return e.activation===`active`||!t.autoEnablesCodemode?n:{...e,activation:`active`,source:`mcp`,...t.error===void 0?{}:{mcpError:t.error}}}function Po(e,t,n){return!e.present||t===`disabled`||n!==`active`?`full`:`subagents`}function Fo(e=process.argv){let t=e[1];if(t===void 0||t===``)return{present:!1,how:`no-entry`};let n;try{n=E(t)}catch{return{present:!1,how:`unresolvable-entry`}}let r=j(n);for(let e of Io){let t=M(r,...e);try{if(D(t).isDirectory())return{present:!0,how:`found`}}catch{}}return{present:!1,how:`not-found`}}const Io=[[`..`,`extensions`,`codemode`],[`..`,`..`,`extensions`,`codemode`],[`extensions`,`codemode`]];function Lo(e,t,n,r,i,a=process.cwd()){let o=n??Fo(),s=r??vo(e,a),c=i??bo(e,a,t);return{surfaceMode:Po(o,s.switch,c.activation),codemode:o,codemodeSwitch:s,codemodeActivation:c}}function Ro(e){let t=M(e,to),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 zo(e){return[...new Set(e)]}function Bo(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 Vo(e,t){let n=e=>Za.includes(e);if(t===`all-but-ptc`)return zo(e.filter(n));let r=new Set(B);return zo(e.filter(e=>n(e)||!r.has(e)))}function Ho(e){let{mode:t,defaultMode:n,active:r,manual:i}=e;return t===`tui`?!n&&!i?{enter:!1,reason:`config-off`}:Za.some(e=>r.includes(e))?!i&&Qa.filter(e=>!r.includes(e)).length>0?{enter:!1,reason:`restricted-session`}:{enter:!0,base:zo(r),loadout:Vo(r,e.hide??`builtins-only`)}:{enter:!1,reason:`tools-unavailable`}:{enter:!1,reason:`not-tui`}}function Uo(e,t){return e.enabled&&e.base!==void 0?e.base:t}function Wo(e,t){return!e.enabled||e.ourLoadout===void 0?!1:!Bo(e.ourLoadout,t)}function Go(e,t){let n=t.length>0&&t.every(e=>Za.includes(e));return e?.enabled===!0&&n&&e.base!==void 0?{base:e.base,restoreFirst:!0}:{base:t,restoreFirst:!1}}function Ko(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(`
|
|
58
58
|
`);return[`[PTC MODE ACTIVE]`,`This session runs in PTC mode. `+n,``,`Work by writing one TypeScript program per task and running it:`,` - ptc_run_code for a plain program (its return value and console.log come back to you)`,` - ptc_workflow when the task has named phases and you want narration (log / phase /`,` parallel / pipeline are available there)`,``,`The program body is an async function. Available inside it: ${r.join(`, `)}, plus the`,'parallel binding `tools["pi.dispatch"](args)` — always bound, and its dot name needs string',"indexing (`tools.pi.dispatch` does not exist). The run's actual bound names are on the","`ptcBindings` global, so a program never has to guess what is bound this run.",i.length>0?`Examples:\n${i}`:``,``,`Batch a task's steps into ONE program instead of issuing many tool calls — gathering`,`intermediate output yourself and returning only what matters is the point of this mode.`,`Image-bearing tool results inside a program are attached to you after the run — never return`,`base64 image data as your program's value.`,`If the PTC surfaces cannot express what you need, say so and the user can run /ptc off.`].filter(e=>e.length>0).join(`
|
|
59
|
-
`)}const
|
|
60
|
-
`),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:
|
|
59
|
+
`)}const qo=[`read`,`bash`],Jo=`Use the read tool to load a skill's file when the task matches its description.`,Yo=`Use tools.read({ path }) inside a ptc_run_code program to load a skill's file when the task matches its description.`;function Xo(e){return!qo.some(t=>e.includes(t))}function Zo(e,t=v){let n=t([...e],`read`).trim();return n.length===0?``:n.includes(Jo)?n.replace(Jo,Yo):`${Yo}\n\n${n}`}const Qo=x.Object({task_id:x.Optional(x.String({description:`Id of the background task to poll with ptc_task_output. Present ONLY for a background call; absent once the call has already finished.`})),status:x.String({description:`"background" when this call returned a handle to poll, otherwise the dispatcher's own outcome status ("fulfilled").`}),report_channel:x.String({description:'Which channel delivered the child report: "prompt-json" (a fenced JSON block on the child\'s final message), "tool" (the child called the report tool), "none" (no report arrived — either the child did not comply with the contract, or this is a background handle that has not finished), or "opted-out" (the agent\'s frontmatter set `childReport: false`, so it was never asked). ALWAYS present, so an absent `report` key is never ambiguous — "none" and "opted-out" are different claims about the child.'}),exit_code:x.Optional(x.Number({description:`The child's exit code. Present ONLY for a call that already finished.`})),read_only_tier:x.Optional(x.String({description:`The read-only tier the dispatch resolved to: "strict" or "lenient" (ADR-0041). Absent when no tier was asked for, so an absent key means "no tier" rather than "tier unknown".`})),why_suppressed:x.Optional(x.Boolean({description:"`true` when you passed a `why` and this session's `whyEnabled` switch was off, so the child's prompt carried no <pi-ptc-why> block (ADR-0043). ABSENT means no `why` was passed — that is the distinction the key exists to make. The child was never told your reason; it did not ignore one. A background call returns a handle and does not carry this key; read it from `ptc_task_output` instead."})),report:x.Optional(x.Object({summary:x.String({description:`One line, in the child's own words, of what it concluded.`}),findings:x.Array(x.Object({what:x.String({description:`The claim this finding makes.`}),evidence:x.String({description:`The independent thing that supports the claim.`})})),files_touched:x.Array(x.String({description:`A path the child created or modified.`})),usage:x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})})})),usage:x.Optional(x.Object({input:x.Number({description:`Input tokens, counted by the host.`}),output:x.Number({description:`Output tokens, counted by the host.`}),cost:x.Number({description:`Total cost, counted by the host.`}),turns:x.Number({description:`Assistant turns, counted by the host.`})},{description:"The host's own count for this child: the same four fields `report.usage` carries, projected from the `DispatchResult.usage` accumulator (ADR-0032, issue #199). ABSENT for a background handle, which has measured nothing yet, and for a child that emitted no usage block. Present on every settled call REGARDLESS of `report_channel`, so a child that reported nothing still accounts for what it cost — the text render states the same four numbers on its `usage` row."}))});function $o(e){let t=e.taskId;return typeof t==`string`?t:void 0}function es(e){let t=e.errorMessage??`the child failed without an error message`,n=[e.started?`child ran`:`harness declined to start`,`exit=`+String(e.exitCode),`turns=`+String(e.usage?.turns??0),`reportChannel=`+e.reportChannel],r=at(e.observedProvider,e.observedModel);r!==void 0&&n.push(`model=`+r);let i=t+` (`+n.join(`, `)+`)`;return i.length<=800?i:`…`+i.slice(-799)}function ts(e){return R({name:`ptc_subagent`,label:`PTC Subagent`,description:["Start a fresh pi agent as a child process: it gets its own context and tools, and it cannot see or change this session except through what it returns. Omit `model` and the child inherits this session's current model (when this pi exposes one; otherwise it falls back to pi's configured default); pass `model`, or let its agent definition pin one, to override that. Use it for work that would otherwise flood this context: a survey, a second opinion, or a task that can run while you do something else.","`agent` is optional — omit it and the child is a fresh generalist pi, with pi's own system prompt and pi's full toolset. Name one to narrow the child instead: an agent is a markdown file in ~/.pi/agent/agents/ for your machine, or <project>/.pi/agents/ for one project, and naming one can restrict the child's tools, pin its model, or append a role. A name with no definition behind it is refused; the refusal lists what IS registered and how to write one.",Yt({cwd:e.cwd,agentScope:e.agentRosterScope??`both`,...e.homeDir===void 0?{}:{homeDir:e.homeDir}})].join(`
|
|
60
|
+
`),promptSnippet:`Start a fresh pi agent as a child process (foreground or background)`,promptGuidelines:[`Prefer one subagent over many tool calls when the work is a question with an answer rather than a fact you can look up, or when the raw output would be larger than the answer.`],parameters:On,outputSchema:Qo,async execute(t,n,r,i,a){let o=et(a),s=await Sn(n,{callId:0,cwd:n.cwd??e.cwd,depth:e.depth,maxDispatchDepth:e.maxDispatchDepth,...e.parentTaskId===void 0?{}:{parentTaskId:e.parentTaskId},...o===void 0?{}:{sessionModel:o}},e.getDispatchDeps?.()??{}),c=$o(s),l=c===void 0?{taskId:void 0,status:s.status,exitCode:s.exitCode}:{taskId:c,status:`background`,exitCode:void 0};if(c!==void 0){let e=_t(n.readOnly),t={task_id:c,status:l.status,report_channel:`none`,...e===void 0?{}:{read_only_tier:e}};return{content:[{type:`text`,text:[`Started background task `+c,wr(e)].filter(e=>e.length>0).join(`
|
|
61
61
|
|
|
62
|
-
`)}],details:
|
|
62
|
+
`)}],details:l,structuredContent:t}}if(s.status===`rejected`)throw Error(`ptc_subagent refused the call: `+es(s));let u=s.report,d=s.readOnlyTier===void 0?{}:{read_only_tier:s.readOnlyTier},f=s.whySuppressed===void 0?{}:{why_suppressed:s.whySuppressed},p=s.usage===void 0?{}:{usage:{input:s.usage.input,output:s.usage.output,cost:s.usage.cost,turns:s.usage.turns}},m=l.exitCode===void 0?{status:l.status,report_channel:s.reportChannel,...d,...f,...p}:u===void 0?{status:l.status,exit_code:l.exitCode,report_channel:s.reportChannel,...d,...f,...p}:{status:l.status,exit_code:l.exitCode,report_channel:s.reportChannel,report:u,...d,...f,...p},h=ci(u,s.reportChannel,s.usage),g=wr(s.readOnlyTier),_=Ni(s.whySuppressed),v=at(s.observedProvider,s.observedModel);return{content:[{type:`text`,text:[g,_,h,v===void 0?``:`model: `+v,s.text].filter(e=>e.length>0).join(`
|
|
63
63
|
|
|
64
|
-
`)}],details:
|
|
65
|
-
`);function
|
|
66
|
-
`)}function Xo(e,t={}){let n=Ka(),r,i=!1,a=new da,o=()=>Mo(n,e.getActiveTools()),s=Ya(y()),c=s.optInBindings,l=()=>c,u=Ja(y()),d=tr(),f=nr(),p=t.backgroundRuntime??ja({concurrency:Re({}).dispatchConcurrency,whyEnabled:u.whyEnabled}),m=!1,h=e=>{console.warn(`[pi-ptc.background] `+e)},g=t=>{if(t.length!==0){if(m){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},_=async e=>{let{items:t,acks:n}=await p.drainNotifications(e),r=t.filter(e=>Na(e.record));for(let e of Fa(r))g(Pa(e,{batchId:Ee(),deliveredAtMs:p.clock()}));await p.acknowledgeNotifications(n)},v=async()=>{let e=await p.registry.query({limit:2**53-1}),t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}return[...t]},b=async()=>{for(let e of await v())await _(e)},x=async e=>{let t=/* @__PURE__ */ new Set;for(let n of e){let e=n.spawnSource.callerId;e.length>0&&t.add(e)}for(let e of t)await _(e)};p.pipeline.onIdleWake(e=>{_(e).catch(e=>{h(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})});function S(t){if(t.surfaceMode===`full`||t.surfaceMode===`subagents`){let n=t.surfaceMode===`full`?`direct`:`codemode`;e.registerTool(di({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`run_code`),depth:d,exposure:n,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps})),e.registerTool(_i({getBindingSourceNames:o,getOptInBindings:l,getPool:()=>a.get(`workflow`),depth:d,exposure:n,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps}))}t.surfaceMode===`subagents`&&e.registerTool(Uo({cwd:process.cwd(),depth:d,maxDispatchDepth:z.maxDispatchDepth,...f===void 0?{}:{parentTaskId:f},getDispatchDeps:()=>p.dispatchDeps})),e.registerTool($i(p.registry)),e.registerTool(sa(p.registry,p.outputStorage)),e.registerTool(ua(p.registry,p.lifecycle,{clock:p.clock})),e.registerTool(qo(d>0))}let C=!1,w=t=>{C||r.codemodeActivation.activation===`inactive`&&e.getActiveTools().includes(`codemode`)&&(C=!0,t.ui.notify(`pi-ptc-subagents: pi's codemode is active in this session, but nothing this package reads predicted it — no tool list names it and no readable mcp.json auto-enables it — so the surface defaulted to full, and your model is being offered two orchestration tools. pi activates codemode at runtime in ways no settings file records (its MCP extension is one). Run pi with codemode active (-t codemode, or add it to defaultTools) to get the subagents surface instead.`,`warning`))};e.on(`turn_start`,async(e,t)=>{m=!0,w(t)}),e.on(`agent_settled`,async()=>{m=!1;try{await b()}catch(e){h(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=a;a=new da,await e.drain()});let T=e=>{let t=[];n.enabled&&t.push(e.ui.theme.fg(`accent`,`PTC`)),e.ui.setStatus(Ua,t.length>0?t.join(` `):void 0)},E=(t,r,a,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),i=!0,e.appendEntry(Ha,{enabled:!0,base:[...t]}),T(a),a.ui.notify(o,`info`)},D=(t,r)=>{let a=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,i=!1,a!==void 0&&e.setActiveTools([...a]),e.appendEntry(r.customType,{enabled:!1}),T(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},ee=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`why`||i.startsWith(`why `))return N(i.slice(4),r);if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}D(r,{announce:!0,customType:Ha});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${rr(n.base,c).join(`, `)||`(none)`}`:`PTC mode is OFF — run /ptc on to enter it.`,`info`);return}if(n.enabled){r.ui.notify(`PTC mode is already on.`,`info`);return}let a=jo({mode:r.mode,defaultMode:!0,active:e.getActiveTools(),manual:!0,hide:Jo});if(!a.enter){r.ui.notify(a.reason===`tools-unavailable`?`Cannot enter PTC mode: ptc_run_code / ptc_workflow are not active in this session.`:`Cannot enter PTC mode in this run mode.`,`warning`);return}E(a.base,a.loadout,r,Yo(a.base,Jo,c))}}),e.on(`session_start`,async(n,i)=>{r=Eo(y(),e.getActiveTools(),t.codemode,t.codemodeSwitch,t.codemodeActivation),S(r),m=!1;let a=await p.bindSession(i.sessionManager?.getSessionDir?.(),e=>i.ui.notify(e,`warning`));try{await x(a)}catch(e){h(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let o=qa(y());o.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${o.error}`,`warning`),u.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${u.error}. That key was ignored rather than acted on, so it cannot have switched the dispatch \`why\` block off — \`/ptc why\` is what decides that, and \`/ptc why\` on its own reports the value in force and where it came from.`,`warning`),s.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${s.error}. No opt-in binding was granted, so the PTC surface stays narrowed. Opt-in bindings: ${fn.join(`, `)}.`,`warning`);let l=Do(y());l!==void 0&&i.ui.notify(`pi-ptc-subagents: `+l.path+` still has a "surfaceMode" key (`+JSON.stringify(l.value)+"), and it is no longer read: the surface is detected from what pi is, and no key pins it. To keep this package out of your sessions entirely, turn it off in pi -- run `pi config` and disable this package's extensions there (its `extensions` entry set to [] stops pi loading it at all). To silence this notice, delete the key.",`warning`);let d=r.codemode;d.present||i.ui.notify(`pi-ptc-subagents: the codemode probe reported `+d.how+`, so the surface is full. That is the safe direction, not an error.`,`info`),r.codemodeSwitch?.error!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.codemodeActivation?.mcpError!==void 0&&i.ui.notify(`pi-ptc-subagents: ${r.codemodeActivation.mcpError}`,`warning`);{let t=e.getAllTools().some(e=>e.name===`codemode`);!d.present&&t&&i.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+d.how+`), so the surface defaulted to full, and your model is being offered two orchestration tools. Enable codemode for real (-t codemode) to get the subagents surface instead.`,`warning`),d.present&&!t&&i.ui.notify(`pi-ptc-subagents: the codemode probe found pi's codemode on disk, but this session does not register it (--no-extensions), so the surface is `+JSON.stringify(r.surfaceMode)+(r.surfaceMode===`subagents`?` with no orchestrator: ptc_run_code and ptc_workflow are reachable only from codemode, and this session has none. Launch with codemode active (pi -t codemode), or turn this package off with pi config.`:`.`),`warning`)}if(r.surfaceMode===`subagents`&&!e.getActiveTools().includes(`codemode`)){let t=e.getActiveTools();t.includes(`ptc_run_code`)||t.includes(`ptc_workflow`)||i.ui.notify(`pi-ptc-subagents: the detected surface is subagents, but codemode is not active in this session, so there is no orchestration tool. Add codemode to your pi tool list (the --tools flag or the default tools setting), or turn this package off with pi config.`,`warning`)}w(i);let f=ee(i),{base:g,restoreFirst:_}=Po(f,e.getActiveTools());_&&e.setActiveTools([...g]);let v=jo({mode:i.mode,defaultMode:o.defaultMode,active:g,manual:!1,hide:Jo}),b=f?.enabled??v.enter;if(j(i),v.enter&&b){E(g,v.loadout,i,Yo(g,Jo,c));return}T(i),!v.enter&&v.reason!==`not-tui`&&f===void 0&&v.reason===`restricted-session`&&i.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{m=!1;try{await p.shutdown(`session_ended_while_running`)}catch(e){h(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let O=!1,k=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){O&&=(delete e.sections.skills,!1);return}let r=Bo(e.skills);r.length!==0&&(e.sections.skills=r,O=!0)};e.on(`before_agent_start`,async(t,r)=>{let a=t.systemPromptOptions;if(k(a,zo(e.getActiveTools())),n.enabled){if(No(n,e.getActiveTools())){D(r,{announce:!1,customType:Ha}),k(a,zo(e.getActiveTools())),r.ui.notify(`PTC mode off — another extension changed the active tool set.`,`warning`);return}if(i)return i=!1,{message:{customType:`ptc-mode-briefing`,content:Fo(rr(n.base,c),Jo),display:!1}}}});let A;function j(e){let t=te(e);t!==void 0&&(A=t.enabled,p.dispatchDeps.whyEnabled=t.enabled)}function te(e){let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-why`)continue;let r=n.data?.enabled;if(typeof r==`boolean`)return{enabled:r}}}function M(e,t){return[`The dispatch \`why\` block is ${e?`ON`:`OFF`}`,t===`session`?`(set by this session)`:`(set by ptc.json)`,e?`-- a dispatched child receives your reason. Run /ptc why off to stop handing it over.`:`-- a dispatched child does not receive your reason. Run /ptc why on to hand it over.`].join(` `)}function N(t,n){let r=t.trim().toLowerCase(),i=A??u.whyEnabled,a=A===void 0?`config`:`session`;if(r===``){n.ui.notify(M(i,a),`info`);return}if(r!==`on`&&r!==`off`){n.ui.notify(`/ptc why takes "on" or "off", or nothing at all to report the current value -- not "${t.trim()}". Nothing changed.`,`warning`);return}let o=r===`on`;if(i===o){n.ui.notify(M(o,a),`info`);return}A=o,p.dispatchDeps.whyEnabled=o,e.appendEntry(Zo,{enabled:o}),n.ui.notify(M(o,`session`),`info`)}}const Zo=`ptc-why`;export{V as BUILTIN_BINDING_NAMES,hn as DEFAULT_BINDING_NAMES,z as DEFAULT_CONFIG,Ga as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,Un as MAX_LINE_CHARS,Va as MODE_REQUIRED_TOOL_NAMES,fn as OPT_IN_BINDING_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,Wa as PTC_MODE_CONFIG_FILE,Ha as PTC_MODE_ENTRY_TYPE,Ua as PTC_MODE_STATUS_KEY,Ba as PTC_MODE_TOOL_NAMES,Ro as PTC_SKILL_LOAD_INSTRUCTION,Zo as PTC_WHY_ENTRY_TYPE,Io as SKILL_READING_TOOL_NAMES,da as TurnPools,Ie as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,En as WorkerPool,Mo as bindingSource,Fo as buildModeInstruction,Bo as buildPtcSkillsSection,Sn as createBuiltinBindings,Le as createWorkerEnv,jo as decideModeEntry,Xo as default,No as detectExternalLoadoutChange,Eo as detectSurfaceMode,Co as detectedSurfaceMode,ze as effectiveTimeoutMs,Ka as initialModeState,pn as isOptInBindingName,Ao as modeLoadout,wo as probeCodemodePresence,oo as readCodemodeSwitch,qa as readDefaultModeConfig,Do as readLegacySurfaceKey,Ya as readOptInBindingsConfig,Ja as readWhyEnabledConfig,er as renderModelValue,Po as resolveBaseOnStart,so as resolveCodemodeActivation,ao as resolveCodemodeSwitch,Re as resolveConfig,mn as resolveOptInBindingNames,Fn as runPtcProgram,ko as sameToolSet,G as sanitizeText,zo as skillsSectionDropped,Gn as stripAnsi};
|
|
64
|
+
`)}],details:l,structuredContent:m}},renderCall(t,n,r){let i=r?.state,a;return i===void 0?a=e.getSessionModel?.():(i.inheritedSessionModel===void 0&&(i.inheritedSessionModel=e.getSessionModel?.()??null),a=i.inheritedSessionModel??void 0),ui(t,n,{...r?.invalidate===void 0?{}:{requestInvalidate:r.invalidate},...r?.isPartial===void 0?{}:{isPartial:r.isPartial},...r?.state===void 0?{}:{state:r.state},...r?.expanded===!0?{expanded:!0}:{},...a===void 0?{}:{sessionModel:a}})}})}function ns(e){return e.length<=200?e:`…`+e.slice(-199)}const rs=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.`}))}),is=[`Hand the host a child report: what you did in this run, in the shape it can read without parsing English.`,`Call it once, at the end. The exact shape is stated in your instructions, which also tell you what to do if this tool is unavailable to you.`,`Evidence is the point of a finding. Put in the independent thing you read, ran or checked — the claim restated is not evidence, and a finding with none is worse than no finding.`,`files_touched lists only paths you actually created or modified; leave it empty rather than guessing.`,`Your prose answer is kept alongside this report and is never replaced by it, so still answer in words.`,`Do not report usage or token counts — those are measured by the host, and anything you send under them is discarded.`].join(`
|
|
65
|
+
`);function as(e){return R({name:Fe,label:`Child Report`,description:is,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:rs,outputSchema:rs,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`,ns(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 $=no;function os(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: ${W(e,n).join(`, `)||`(none)`}.`,`Run /ptc off to restore the normal tool set.`].join(`
|
|
66
|
+
`)}function ss(e,t={}){let n=ro(),r,i,a=!1,o=new Sa,s=()=>Uo(n,e.getActiveTools()),c=oo(y()),l=c.optInBindings,u=()=>l,d=ao(y()),f=pr(),p=mr(),m=t.backgroundRuntime??Ha({concurrency:Re({}).dispatchConcurrency,whyEnabled:d.whyEnabled}),h=!1,g=e=>{console.warn(`[pi-ptc.background] `+e)},_=t=>{if(t.length!==0){if(h){e.sendMessage({customType:`bg-task-notification`,content:t,display:!1},{deliverAs:`steer`});return}e.sendUserMessage(t)}},v=async e=>{let{items:t,acks:n}=await m.drainNotifications(e),r=t.filter(e=>Wa(e.record));for(let e of Ka(r))_(Ga(e,{batchId:Ee(),deliveredAtMs:m.clock()}));await m.acknowledgeNotifications(n)},b=async()=>{let e=await m.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]},x=async()=>{for(let e of await b())await v(e)},S=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 v(e)};m.pipeline.onIdleWake(e=>{v(e).catch(e=>{g(`notification delivery failed: `+(e instanceof Error?e.message:String(e)))})});function C(t){if(t.surfaceMode===`full`||t.surfaceMode===`subagents`){let n=t.surfaceMode===`full`?`direct`:`codemode`;e.registerTool(Si({getBindingSourceNames:s,getOptInBindings:u,getPool:()=>o.get(`run_code`),depth:f,exposure:n,...p===void 0?{}:{parentTaskId:p},getDispatchDeps:()=>m.dispatchDeps})),e.registerTool(Oi({getBindingSourceNames:s,getOptInBindings:u,getPool:()=>o.get(`workflow`),depth:f,exposure:n,...p===void 0?{}:{parentTaskId:p},getDispatchDeps:()=>m.dispatchDeps}))}t.surfaceMode===`subagents`&&e.registerTool(ts({cwd:process.cwd(),depth:f,maxDispatchDepth:z.maxDispatchDepth,...p===void 0?{}:{parentTaskId:p},getDispatchDeps:()=>m.dispatchDeps,getSessionModel:()=>i})),e.registerTool(ua(m.registry)),e.registerTool(va(m.registry,m.outputStorage)),e.registerTool(xa(m.registry,m.lifecycle,{clock:m.clock})),e.registerTool(as(f>0))}let w=!1,T=t=>{w||r.codemodeActivation.activation===`inactive`&&e.getActiveTools().includes(`codemode`)&&(w=!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)=>{i=et(t),h=!0,T(t)}),e.on(`agent_settled`,async()=>{h=!1;try{await x()}catch(e){g(`agent_settled delivery failed: `+(e instanceof Error?e.message:String(e)))}}),e.on(`turn_end`,async()=>{let e=o;o=new Sa,await e.drain()});let E=e=>{let t=[];n.enabled&&t.push(e.ui.theme.fg(`accent`,`PTC`)),e.ui.setStatus(eo,t.length>0?t.join(` `):void 0)},D=(t,r,i,o)=>{n.enabled=!0,n.base=t,n.ourLoadout=r,e.setActiveTools([...r]),a=!0,e.appendEntry($a,{enabled:!0,base:[...t]}),E(i),i.ui.notify(o,`info`)},ee=(t,r)=>{let i=n.base;n.enabled=!1,n.base=void 0,n.ourLoadout=void 0,a=!1,i!==void 0&&e.setActiveTools([...i]),e.appendEntry(r.customType,{enabled:!1}),E(t),r.announce&&t.ui.notify(`PTC mode off — built-in tools are directly callable again.`,`info`)},te=e=>{let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-mode`)continue;let r=n.data,i=Array.isArray(r?.base)?r.base.filter(e=>typeof e==`string`):void 0;return{enabled:r?.enabled===!0,...i===void 0?{}:{base:i}}}};e.registerCommand(`ptc`,{description:`Show or toggle PTC mode`,handler:async(t,r)=>{let i=t.trim().toLowerCase();if(i===`why`||i.startsWith(`why `))return N(i.slice(4),r);if(i===`off`){if(!n.enabled){r.ui.notify(`PTC mode is already off.`,`info`);return}ee(r,{announce:!0,customType:$a});return}if(i!==`on`){r.ui.notify(n.enabled?`PTC mode is ON — run /ptc off to restore built-in tools.\nBindings: ${W(n.base,l).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=Ho({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}D(a.base,a.loadout,r,os(a.base,$,l))}}),e.on(`session_start`,async(n,a)=>{i=et(a),r=Lo(y(),e.getActiveTools(),t.codemode,t.codemodeSwitch,t.codemodeActivation),C(r),h=!1;let o=await m.bindSession(a.sessionManager?.getSessionDir?.(),e=>a.ui.notify(e,`warning`));try{await S(o)}catch(e){g(`startup reconcile delivery failed: `+(e instanceof Error?e.message:String(e)))}let s=io(y());s.error!==void 0&&a.ui.notify(`pi-ptc-subagents: ${s.error}`,`warning`),d.error!==void 0&&a.ui.notify(`pi-ptc-subagents: ${d.error}. That key was ignored rather than acted on, so it cannot have switched the dispatch \`why\` block off — \`/ptc why\` is what decides that, and \`/ptc why\` on its own reports the value in force and where it came from.`,`warning`),c.error!==void 0&&a.ui.notify(`pi-ptc-subagents: ${c.error}. No opt-in binding was granted, so the PTC surface stays narrowed. Opt-in bindings: ${Cn.join(`, `)}.`,`warning`);let u=Ro(y());u!==void 0&&a.ui.notify(`pi-ptc-subagents: `+u.path+` still has a "surfaceMode" key (`+JSON.stringify(u.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 f=r.codemode;f.present||a.ui.notify(`pi-ptc-subagents: the codemode probe reported `+f.how+`, so the surface is full. That is the safe direction, not an error.`,`info`),r.codemodeSwitch?.error!==void 0&&a.ui.notify(`pi-ptc-subagents: ${r.codemodeSwitch.error}`,`warning`),r.codemodeActivation?.mcpError!==void 0&&a.ui.notify(`pi-ptc-subagents: ${r.codemodeActivation.mcpError}`,`warning`);{let t=e.getAllTools().some(e=>e.name===`codemode`);!f.present&&t&&a.ui.notify(`pi-ptc-subagents: this session registers pi's codemode, but the probe did not find it (`+f.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`),f.present&&!t&&a.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`)||a.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`)}T(a);let p=te(a),{base:_,restoreFirst:v}=Go(p,e.getActiveTools());v&&e.setActiveTools([..._]);let b=Ho({mode:a.mode,defaultMode:s.defaultMode,active:_,manual:!1,hide:$}),x=p?.enabled??b.enter;if(ne(a),b.enter&&x){D(_,b.loadout,a,os(_,$,l));return}E(a),!b.enter&&b.reason!==`not-tui`&&p===void 0&&b.reason===`restricted-session`&&a.ui.notify(`PTC mode skipped: this session was launched with an explicit tool restriction.`,`info`)}),e.on(`session_shutdown`,async()=>{h=!1;try{await m.shutdown(`session_ended_while_running`)}catch(e){g(`session shutdown failed: `+(e instanceof Error?e.message:String(e)))}});let O=!1,k=(e,t)=>{if(e===void 0)return;if(!n.enabled||!t){O&&=(delete e.sections.skills,!1);return}let r=Zo(e.skills);r.length!==0&&(e.sections.skills=r,O=!0)};e.on(`before_agent_start`,async(t,r)=>{let i=t.systemPromptOptions;if(k(i,Xo(e.getActiveTools())),n.enabled){if(Wo(n,e.getActiveTools())){ee(r,{announce:!1,customType:$a}),k(i,Xo(e.getActiveTools())),r.ui.notify(`PTC mode off — another extension changed the active tool set.`,`warning`);return}if(a)return a=!1,{message:{customType:`ptc-mode-briefing`,content:Ko(W(n.base,l),$),display:!1}}}});let A;function ne(e){let t=j(e);t!==void 0&&(A=t.enabled,m.dispatchDeps.whyEnabled=t.enabled)}function j(e){let t=e.sessionManager.getEntries();for(let e=t.length-1;e>=0;--e){let n=t[e];if(n?.type!==`custom`||n.customType!==`ptc-why`)continue;let r=n.data?.enabled;if(typeof r==`boolean`)return{enabled:r}}}function M(e,t){return[`The dispatch \`why\` block is ${e?`ON`:`OFF`}`,t===`session`?`(set by this session)`:`(set by ptc.json)`,e?`-- a dispatched child receives your reason. Run /ptc why off to stop handing it over.`:`-- a dispatched child does not receive your reason. Run /ptc why on to hand it over.`].join(` `)}function N(t,n){let r=t.trim().toLowerCase(),i=A??d.whyEnabled,a=A===void 0?`config`:`session`;if(r===``){n.ui.notify(M(i,a),`info`);return}if(r!==`on`&&r!==`off`){n.ui.notify(`/ptc why takes "on" or "off", or nothing at all to report the current value -- not "${t.trim()}". Nothing changed.`,`warning`);return}let o=r===`on`;if(i===o){n.ui.notify(M(o,a),`info`);return}A=o,m.dispatchDeps.whyEnabled=o,e.appendEntry(cs,{enabled:o}),n.ui.notify(M(o,`session`),`info`)}}const cs=`ptc-why`;export{B as BUILTIN_BINDING_NAMES,En as DEFAULT_BINDING_NAMES,z as DEFAULT_CONFIG,no as DEFAULT_HIDE_STRATEGY,o as HOST_FRAME_KIND,tr as MAX_LINE_CHARS,Qa as MODE_REQUIRED_TOOL_NAMES,Cn as OPT_IN_BINDING_NAMES,n as PTC_ERROR_KIND,i as PTC_LOG_LEVEL,to as PTC_MODE_CONFIG_FILE,$a as PTC_MODE_ENTRY_TYPE,eo as PTC_MODE_STATUS_KEY,Za as PTC_MODE_TOOL_NAMES,Yo as PTC_SKILL_LOAD_INSTRUCTION,cs as PTC_WHY_ENTRY_TYPE,qo as SKILL_READING_TOOL_NAMES,Sa as TurnPools,Ie as WORKER_ENV_ALLOW_LIST,t as WORKER_FRAME_KIND,Rn as WorkerPool,Uo as bindingSource,Ko as buildModeInstruction,Zo as buildPtcSkillsSection,Nn as createBuiltinBindings,Le as createWorkerEnv,Ho as decideModeEntry,ss as default,Wo as detectExternalLoadoutChange,Lo as detectSurfaceMode,Po as detectedSurfaceMode,ze as effectiveTimeoutMs,ro as initialModeState,wn as isOptInBindingName,Vo as modeLoadout,Fo as probeCodemodePresence,vo as readCodemodeSwitch,io as readDefaultModeConfig,Ro as readLegacySurfaceKey,oo as readOptInBindingsConfig,ao as readWhyEnabledConfig,fr as renderModelValue,Go as resolveBaseOnStart,yo as resolveCodemodeActivation,_o as resolveCodemodeSwitch,Re as resolveConfig,Tn as resolveOptInBindingNames,qn as runPtcProgram,Bo as sameToolSet,U as sanitizeText,Xo as skillsSectionDropped,rr as stripAnsi};
|
|
67
67
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-ptc-subagents",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.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",
|