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 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.0...HEAD
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, and
368
- every request, is left to the provider. `pi-squire` reads `from` and requires
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-squire",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Starts a delegate Pi session in a background tmux window, sends it the task over message:*, and shows the parent its result",
5
5
  "keywords": [
6
6
  "pi-package",
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
- export function registerChild(pi: ExtensionAPI): void {
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
- if ((process.env[PARENT_ENV] ?? "") !== "") {
259
- registerChild(pi);
258
+ const parentId = process.env[PARENT_ENV] ?? "";
259
+ if (parentId !== "") {
260
+ registerChild(pi, parentId);
260
261
  return;
261
262
  }
262
263