pi-squire 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,39 @@ follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.12.0] - 2026-10-26
10
+
11
+ ### Changed
12
+
13
+ - Delegates open in a companion tmux session, `<your session>-squire`, instead
14
+ of your own session, created on demand and removed by tmux with its last
15
+ window. pi-squire marks the session it creates (tmux session option
16
+ `@squire-companion`), so only a marked session counts as a companion: your
17
+ own session called `pi-squire` gets `pi-squire-squire`. Set
18
+ `"windowPlacement": "current"` in `<agent dir>/squire/settings.json` to open
19
+ them in your session as before; any other value refuses the launch.
20
+ The start message, `delegation_status` and the delegate card name the session,
21
+ and the `delegate` and `delegation_resume` results and the status details gain
22
+ an optional `windowSession`. `session:launch` is unchanged.
23
+ - tmux 3.2 or later is now required (it was 3.0); `/delegate`, `/delegate-resume`
24
+ and the tools refuse an older tmux with its version.
25
+
26
+ ## [0.11.0] - 2026-10-26
27
+
28
+ ### Added
29
+
30
+ - The `session:launch` payload gains a read-only `toolCallId`, the ID of the
31
+ `delegate` tool call that started the launch, so a listener can tie a
32
+ delegate's window to that call. It is `undefined` for a launch from the
33
+ `/delegate` command.
34
+ - `delegation_resume` and `/delegate-resume <id> [--model …] [--thinking …] [--auto-exit|--no-auto-exit] <task>` reopen an exited delegate's own session (`pi --session <path>`) in a new window with a follow-up task. The resume is recorded as a new delegation with `resumedFrom`; mail, replies and usage-limit marks use the delegation's session id, so records from before resuming read as before. A delegate whose working directory is gone, one still running, one whose window is open and an older delegation of a resumed chain are refused. `delegation_status` shows `resumed from` and `resumed as`, results and closed-without-a-result messages name `resumedFrom`, and the latter point to `delegation_resume`. The `delegate` tool's description mentions it, and `--session` joins the launch invariants listed for `session:launch`. A resume emits `session:launch`
35
+ too, with `toolCallId` set to the `delegation_resume` call, or `undefined`
36
+ from `/delegate-resume`; unlike a launch's, it comes before the task is sent,
37
+ because a resume mails the task only once its window is open (mail for a
38
+ window that never opened would otherwise reach the next resume as a second
39
+ task; a failed send kills the new window). A resumed delegation is never
40
+ reported closed without a result.
41
+
9
42
  ## [0.10.0] - 2026-10-24
10
43
 
11
44
  ### Added
@@ -458,7 +491,9 @@ author's dotfiles; the changes below are against that copy.
458
491
 
459
492
  - The published file list includes `child.ts`, which `index.ts` imports.
460
493
 
