pi-squire 0.2.0 → 0.2.2
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 +20 -1
- package/README.md +13 -3
- package/package.json +1 -1
- package/src/child.ts +25 -1
- package/src/index.ts +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,23 @@ follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.2.2] - 2026-10-02
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- The README links `CONTRIBUTING.md` on GitHub, since it is not in the npm
|
|
14
|
+
package and its relative link 404s on pi.dev.
|
|
15
|
+
|
|
16
|
+
## [0.2.1] - 2026-10-02
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- A delegate's task now arrives as a user prompt labelled `[delegate]` instead
|
|
21
|
+
of a `[mailbox]` message. Pi 1.0.0 started the injected message's turn
|
|
22
|
+
without the system prompt, so a fresh delegate saw no context files, skills
|
|
23
|
+
or role paragraph until after its first tool call, and could reject them as
|
|
24
|
+
an injection (earendil-works/pi#5581).
|
|
25
|
+
|
|
9
26
|
## [0.2.0] - 2026-10-02
|
|
10
27
|
|
|
11
28
|
### Breaking
|
|
@@ -69,6 +86,8 @@ author's dotfiles; the changes below are against that copy.
|
|
|
69
86
|
|
|
70
87
|
- The published file list includes `child.ts`, which `index.ts` imports.
|
|
71
88
|
|
|
72
|
-
[Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.2.
|
|
89
|
+
[Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.2.2...HEAD
|
|
90
|
+
[0.2.2]: https://github.com/gvanderclay/pi-squire/compare/v0.2.1...v0.2.2
|
|
91
|
+
[0.2.1]: https://github.com/gvanderclay/pi-squire/compare/v0.2.0...v0.2.1
|
|
73
92
|
[0.2.0]: https://github.com/gvanderclay/pi-squire/compare/v0.1.0...v0.2.0
|
|
74
93
|
[0.1.0]: https://github.com/gvanderclay/pi-squire/releases/tag/v0.1.0
|
package/README.md
CHANGED
|
@@ -364,8 +364,18 @@ provider's own README carries the contract.
|
|
|
364
364
|
recorded delegation's request is taken over. `pi-squire` sets `handled`, so
|
|
365
365
|
the provider injects nothing, and shows the parent the result message above.
|
|
366
366
|
The reply's request copies fill the quoted task and its `cur/` path is the
|
|
367
|
-
envelope it names. A reply to a request this session did not delegate
|
|
368
|
-
|
|
367
|
+
envelope it names. A reply to a request this session did not delegate is left
|
|
368
|
+
to the provider.
|
|
369
|
+
|
|
370
|
+
Inside a delegate, `pi-squire` also takes over the task: a `request` whose
|
|
371
|
+
`from` is the parent's address. It sets `handled` and sends the task as a user
|
|
372
|
+
prompt labelled `[delegate]`, so the run starts the way a typed prompt does.
|
|
373
|
+
Pi 1.0.0 starts a turn for an injected custom message without preparing the
|
|
374
|
+
system prompt, so a fresh delegate's first request would otherwise carry no
|
|
375
|
+
context files, skills or role paragraph
|
|
376
|
+
([earendil-works/pi#5581](https://github.com/earendil-works/pi/issues/5581)).
|
|
377
|
+
The provider still arms the automatic answer for a request a listener took
|
|
378
|
+
over. Every other message to the delegate is left to the provider. `pi-squire` reads `from` and requires
|
|
369
379
|
it to be the sender's address, which for a delegate is its session id; a reply
|
|
370
380
|
from any other sender is left to the provider, even when it answers a recorded
|
|
371
381
|
request. The provider's README carries the contract.
|
|
@@ -420,7 +430,7 @@ A `message:*` provider must:
|
|
|
420
430
|
|
|
421
431
|
## Contributing
|
|
422
432
|
|
|
423
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) to set up, run the tests and open a pull
|
|
433
|
+
See [CONTRIBUTING.md](https://github.com/gvanderclay/pi-squire/blob/main/CONTRIBUTING.md) to set up, run the tests and open a pull
|
|
424
434
|
request. Changes by release are in [CHANGELOG.md](CHANGELOG.md).
|
|
425
435
|
|
|
426
436
|
## License
|
package/package.json
CHANGED
package/src/child.ts
CHANGED
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
// taking over — typing here, or stopping a run — turns it off for the rest of
|
|
9
9
|
// the session, with a notice; `/auto-exit` turns it back on. Modelled on
|
|
10
10
|
// edxeth/pi-subagents' `auto-exit` (README "Child lifecycle", `cf6dbf4`).
|
|
11
|
+
//
|
|
12
|
+
// It also takes over the parent's task request on `message:inbound` and sends
|
|
13
|
+
// it as a user prompt. Pi 1.0.0 starts a custom-message turn without preparing
|
|
14
|
+
// the system prompt, so a fresh delegate's first request would carry no
|
|
15
|
+
// AGENTS.md, skills or role addendum (earendil-works/pi#5581). The provider
|
|
16
|
+
// still arms the automatic answer for a request a listener took over.
|
|
17
|
+
// ponytail: drop the takeover once #5581 lands and the minimum Pi has it.
|
|
11
18
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
12
19
|
|
|
13
20
|
/** The launch variable that carries the parent's resolved setting. */
|
|
@@ -19,7 +26,24 @@ const ON_NOTICE = "delegate: auto-exit is on; this delegate closes after its nex
|
|
|
19
26
|
|
|
20
27
|
type Message = { role?: string; stopReason?: unknown };
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
type Inbound = { envelope?: { from?: unknown; kind?: unknown; body?: unknown }; handled?: boolean };
|
|
30
|
+
|
|
31
|
+
export function registerChild(pi: ExtensionAPI, parent: string): void {
|
|
32
|
+
let current: ExtensionContext | undefined;
|
|
33
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
34
|
+
current = ctx;
|
|
35
|
+
});
|
|
36
|
+
pi.events.on("message:inbound", (data) => {
|
|
37
|
+
const payload = data as Inbound;
|
|
38
|
+
const envelope = payload?.envelope;
|
|
39
|
+
if (payload.handled === true || envelope?.kind !== "request" || envelope.from !== parent) return;
|
|
40
|
+
payload.handled = true;
|
|
41
|
+
const text = `[delegate] Your task, from the session that started you (${parent}). Your final message this turn goes back to it automatically.\n\n${String(envelope.body ?? "")}`;
|
|
42
|
+
Promise.resolve(pi.sendUserMessage(text, { deliverAs: "steer" })).catch((err) =>
|
|
43
|
+
current?.ui.notify(`delegate: could not start the task: ${(err as Error).message}`, "error"),
|
|
44
|
+
);
|
|
45
|
+
});
|
|
46
|
+
|
|
23
47
|
let armed = process.env[AUTO_EXIT_ENV] === "1";
|
|
24
48
|
/** Whether the run that just ended finished normally: not stopped, not failed. */
|
|
25
49
|
let completed = false;
|
package/src/index.ts
CHANGED
|
@@ -255,8 +255,9 @@ function toolDescription(agents: readonly Agent[]): string {
|
|
|
255
255
|
*/
|
|
256
256
|
export default function delegate(pi: ExtensionAPI, tmux: TmuxClient = createTmuxClient()): void {
|
|
257
257
|
// A delegate registers only its auto-exit side: `delegate` is one level deep (Q27).
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
const parentId = process.env[PARENT_ENV] ?? "";
|
|
259
|
+
if (parentId !== "") {
|
|
260
|
+
registerChild(pi, parentId);
|
|
260
261
|
return;
|
|
261
262
|
}
|
|
262
263
|
|