zswarm 0.2.6 → 0.2.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zswarm",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "type": "module",
5
5
  "description": "Coordinate CLI agent crews in Zellij panes",
6
6
  "engines": {
@@ -23,8 +23,8 @@
23
23
  "skills"
24
24
  ],
25
25
  "dependencies": {
26
- "@zswarm/cli": "0.2.6",
27
- "@zswarm/mcp": "0.1.16"
26
+ "@zswarm/cli": "0.2.7",
27
+ "@zswarm/mcp": "0.1.17"
28
28
  },
29
29
  "publishConfig": {
30
30
  "access": "public"
@@ -2,8 +2,9 @@
2
2
 
3
3
  Verified live against **codex**, **cursor**, **pi**, **opencode**, and **gemini** (`agy`).
4
4
 
5
- - **Read** (`dump`, `tail`, `status`, `wait --for idle`) works on all five.
5
+ - **Read** (`dump`, `tail`, `status`, `wait --for idle`) works on all five verified harnesses.
6
6
  - **Send** lands on all five (`codex` auto-detects `submit=double-enter`, others `auto`). The `expect` guard works on all five.
7
+ - **OpenCode's** exit recipe is `/exit` and its ready markers are `Ask anything` / `ctrl+p commands` (verified live on a real pane). **Claude Code** carries a named `claude` profile (busy marker `esc to interrupt`, exit recipe `/exit`, ready marker `? for shortcuts`), defined from its documented UI; it was not verified live on the host that added it. Restart waits for the screen to settle when a profile declares no ready marker, and the other profiles restart with the Ctrl+C fallback.
7
8
  - **Replies can take > 60s.** Budget timeouts; a quiet pane is rarely a failed send.
8
9
  - **`wait --match` on a redrawing TUI is viewport-and-moment dependent.** Those apps
9
10
  own the alternate screen (no scrollback; `--full` is identical). Prefer
@@ -12,10 +13,10 @@ Verified live against **codex**, **cursor**, **pi**, **opencode**, and **gemini*
12
13
 
13
14
  Reaching zswarm from a harness is separate from driving one:
14
15
 
15
- - **4 of 5 have an MCP client** — they reach zswarm once session and interpreter
16
+ - **5 of 6 have an MCP client** — they reach zswarm once session and interpreter
16
17
  path are explicit in the server config.
17
18
  - **1 ships no MCP client** — use `@zswarm/cli`, or the generic MCP bridge at
18
19
  `packages/pi/extensions/zswarm-mcp.ts` (`ZSWARM_MCP_SERVERS`).
19
- - **Being a target needs no integration.** All five are drivable with
20
+ - **Being a target needs no integration.** All six are drivable with
20
21
  `send` / `dump` / `tail` / `wait` / `status`.
21
22
 
@@ -13,6 +13,7 @@ MCP: `zswarm({ op, ... })`. CLI: `zswarm <op>`. Same surface.
13
13
  | `keys` | `expect` is checked before any input. Key specs (`keys: ["Ctrl c"]`) or literal `chars` (+ `enter`) |
14
14
  | `interrupt` | `Esc`; `hard: true` sends `Ctrl c` |
15
15
  | `spawn` | New pane (`newTab: true` for a fresh tab) with `command`, `cwd`, `name`, `direction`, `floating`; `tab` = tab name; `worktree` isolates on a branch |
16
+ | `restart` | Restart the agent in its pane in place (same pane id, title, position) with an optional handoff; `to`, `handoffSelf`, `handoff` (inline), `command`, `force`, `timeoutMs`. See [restart](#restart) |
16
17
  | `close` | Close a pane |
17
18
  | `rename` | Retitle a pane (`to` + `name`) or a tab (`tab` + `name`) |
18
19
  | `focus` | Focus a pane; already-focused is a no-op success |
@@ -56,6 +57,38 @@ zswarm({ op: "send", to: "reviewer", body: "…", expect: "Add a follow-up" })
56
57
 
57
58
  Failure is `expect_missing` and nothing is written.
58
59
 
60
+ ## restart
61
+
62
+ Restart the agent already running in a pane, in place: the same pane id, title,
63
+ and position come back with a fresh harness process. Optional handoff first:
64
+ `--handoff-self` asks the running agent to write its handoff to a file and print
65
+ a marker, then waits (bounded) for it; `--handoff-file PATH` (`-` for stdin) reads
66
+ a handoff on the caller, like `--body-file` (MCP `handoff` is inline).
67
+
68
+ The steps are: exit via the harness profile's exit recipe (Claude Code / OpenCode
69
+ type `/exit`; other profiles fall back to Ctrl+C), then Ctrl+C twice if it did not
70
+ exit; wait until the pane's command has exited (Zellij reports the pane exited, a
71
+ command pane shows its re-run prompt, or a shell prompt returns); relaunch in the
72
+ same pane — a command pane gets ENTER at Zellij's re-run prompt, a shell pane gets
73
+ the profile's launch command or `--command`; wait for readiness — the harness ready
74
+ marker (OpenCode `Ask anything` / `ctrl+p commands`, Claude Code `? for shortcuts`),
75
+ or, for a harness with no declared marker, until the screen stops changing (two
76
+ identical dumps ~1s apart), then a short settle before input; and deliver the
77
+ handoff. A short handoff is pasted; a long one becomes a one-line pointer to the
78
+ file. If the send reports `not-delivered` (positive evidence nothing landed), the
79
+ handoff is resent once after readiness returns; any other non-true submission is
80
+ reported, never resent.
81
+
82
+ The result lists each step's outcome under `steps`. A failure names the failed
83
+ step in `error.message`, with the step in `error.details.step`. A pane that a
84
+ relay has leased is refused with `pane_leased` unless `--force`.
85
+
86
+ ```text
87
+ zswarm restart --to reviewer --handoff-self
88
+ zswarm restart --to terminal_9 --handoff-file handoff.md --timeout-ms 60000
89
+ zswarm({ op: "restart", to: "reviewer", handoff: "pick up the failing test", force: true })
90
+ ```
91
+
59
92
  ## Event bus
60
93
 
61
94
  `zswarm({ op: "bus", install: true })` once per Zellij session. After that
@@ -122,4 +122,7 @@ running and finished relays, `--leases` lists current pane leases,
122
122
  keep a remote crew running. A relay leases its target pane until it ends; a
123
123
  second relay (or `send --if-idle`) refuses a leased pane with `pane_leased`
124
124
  (`--queue` waits, `--force` shares the lease, a stale lease is taken over).
125
+ `relay --if-idle` applies `send --if-idle`'s busy check before the lease
126
+ (`pane_busy` when the harness shows work; `--queue` waits for the pane to
127
+ go idle as well as for the lease; `--force` skips the check).
125
128
  See docs/hosts.md in the zswarm repo.