461
- [Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.10.0...HEAD
494
+ [Unreleased]: https://github.com/gvanderclay/pi-squire/compare/v0.12.0...HEAD
495
+ [0.12.0]: https://github.com/gvanderclay/pi-squire/compare/v0.11.0...v0.12.0
496
+ [0.11.0]: https://github.com/gvanderclay/pi-squire/compare/v0.10.0...v0.11.0
462
497
  [0.10.0]: https://github.com/gvanderclay/pi-squire/compare/v0.9.5...v0.10.0
463
498
  [0.9.5]: https://github.com/gvanderclay/pi-squire/compare/v0.9.4...v0.9.5
464
499
  [0.9.4]: https://github.com/gvanderclay/pi-squire/compare/v0.9.3...v0.9.4
package/README.md CHANGED
@@ -16,9 +16,11 @@ You need:
16
16
  options the parent guidance uses, and the extension APIs the package relies
17
17
  on. Pi supplies the peer dependencies `@earendil-works/pi-coding-agent` and
18
18
  `typebox`.
19
- - tmux 3.0 or later, with the Pi session running in a tmux pane. That is the
20
- first version with `new-window -e`. A window is opened in the pane's
21
- session, so a client attached elsewhere does not matter.
19
+ - tmux 3.2 or later, with the Pi session running in a tmux pane. That is the
20
+ first version with `new-session -e` and `display-popup`. Windows are placed
21
+ relative to the pane's session (see [Where delegate windows
22
+ open](#where-delegate-windows-open)), so a client attached elsewhere does
23
+ not matter.
22
24
  - A provider of `message:*`;
23
25
  [pi-session-mail](https://github.com/gvanderclay/pi-session-mail) is one
24
26
  example. Without a provider there is no way to send the task or get an
@@ -130,6 +132,39 @@ temporary folder, not as text on the command line.
130
132
  missing. In print mode (`pi -p`) Pi does not show the refusal notices, so
131
133
  the refusal is silent there.
132
134
 
135
+ ## Where delegate windows open
136
+
137
+ By default a delegate's window opens in a **companion session** named after
138
+ yours with `-squire` added: from the session `work`, delegates go to
139
+ `work-squire`. Your own session stays as it is, even when its name already
140
+ ends in `-squire`: a session called `pi-squire` gets `pi-squire-squire`.
141
+ pi-squire marks each companion session it creates with the tmux session
142
+ option `@squire-companion`; a parent that runs in a marked session uses it, so
143
+ a delegate that delegates does not make `work-squire-squire`.
144
+
145
+ - The session is created on demand, by the launch that needs it, and tmux
146
+ removes it with its last window, so it does not outlive its delegates.
147
+ - `detach-on-destroy` is set to `off` (and the mark set) on that session only: if you are
148
+ looking at it when its last delegate exits, tmux moves you to your most
149
+ recent other session instead of detaching you. Your sessions and tmux's
150
+ global options are never changed.
151
+ - The start message, the delegate card and the `delegate` and
152
+ `delegation_resume` results show the session the window opened in, as the
153
+ optional `windowSession`; they keep that name. `delegation_status` looks it
154
+ up each time, so it follows a window you move to another session, which is
155
+ still found, closed and resumed.
156
+
157
+ To open windows in your own session, as before, set `windowPlacement` in
158
+ `<agent dir>/squire/settings.json`, beside `worktreeRoot`:
159
+
160
+ ```json
161
+ { "windowPlacement": "current" }
162
+ ```
163
+
164
+ The values are `companion` (the default when the setting is absent) and
165
+ `current`. The file is read at each launch. Any other value refuses the launch
166
+ with an error naming the file, before the task is sent or a window opens.
167
+
133
168
  ## Working directory
134
169
 
135
170
  `--cwd <dir>` (the `delegate` tool's `cwd`) runs the delegate in an existing
@@ -428,7 +463,7 @@ agent's `auto-exit`.
428
463
 
429
464
  ## Tools
430
465
 
431
- The model gets three tools. They share the command's launch path and the
466
+ The model gets four tools. They share the command's launch path and the
432
467
  session's delegation records. None of them is registered inside a delegate.
433
468
 
434
469
  | Tool | Parameters | What it does |
@@ -436,6 +471,7 @@ session's delegation records. None of them is registered inside a delegate.
436
471
  | `delegate` | `agent`, `task`, optional `model`, `thinking`, `label`, `cwd` and `auto_exit` (boolean) | Validates the call the way the command does, starts the delegation without opening a dialog (except an unresolved [trust question](#project-trust) for `cwd`), and returns the delegation id at once without waiting for a result. |
437
472
  | `delegation_status` | optional `id` | Reports each delegation as running, done, closed or closed without a result, with the window, the delegate's session and the result envelope's path. |
438
473
  | `delegation_close` | `id` | Kills the window through tmux and records the close, so `delegation_status` reports it closed. |
474
+ | `delegation_resume` | `id`, `task`, optional `model`, `thinking` and `auto_exit` | Reopens an exited delegate's own session in a new window with a follow-up task, and returns the new delegation's id at once (see [Resuming a delegation](#resuming-a-delegation)). |
439
475
 
440
476
  The `delegate` tool's description lists the current roster, one line per agent:
441
477
  its name, description, default model and thinking, auto-exit when it is off,
@@ -778,6 +814,59 @@ session or offer to fork it rather than open it when the delegate ran in
778
814
  another directory or its file lives in another storage directory. The
779
815
  absolute path opens that file directly.
780
816
 
817
+ ## Resuming a delegation
818
+
819
+ An exited delegate can continue its own session with a follow-up task:
820
+
821
+ ```text
822
+ /delegate-resume <id> [--model <provider/id>] [--thinking <level>] [--auto-exit | --no-auto-exit] <task…>
823
+ ```
824
+
825
+ The model does the same with `delegation_resume` (`id` and `task`, optionally
826
+ `model`, `thinking` and `auto_exit`), which returns the `delegate` tool's result
827
+ plus `resumedFrom`. The command completes the ids that can still be resumed.
828
+
829
+ - The delegate's own session file is reopened with `pi --session <absolute path>`
830
+ and the recorded `--session-dir`, in a new window named like the first. The
831
+ delegate keeps everything it read and decided; Pi appends to the same file.
832
+ Opening it yourself is `pi --session <path>`, outside this tool.
833
+ - The resume is recorded as a **new delegation** with its own id and a
834
+ `resumedFrom` naming the old one. Its task goes to the old session's mail
835
+ address, and its result arrives as a `[delegate]` message that names
836
+ `resumed from <id>`. Status shows `resumed from <id>` on the new delegation and
837
+ `resumed as <id>` on the old one. A late reply to the old request still
838
+ settles the old delegation only, and a resumed delegation is never reported
839
+ closed without a result.
840
+ - Unlike a launch, the task is mailed after the window opens: the session's
841
+ inbox outlives a failed attempt, so a task sent for a window that never
842
+ opened would reach the next resume as a second task. The reopened delegate
843
+ receives it once its mailbox starts. If the send fails, the new window is
844
+ killed and nothing is recorded.
845
+ - A chain resumes from its newest delegation; resuming an older one is refused,
846
+ naming the newest.
847
+ - It is refused, before anything is sent or opened, unless: the delegation is a
848
+ started one (not a workspace attempt); it is not `running` (mail a running
849
+ delegate instead) and tmux can be asked; no window with its id and name still
850
+ runs a program (an exited one is killed first; a window that merely shares the
851
+ name is ignored); its session file is found and the working directory in the
852
+ file's header still exists; its agent is still in the roster; and no other
853
+ resume of it is under way. A delegate whose window was killed mid-turn can be
854
+ resumed.
855
+ - A removed working directory, a removed managed worktree included, makes a
856
+ delegation not resumable: Pi runs a reopened session in its stored directory.
857
+ The window opens in that directory, with project trust decided again for it as
858
+ for `cwd` (see [Project trust](#project-trust)); there is no `cwd` or
859
+ `worktree` for a resume, and no worktree is created.
860
+ - Without `model` it continues on the model the delegate finished on, moving to
861
+ its agent's fallbacks when that one is unavailable or marked (see
862
+ [Usage limits](#usage-limits)). An explicit `model` is used alone and refused
863
+ rather than substituted. `thinking` and `auto_exit` default to the
864
+ delegation's own. The agent's prompt, tools and extensions are those of the
865
+ roster now.
866
+ - `session:launch` is emitted as for any launch, with the same payload.
867
+ - Not detected: a Pi process you opened yourself on the same session outside
868
+ pi-squire's window. Close it before resuming.
869
+
781
870
  ## Hooks
782
871
 
783
872
  The `js` block below is the contract's worked example, and
@@ -788,8 +877,10 @@ that block.
788
877
 
789
878
  ### `session:launch`
790
879
 
791
- `pi-squire` provides this hook. It emits `{ args, env, agent, cwd }` after the
792
- task has been sent and just before it opens the delegate's window.
880
+ `pi-squire` provides this hook. It emits `{ args, env, agent, cwd, toolCallId }`
881
+ just before it opens the delegate's window: for a launch, after the task has
882
+ been sent; for a resume, before it is sent, since a resume mails the task once
883
+ the window is open (see [Resuming a delegation](#resuming-a-delegation)).
793
884
 
794
885
  | Field | Meaning |
795
886
  | --- | --- |
@@ -797,15 +888,17 @@ task has been sent and just before it opens the delegate's window.
797
888
  | `env` | the child's environment, as `KEY`/`value` pairs |
798
889
  | `agent` | the agent's name, as in `<agent dir>/squire/agents/<name>/AGENT.md`; read it, do not change it |
799
890
  | `cwd` | the directory the window opens in, the parent's or the resolved `--cwd`; read it, do not change it |
891
+ | `toolCallId` | the ID of the `delegate` or `delegation_resume` tool call that started the launch; absent when started from the `/delegate` or `/delegate-resume` command; read it, do not change it |
800
892
 
801
893
  Listeners may only append to `args` and add keys to `env`; there is no veto,
802
894
  and `pi-squire` passes both to tmux unchanged. Do all work synchronously: the
803
895
  emitter reads the payload the moment `emit` returns.
804
896
 
805
- `cwd`, the trust flag (`--approve` or `--no-approve`) and `--session-dir` are
806
- launch invariants that `pi-squire` chooses. The window opens in its own `cwd`,
897
+ `cwd`, the trust flag (`--approve` or `--no-approve`), `--session-dir` and the
898
+ session choice (`--session-id` for a new delegate, `--session` for a [resumed](#resuming-a-delegation)
899
+ one) are launch invariants that `pi-squire` chooses. The window opens in its own `cwd`,
807
900
  whatever a listener assigns to the payload. A listener must not add another
808
- trust flag, `--session-dir` or a working-directory change to `args`, since
901
+ trust flag, `--session-dir`, `--session` or `--session-id`, or a working-directory change to `args`, since
809
902
  that would launch a child whose trust or session storage the parent did not
810
903
  choose and cannot find; append only unrelated settings.
811
904
 
@@ -890,16 +983,17 @@ version and is listed under "Breaking" in [CHANGELOG.md](CHANGELOG.md).
890
983
 
891
984
  Other extensions may rely on:
892
985
 
893
- - the `session:launch` payload `{ args, env, agent, cwd }`, emitted
894
- synchronously after the task is sent and before the window opens, with
986
+ - the `session:launch` payload `{ args, env, agent, cwd, toolCallId }`, emitted
987
+ synchronously before the window opens (after the task is sent for a launch,
988
+ before it is sent for a resume), with
895
989
  `cwd`, the trust flag and `--session-dir` chosen by `pi-squire` (see
896
990
  [Hooks](#hooks));
897
991
  - the `message:send`, `message:inbound` and `message:scan` hooks, consumed as
898
992
  their sections document;
899
- - the `delegate`, `delegation_status` and `delegation_close` tool names,
993
+ - the `delegate`, `delegation_status`, `delegation_close` and `delegation_resume` tool names,
900
994
  parameters, the recorded `workspace` shape and the `workspaceSnapshot`
901
995
  shape in results and status;
902
- - the `/delegate` syntax and flags;
996
+ - the `/delegate` and `/delegate-resume` syntax and flags;
903
997
  - the `[delegate]` result text and the closed-without-a-result text;
904
998
  - `AGENT.md`'s frontmatter keys and its location,
905
999
  `<agent dir>/squire/agents/<name>/AGENT.md`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-squire",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
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",