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 +36 -1
- package/README.md +107 -13
- package/package.json +1 -1
- package/src/index.ts +231 -41
- package/src/render.ts +4 -3
- package/src/result-message.ts +120 -0
- package/src/result-sessions.ts +35 -3
- package/src/results.ts +37 -116
- package/src/resume.ts +472 -0
- package/src/tmux.ts +161 -37
- package/src/tracking-text.ts +41 -0
- package/src/tracking.ts +43 -51
- package/src/window-placement.ts +31 -0
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.
|
|
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.
|
|
20
|
-
first version with `new-
|
|
21
|
-
|
|
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
|
|
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 }`
|
|
792
|
-
|
|
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`)
|
|
806
|
-
|
|
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
|
|
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 `
|
|
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