agentp 2.0.0 → 2.1.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/CONTRIBUTING.md CHANGED
@@ -6,7 +6,8 @@ agentp is a collection of three **zero-dependency** Node.js CLI tools that
6
6
  extend [OpenCode](https://opencode.ai) v2:
7
7
 
8
8
  - **`agentp`** — pipes prompt text into a running OpenCode session and streams the answer back to stdout.
9
- - **`ocmux`** — manages per-project TUI windows in tmux (session picker, project switcher, create/rename/delete/annotate sessions) on top of a single **user-managed** OpenCode server.
9
+ - **`ocmux`** — routes project sessions and optional user-placed dedicated/shared
10
+ TUI panes in tmux on top of user-managed OpenCode servers.
10
11
  - **`tgagentp`** — bridges a Telegram bot chat with OpenCode (multi-chat, multi-server, file sharing). *Experimental.*
11
12
 
12
13
  The project aims to stay **zero npm dependencies** — everything uses only the
@@ -42,12 +43,13 @@ npm install -g .
42
43
  agentp/
43
44
  ├── bin/
44
45
  │ ├── agentp — stdin-to-session pipe
45
- │ ├── ocmux — project/TUI window manager + interactive pickers
46
+ │ ├── ocmux — project/session router + interactive pickers
46
47
  │ └── tgagentp — Telegram bot bridge
47
48
  ├── lib/
48
49
  │ ├── opencode.js — OpenCode v2 HTTP/SSE client (shared by all three)
49
- │ ├── ocmux.js — tmux helpers (shared by ocmux + tgagentp)
50
+ │ ├── ocmux.js — registered-TUI routing helpers
50
51
  │ ├── project-state.js — `.ocmux.json` v2 schema + per-session reminders
52
+ │ ├── tui-registry.js — private runtime registry + tmux pane operations
51
53
  │ ├── tui-cmd.js — tmux send-keys passthrough (tgagentp)
52
54
  │ ├── file-share.js — telegram-shared directory + upload/download
53
55
  │ └── telegram-*.js — Telegram API + formatting helpers
@@ -72,8 +74,8 @@ agentp/
72
74
  ### Conventions
73
75
 
74
76
  - **HTTP:** use `lib/opencode.js` helpers — never raw `http.request`.
75
- - **tmux:** use `lib/ocmux.js` helpers (`_tmux` / exported wrappers) — never raw
76
- `spawnSync`.
77
+ - **tmux TUI registrations:** use `lib/tui-registry.js`; keep socket, pane,
78
+ token, and PID data out of `.ocmux.json`.
77
79
  - **State:** `.ocmux.json` I/O goes through `lib/project-state.js`
78
80
  (`readProjectState`, `writeProjectState`, `readAnnotations`, `writeAnnotation`,
79
81
  atomic writes). Never hand-roll reads/writes.
package/README.md CHANGED
@@ -8,7 +8,9 @@
8
8
  This package provides three CLI tools:
9
9
 
10
10
  - **`agentp`** — pipes prompt text into a running OpenCode server and streams the assistant final answer back to stdout
11
- - **`ocmux`** — manages project TUI windows in tmux on top of a single user-managed OpenCode server (session picker, project switcher, create/rename/delete/annotate sessions)
11
+ - **`ocmux`** — routes project sessions and optionally drives user-placed,
12
+ registered OpenCode TUI panes in tmux (session picker, project switcher,
13
+ create/rename/delete/annotate sessions)
12
14
  - **`tgagentp`** — bridges a Telegram bot chat with all running OpenCode servers (receives messages from Telegram, routes them to the active server, sends answers back). Supports slash commands for multi-server management, session switching, agent/model listing, including file sharing from the chat.
13
15
 
14
16
  It is designed for prompt-driven workflows where you want to do things like:
@@ -42,7 +44,7 @@ npm link
42
44
 
43
45
  - Node.js 18+
44
46
  - **OpenCode v2** (`opencode serve`) — the server is user-managed; these tools only check it is reachable and complain otherwise.
45
- - [tmux](https://github.com/tmux/tmux) when using `ocmux` (project TUI windows).
47
+ - [tmux](https://github.com/tmux/tmux) when using registered `ocmux` TUIs.
46
48
 
47
49
  ## Servers
48
50
 
@@ -214,7 +216,8 @@ The ticket is `agentp_ticket` followed by a JSON object with these fields:
214
216
  - `ctime` — creation timestamp (ISO 8601). Only used to compute `elapsed`.
215
217
  - `path` — path to the temp file holding the result.
216
218
  - `server` — OpenCode server URL used by the deferred job.
217
- - `sessionId` — OpenCode session ID used by the deferred job.
219
+ - `sessionId` — OpenCode session ID used by a normal deferred job.
220
+ - `sessionIds` — array of OpenCode session IDs used by a **broadcast** deferred job (replaces `sessionId`).
218
221
  - `elapsed` — seconds since `ctime`, included only when the ticket is re-printed (not on first print).
219
222
  - `defer` — the timeout requested at submission, included only when it was > 0.
220
223
  - `cancelled` — always present (defaults to `false`). Set it to `true` and pipe the ticket back to cancel the running job (see below).
@@ -229,6 +232,13 @@ printf "Refactor the auth module" | agentp --defer --onlineTicket
229
232
 
230
233
  Both formats are accepted when piping a ticket back to `agentp --defer`.
231
234
 
235
+ When `ocmux` has a broadcast selection, `agentp --defer` creates a ticket with
236
+ `sessionIds` and sends the prompt to every selected session. On retrieval,
237
+ `--qa` includes the original prompt plus one `💬 <name> [<id>]` answer section
238
+ per session. Individual failures/incomplete sessions are listed with an error
239
+ and timestamp. Broadcast tickets do **not** support queued follow-up text (a
240
+ follow-up is inherently ambiguous across multiple sessions).
241
+
232
242
  You can also append follow-up text after a not-yet-ready ticket to queue more
233
243
  input into the original running task, similar to typing into the OpenCode TUI
234
244
  while the agent is busy:
@@ -315,59 +325,151 @@ Useful to grab recent answers without sending a new prompt.
315
325
 
316
326
  ## ocmux
317
327
 
318
- Manage **project TUI windows** in tmux on top of a single user-managed OpenCode
319
- server. A project is a directory holding a `.ocmux.json` state file recording
320
- the target session; an `Opencode` tmux session holds one window per project
321
- (TUI only, pane 0).
328
+ Manage project/session routing on top of a user-managed OpenCode server. A
329
+ project is a directory holding a `.ocmux.json` state file recording its target
330
+ session. TUIs are optional: `ocmux tui` can register any tmux pane as a
331
+ project-dedicated display, while `ocmux tui --shared` registers one fallback
332
+ display that follows session switches from every project.
322
333
 
323
334
  ```bash
324
- ocmux [-l] [<subcommand>] [<directory>]
335
+ ocmux [-l] [--all-projects] [<subcommand>] [<directory>]
325
336
  ```
326
337
 
327
338
  Without arguments (and with a TTY), opens an **interactive session picker** for
328
339
  the project found upward from `<directory>` (default: `$PWD`):
329
340
 
341
+ - the title bar names the project being worked on — `ocmux — <project> sessions`
342
+ — so the list is never ambiguous
330
343
  - sessions are listed most-recently-viewed first
331
- - `Enter`/`Space` switches (menu stays open) · `n` create (name input) ·
332
- `r` rename (edit in place) · `R` set a reminder · `d` delete (confirm) ·
333
- `a` switch agent · `m` switch model · `p` project switcher · `h` help ·
334
- `q`/`Ctrl+C` quit
335
- - switching updates `.ocmux.json` and relaunches the TUI on the chosen session
336
- (`opencode --server <url> --session <id>`); silent on success
344
+ - `/` starts an **incremental search** of the list (matches title/id,
345
+ case-insensitive, space-separated tokens are ANDed). While the search line is
346
+ active it shows `Enter: confirm · Esc: cancel` on the right: `Enter` keeps the
347
+ filter and returns to normal navigation, `ESC` clears it, `/` resumes editing
348
+ it, and `Backspace` on an already-empty search also exits it. The same `/`
349
+ search works in the model/agent pickers and the project switcher.
350
+ - `Enter` switches (menu stays open). `Space` over a different session enters
351
+ **broadcast mode**: Space selects/deselects sessions; `Enter` keeps the list
352
+ and switches normally; `ESC`/`q` cancels back to the session list and returns
353
+ the TUI to the stored session; deselecting down to a single session selects
354
+ that remaining session. New selections open in the TUI for inspection.
355
+ Broadcast mode also has `h` help, `d` delete, and `m` to change the model for
356
+ every selected session.
357
+ - `n` create (name input) · `r` rename (edit in place) · `R` set a reminder ·
358
+ `d` delete (confirm) · `a` switch agent · `m` switch model · `p` project
359
+ switcher (inspect-only by default) · `h` help · `q` quit
360
+ - `m` opens the model list **sorted by provider** with the cursor already on the
361
+ session's **current model** — also in broadcast mode, where it starts from the
362
+ cursor session's model, so a bulk change begins where you are
363
+ - **`q` only quits the session picker.** In every other menu (model/agent
364
+ pickers, project switcher, help/input prompts) `q`/`ESC` just closes that menu
365
+ and returns to the previous one. **`Ctrl+C` fully exits** `ocmux` from any menu.
366
+ - switching updates `.ocmux.json` and refreshes the project's dedicated TUI, or
367
+ the shared TUI when no live dedicated one exists; silent on success. The file
368
+ updated is always the one of the project being listed — your own project
369
+ unless ocmux was started with `--all-projects`
337
370
  - new sessions inherit the model of the previously selected session (v2
338
371
  sessions created via the API have no model and won't run a prompt until set)
339
372
 
340
373
  Reminders (`R`) are stored in the `.ocmux.json` `annotations` map; `agentp`
341
374
  prepends a session's reminder to every prompt sent to it.
342
375
 
376
+ Broadcast selections are stored in `.ocmux.json` as `broadcast`. `agentp`
377
+ sends a prompt to all selected sessions (waiting for busy sessions to go idle),
378
+ and prints a labeled answer section for each. Errors/incomplete targets are
379
+ reported individually with session name, id, error, and timestamp.
380
+
343
381
  Subcommands:
344
382
 
345
- - **`serve [--server <url>] [--git|--GIT] [dir]`** — create a project TUI window
383
+ - **`serve [--server <url>] [--git|--GIT] [dir]`** — initialize project state
346
384
  (checks the server is reachable first). Aliased as `new` for backwards
347
385
  compatibility. `--git`/`--GIT` resolve `dir` to the nearest parent with a
348
386
  `.git` entry / directory.
387
+ - **`tui [--shared] [--server <url>] [dir]`** — register the current tmux pane and run OpenCode
388
+ in it. Without `--shared`, the pane follows only that project. With
389
+ `--shared`, it becomes the one fallback TUI for all projects and can reconnect
390
+ across server URLs as selections change. Re-registering a slot stops its old
391
+ wrapper without destroying the old pane. Closing the TUI unregisters it.
392
+ `tui --list` lists live registrations; `tui [--shared] --status` inspects a
393
+ dedicated/shared slot; `tui [--shared] --detach` unregisters that slot without
394
+ closing the pane or its current TUI.
349
395
  - **`session <id|title> [dir]`** — non-interactive session switch.
350
- - **`list [-l]`** — list project windows (with `-l`, their server URL).
351
- - **`model [ref]`** — switch the model of the selected session.
352
- - **`kill [dir]`** — close the project's TUI window. **Keeps `.ocmux.json`**
353
- (session memory; marks it `stopped`).
354
- - **`resurrect [dir]`** — recreate the project window from its state file.
396
+ - **`list [-l]`** — list configured projects and whether their route is
397
+ `project`, `shared`, or `headless` (with `-l`, their server URL).
355
398
  - **`migrate`** — rewrite legacy (v1-style) `.ocmux.json` files to the v2 schema.
356
399
 
357
400
  The old `switch` subcommand is gone: press **`p`** inside the session picker to
358
- open the (read-only) project switcher instead. `ocmux` never starts or stops the
401
+ open the project switcher instead. The switcher is a **foldable tree**: `▸`/`▾`
402
+ marks a project as folded/unfolded, `Space` folds/unfolds a project's sessions
403
+ (fetched once per project, most recent first), and `/` searches projects *and*
404
+ their unfolded sessions (a matching session keeps its project header visible).
405
+
406
+ By default the switcher is an **inspector**: `Enter` on a project row routes its
407
+ current session to the applicable registered TUI, `Enter`/`Space` on a session
408
+ row shows that session, and you **always come back to your own project's
409
+ list** when you leave it (`q`). No `.ocmux.json` is ever written from there, so
410
+ `agentp` — which reads the state file of the directory it runs in — keeps
411
+ prompting your own project's session.
412
+
413
+ Pass **`--all-projects`** to turn it into a real switcher: selecting a project
414
+ then moves the session picker over to that project, and picking a session there
415
+ updates *that* project's `.ocmux.json` (which is what `agentp` reads when it
416
+ runs in that directory). The title bar always names the project being listed, so
417
+ either way you can tell where you are. `ocmux` never starts or stops the
359
418
  OpenCode server — run `opencode serve` yourself (see [Versioning](#versioning)
360
419
  for the pairing policy).
361
420
 
362
- Options: `-l` · `--version` · `-h` · `--` (treat the next argument as a directory).
421
+ Options: `-l` · `--all-projects` · `--shared` (only with `tui`) · `--version` ·
422
+ `-h` · `--` (treat the next argument as a directory). There is no `--global`
423
+ alias.
363
424
 
364
425
  Notes:
365
426
 
366
- - If `<directory>` is not a valid path, `ocmux` matches it against the basenames
367
- of existing project windows (exact unique match).
368
427
  - If the server is password-protected (`OPENCODE_SERVER_PASSWORD`), both
369
428
  `agentp` and `ocmux` send the required HTTP Basic Auth credentials.
370
429
 
430
+ ### TUI runtime registry
431
+
432
+ TUI placement is ephemeral and is never written to `.ocmux.json`. Registrations
433
+ live in `$XDG_RUNTIME_DIR/agentp/ocmux-tuis.json` (falling back to a private
434
+ `/tmp/agentp-<uid>/` directory); `OCMUX_RUNTIME_DIR` overrides that location.
435
+ The directory is mode `0700`, registry files are mode `0600`, and updates use a
436
+ lock plus atomic rename.
437
+
438
+ A registration stores the tmux socket, pane ID, diagnostic wrapper PID, and a
439
+ random pane verification token. Matching ID/token options are also written to
440
+ the pane before it can be respawned. This prevents stale entries from targeting
441
+ an unrelated pane and lets a pane move between windows or tmux sessions on the
442
+ same socket without re-registering. Dead registrations are pruned when queried.
443
+
444
+ Closing OpenCode makes its foreground `ocmux tui` wrapper unregister itself if
445
+ it still owns the token. Replacing a dedicated/shared registration interrupts
446
+ the previous wrapper but preserves its pane. `--detach` only unregisters and
447
+ clears the pane markers; it does not close the pane or the OpenCode process.
448
+
449
+ Registry commands:
450
+
451
+ ```bash
452
+ ocmux tui # dedicated TUI for the current project
453
+ ocmux tui /path/to/project # dedicated TUI for another project
454
+ ocmux tui --shared # the single cross-project fallback TUI
455
+ ocmux tui --list # all live dedicated/shared registrations
456
+ ocmux tui --status # current project's dedicated slot
457
+ ocmux tui --status --shared # shared slot
458
+ ocmux tui --detach # unregister current project's slot
459
+ ocmux tui --detach --shared # unregister shared slot
460
+ ```
461
+
462
+ Routing precedence is:
463
+
464
+ 1. a live TUI dedicated to the selected project;
465
+ 2. the single live shared TUI;
466
+ 3. headless operation (the session still switches successfully).
467
+
468
+ Switching respawns the registered pane with `ocmux tui`, which reconnects
469
+ OpenCode to the selected server, directory, and session. Server-side work keeps
470
+ running, but client-local TUI state such as a draft prompt or scroll position is
471
+ lost during the refresh.
472
+
371
473
  ### State file
372
474
 
373
475
  `.ocmux.json` (in the project directory) stores `version`, `directory`,
@@ -380,8 +482,8 @@ gitignored — never commit it.
380
482
  2. Resolves the target from the nearest `.ocmux.json`: server URL, project
381
483
  directory, and the stored session id (falls back to the most recently viewed
382
484
  session in that directory, or creates one pinned to the directory).
383
- 3. Focuses the project's TUI window, prepends the session annotation (if any),
384
- and sends the prompt via the v2 session API (`POST /api/session/:id/prompt`,
485
+ 3. Prepends the session annotation (if any) and sends the prompt via the v2
486
+ session API (`POST /api/session/:id/prompt`,
385
487
  delivering to that session regardless of what the TUI shows).
386
488
  4. Attaches to the SSE stream first so no events are missed, and streams text
387
489
  until the session is quiescent after its terminal signal.
@@ -423,7 +525,7 @@ Non-text Telegram updates (photos, stickers, etc.) are silently ignored.
423
525
  | `/servers` | List all ocmux-served projects (▶ active, 🔌 disconnected, 💀 dead) |
424
526
  | `/server <name>` | Switch active server; matches by full path, basename, or substring |
425
527
  | `/server --force <name>` | Take over a server from another chat |
426
- | `/resurrect [path]` | Restart a crashed server from its `.ocmux.json`; accepts optional directory path |
528
+ | `/resurrect [path]` | Check the configured user-managed server and explain how to restart it externally |
427
529
  | `/sessions` | List sessions (numbered, newest first) |
428
530
  | `/session <name-or-number>` | Switch to a session by name or position |
429
531
  | `/session new [name]` | Create a new session |