@geohar/un-bien 0.9.0 → 0.14.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/README.md +99 -130
- package/dist/actions/handlers.js.map +1 -1
- package/dist/actions/registry.js.map +1 -1
- package/dist/bin/launcher.js.map +1 -1
- package/dist/commands/deps.d.ts +156 -0
- package/dist/commands/deps.js +2 -0
- package/dist/commands/deps.js.map +1 -0
- package/dist/commands/fork_link.d.ts +4 -0
- package/dist/commands/fork_link.js +45 -0
- package/dist/commands/fork_link.js.map +1 -0
- package/dist/commands/housekeeping.d.ts +34 -0
- package/dist/commands/housekeeping.js +275 -0
- package/dist/commands/housekeeping.js.map +1 -0
- package/dist/commands/info.d.ts +43 -0
- package/dist/commands/info.js +127 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/lifecycle.d.ts +45 -0
- package/dist/commands/lifecycle.js +708 -0
- package/dist/commands/lifecycle.js.map +1 -0
- package/dist/commands/pairing.d.ts +26 -0
- package/dist/commands/pairing.js +167 -0
- package/dist/commands/pairing.js.map +1 -0
- package/dist/commands/register.d.ts +12 -0
- package/dist/commands/register.js +255 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/relay.d.ts +28 -0
- package/dist/commands/relay.js +81 -0
- package/dist/commands/relay.js.map +1 -0
- package/dist/commands/session_ops.d.ts +52 -0
- package/dist/commands/session_ops.js +75 -0
- package/dist/commands/session_ops.js.map +1 -0
- package/dist/config.d.ts +2 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon/install.d.ts +4 -3
- package/dist/daemon/install.js +7 -1
- package/dist/daemon/install.js.map +1 -1
- package/dist/enrich_tool_args.js.map +1 -1
- package/dist/extension_ui_bridge.js.map +1 -1
- package/dist/image_codec.js.map +1 -1
- package/dist/index.d.ts +32 -101
- package/dist/index.js +818 -2867
- package/dist/index.js.map +1 -1
- package/dist/launch.d.ts +9 -1
- package/dist/launch.js +39 -4
- package/dist/launch.js.map +1 -1
- package/dist/launcher/launcher.js +21 -2
- package/dist/launcher/launcher.js.map +1 -1
- package/dist/mcp/mesh_result.js.map +1 -1
- package/dist/mcp/mesh_server.js.map +1 -1
- package/dist/mesh/canonical.js +1 -1
- package/dist/mesh/canonical.js.map +1 -1
- package/dist/mesh/client.js.map +1 -1
- package/dist/mesh/encoding.js.map +1 -1
- package/dist/mesh/self_revoke.js.map +1 -1
- package/dist/mesh/siblings.js.map +1 -1
- package/dist/mesh/verify.js +1 -1
- package/dist/mesh/verify.js.map +1 -1
- package/dist/pairing/crypto.js +0 -1
- package/dist/pairing/crypto.js.map +1 -1
- package/dist/pairing/peer_trust.js.map +1 -1
- package/dist/pairing/qr.js.map +1 -1
- package/dist/pairing/storage.js +4 -3
- package/dist/pairing/storage.js.map +1 -1
- package/dist/panel_bridge.js +1 -0
- package/dist/panel_bridge.js.map +1 -1
- package/dist/paths.d.ts +22 -8
- package/dist/paths.js +37 -10
- package/dist/paths.js.map +1 -1
- package/dist/protocol/codec.js.map +1 -1
- package/dist/rooms.js +1 -4
- package/dist/rooms.js.map +1 -1
- package/dist/session/bridge.js.map +1 -1
- package/dist/session/broker.js.map +1 -1
- package/dist/session/broker_remote.js.map +1 -1
- package/dist/session/capabilities.d.ts +11 -0
- package/dist/session/capabilities.js +35 -0
- package/dist/session/capabilities.js.map +1 -0
- package/dist/session/cwd_lock.js +3 -3
- package/dist/session/cwd_lock.js.map +1 -1
- package/dist/session/debug_log.js +13 -3
- package/dist/session/debug_log.js.map +1 -1
- package/dist/session/envelope.js.map +1 -1
- package/dist/session/global_config.d.ts +1 -1
- package/dist/session/global_config.js +1 -1
- package/dist/session/global_config.js.map +1 -1
- package/dist/session/ipc.d.ts +2 -2
- package/dist/session/ipc.js.map +1 -1
- package/dist/session/leader_election.js.map +1 -1
- package/dist/session/local_config.d.ts +37 -0
- package/dist/session/local_config.js +45 -1
- package/dist/session/local_config.js.map +1 -1
- package/dist/session/mesh_node.d.ts +1 -1
- package/dist/session/mesh_node.js +1 -1
- package/dist/session/mesh_node.js.map +1 -1
- package/dist/session/peer.js.map +1 -1
- package/dist/session/peer_inventory.js.map +1 -1
- package/dist/session/peer_limits.js.map +1 -1
- package/dist/session/received_images.d.ts +63 -0
- package/dist/session/received_images.js +273 -0
- package/dist/session/received_images.js.map +1 -0
- package/dist/session/relay_lifecycle.d.ts +219 -0
- package/dist/session/relay_lifecycle.js +764 -0
- package/dist/session/relay_lifecycle.js.map +1 -0
- package/dist/session/rpc_envelope.d.ts +10 -0
- package/dist/session/rpc_envelope.js +9 -0
- package/dist/session/rpc_envelope.js.map +1 -1
- package/dist/session/rpc_handlers.d.ts +53 -0
- package/dist/session/rpc_handlers.js +268 -0
- package/dist/session/rpc_handlers.js.map +1 -0
- package/dist/session/rpc_inbound.d.ts +41 -6
- package/dist/session/rpc_inbound.js +55 -0
- package/dist/session/rpc_inbound.js.map +1 -1
- package/dist/session/setup_wizard.js.map +1 -1
- package/dist/session/tools.js.map +1 -1
- package/dist/session/wizard.js.map +1 -1
- package/dist/state_migration.d.ts +45 -0
- package/dist/state_migration.js +104 -0
- package/dist/state_migration.js.map +1 -0
- package/dist/subagent_rooms.d.ts +19 -0
- package/dist/subagent_rooms.js +146 -14
- package/dist/subagent_rooms.js.map +1 -1
- package/dist/test_hooks.d.ts +180 -0
- package/dist/test_hooks.js +98 -0
- package/dist/test_hooks.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +11 -0
- package/dist/transport/peer_channel.js +34 -11
- package/dist/transport/peer_channel.js.map +1 -1
- package/dist/transport/pi_forward_client.js.map +1 -1
- package/dist/transport/relay_client.d.ts +5 -2
- package/dist/transport/relay_client.js +6 -3
- package/dist/transport/relay_client.js.map +1 -1
- package/dist/ui/footer.js.map +1 -1
- package/docs/daemon.md +160 -170
- package/package.json +1 -1
- package/service-templates/launchd.plist.template +5 -4
- package/service-templates/systemd.service.template +3 -2
package/README.md
CHANGED
|
@@ -100,7 +100,7 @@ current turn, and receive any later reply through the inbox/turn flow with
|
|
|
100
100
|
`re` correlating it to the original message id.
|
|
101
101
|
|
|
102
102
|
Peers on the same machine talk over a Unix domain socket at
|
|
103
|
-
`~/.
|
|
103
|
+
`~/.local/state/un-bien/sessions/<session-name>/broker.sock`. When sibling PCs are paired,
|
|
104
104
|
a leader-capable Extension or MCP participant bridges the opaque cross-PC
|
|
105
105
|
addresses over the relay; local-only use stays on UDS when relay access is off.
|
|
106
106
|
Useful for splitting work across roles (`backend`, `frontend`, `tests`,
|
|
@@ -240,7 +240,7 @@ Once the relay is up (`/unbien relay status` shows `started` or `paired`):
|
|
|
240
240
|
|
|
241
241
|
A QR code is printed in the terminal. Scan it with the Un Bien mobile app.
|
|
242
242
|
Pairing is **per machine** — once a device is paired, every Pi process on
|
|
243
|
-
this machine accepts it (it lives in `~/.
|
|
243
|
+
this machine accepts it (it lives in `~/.local/state/un-bien/peers.json`).
|
|
244
244
|
|
|
245
245
|
To list paired devices:
|
|
246
246
|
|
|
@@ -374,7 +374,7 @@ original message id.
|
|
|
374
374
|
|
|
375
375
|
The wire format is a 5-field envelope `{ from, to, id, re, body }` serialized
|
|
376
376
|
as one JSON line per message. The leader's broker writes an `audit.jsonl`
|
|
377
|
-
log at `~/.
|
|
377
|
+
log at `~/.local/state/un-bien/sessions/<name>/audit.jsonl` for postmortem inspection.
|
|
378
378
|
|
|
379
379
|
Useful commands:
|
|
380
380
|
|
|
@@ -409,56 +409,17 @@ real name to the peer.
|
|
|
409
409
|
| `/unbien relay url <url>` | Same as `set-relay` |
|
|
410
410
|
| `/unbien config` | Show the effective relay URL and its source (env / config / unset) |
|
|
411
411
|
|
|
412
|
-
###
|
|
413
|
-
|
|
414
|
-
| Command
|
|
415
|
-
|
|
|
416
|
-
| `/unbien
|
|
417
|
-
| `/unbien
|
|
418
|
-
| `/unbien daemons` | List registered daemons + state |
|
|
419
|
-
| `/unbien daemon start` | Start every registered daemon |
|
|
420
|
-
| `/unbien daemon stop` | Stop every running daemon (`/unbien stop` stops only the local terminal) |
|
|
421
|
-
| `/unbien daemon restart` | Stop + start all daemons |
|
|
422
|
-
| `/unbien daemon status` | Detailed runtime status (pid, uptime, restart count) |
|
|
423
|
-
| `/unbien daemon send <id> "<text>"` | Send a prompt to a specific daemon |
|
|
424
|
-
| `/unbien cron add <id> "<expr>" "<prompt>"` | Schedule a recurring prompt (`--tz`, `--wake`, `--no-skip-busy`, `--catchup`) |
|
|
425
|
-
| `/unbien cron list` | List scheduled jobs (schedule, enabled, next run, last status) |
|
|
426
|
-
| `/unbien cron run <jobId>` | Fire a job now (ignores its schedule) |
|
|
427
|
-
| `/unbien cron enable\|disable <jobId>` | Toggle a job on/off |
|
|
428
|
-
| `/unbien cron remove <jobId>` | Delete a job |
|
|
429
|
-
| `/unbien cron log [<jobId>] [--tail N]` | Read the fire/skip audit log |
|
|
430
|
-
| `/unbien install` | Install `pi-supervisord` as a system service |
|
|
431
|
-
| `/unbien uninstall` | Remove the system service (registry preserved) |
|
|
412
|
+
### Service install & remote launch (see [Remote launch](#remote-launch))
|
|
413
|
+
|
|
414
|
+
| Command | Description |
|
|
415
|
+
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
416
|
+
| `/unbien install` | Install the **unbien-launcher** daemon as a system service + link the `unbien` CLI |
|
|
417
|
+
| `/unbien uninstall` | Remove the launcher service + CLI links (pairing and config preserved) |
|
|
432
418
|
|
|
433
419
|
All commands above work both as Pi slash commands (interactive) and as
|
|
434
420
|
shell-level `unbien <subcommand>` when the package is installed
|
|
435
421
|
globally (`npm install -g @geohar/un-bien`).
|
|
436
422
|
|
|
437
|
-
### Scheduled prompts (`cron`)
|
|
438
|
-
|
|
439
|
-
`unbien cron` schedules **recurring prompts** to daemons through the
|
|
440
|
-
supervisor — e.g. a daily "summarise new PRs". Output flows fire-and-forget to
|
|
441
|
-
the mesh/app like any prompt; the cron layer only audits the dispatch.
|
|
442
|
-
|
|
443
|
-
- **Schedule** is a cron expression (croner syntax; an optional 6th _seconds_
|
|
444
|
-
field is supported), with an optional IANA timezone via `--tz`:
|
|
445
|
-
|
|
446
|
-
```sh
|
|
447
|
-
unbien cron add a1b2c3d4 "0 9 * * *" "Summarise new PRs" --tz America/Sao_Paulo
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
- **Minimum interval is 60s** — more frequent schedules are rejected (guards
|
|
451
|
-
token cost + pileup). A fire is **skipped when the daemon is mid-turn**
|
|
452
|
-
(`--no-skip-busy` to override); `--wake` starts a stopped daemon first;
|
|
453
|
-
`--catchup` runs once on supervisor start if the previous run was missed.
|
|
454
|
-
- **Prerequisite**: the supervisor must run as a service (`unbien install`).
|
|
455
|
-
Without it there is no scheduler, and `cron` commands say so instead of
|
|
456
|
-
silently pretending to schedule.
|
|
457
|
-
- **Audit**: every fire **and** every skip appends one line to
|
|
458
|
-
`~/.pi/un-bien/cron.jsonl` with a `result` of `delivered`,
|
|
459
|
-
`woke_and_delivered`, `deliver_failed`, `skipped_busy`, `skipped_down`, or
|
|
460
|
-
`skipped_disabled` — read it with `unbien cron log`.
|
|
461
|
-
|
|
462
423
|
### Footer + title
|
|
463
424
|
|
|
464
425
|
- `📡 local (N)` — current agent session and peer count (local mesh)
|
|
@@ -472,105 +433,101 @@ tabs.
|
|
|
472
433
|
|
|
473
434
|
---
|
|
474
435
|
|
|
475
|
-
##
|
|
436
|
+
## Remote launch
|
|
476
437
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
438
|
+
The **unbien-launcher** is a lightweight mesh peer — **not** a Pi session — that
|
|
439
|
+
lets a paired app reach your machine even when no Pi is running. It reuses the
|
|
440
|
+
machine's un-bien config (identity + relay), joins the machine-level control
|
|
441
|
+
room, advertises `remote_launch`, and spawns a `pi` window via `tmux` (default)
|
|
442
|
+
or `herdr` when the app asks for one.
|
|
481
443
|
|
|
482
444
|
See [`docs/daemon.md`](./docs/daemon.md) for troubleshooting.
|
|
483
445
|
|
|
484
446
|
### One-time setup
|
|
485
447
|
|
|
486
448
|
```bash
|
|
487
|
-
# Install the package globally so `unbien`
|
|
488
|
-
#
|
|
489
|
-
#
|
|
449
|
+
# Install the package globally so the `unbien` CLI is on your PATH
|
|
450
|
+
# (`pi install npm:@geohar/un-bien` alone makes the Pi extension available
|
|
451
|
+
# but does NOT expose the CLI binary — see
|
|
490
452
|
# https://docs.npmjs.com/cli/v10/configuring-npm/package-json#bin).
|
|
491
453
|
npm install -g @geohar/un-bien
|
|
492
454
|
|
|
493
|
-
# Install the
|
|
455
|
+
# Install the launcher as a user-level system service. Linux uses
|
|
494
456
|
# systemd --user; macOS uses launchd LaunchAgent. Both auto-start at
|
|
495
457
|
# login and survive reboots.
|
|
496
458
|
unbien install
|
|
497
459
|
```
|
|
498
460
|
|
|
461
|
+
Or from inside Pi: `/unbien install` — same service, plus it links the
|
|
462
|
+
`unbien` CLI into `~/.local/bin` so no global npm install is needed.
|
|
463
|
+
|
|
499
464
|
The `install` command:
|
|
500
465
|
|
|
501
|
-
- Writes `~/.config/systemd/user/unbien-
|
|
502
|
-
|
|
466
|
+
- Writes `~/.config/systemd/user/unbien-launcher.service` (Linux) or
|
|
467
|
+
`~/Library/LaunchAgents/dev.unbien.launcher.plist` (macOS); on Windows it
|
|
468
|
+
registers a Task Scheduler task (`RemotePiLauncher`) and prompts for
|
|
469
|
+
elevation once
|
|
503
470
|
- Activates it via `systemctl --user enable --now` or `launchctl bootstrap`
|
|
504
|
-
- The
|
|
471
|
+
- The launcher starts immediately and re-starts on every login
|
|
505
472
|
|
|
506
|
-
|
|
473
|
+
A standalone package exists for running the launcher in the foreground, no
|
|
474
|
+
service: `npm install -g @geohar/un-bien-launcher` → `unbien-launcher`. Same
|
|
475
|
+
daemon, shipped as its own binary (see the
|
|
476
|
+
[launcher README](../launcher/README.md)).
|
|
507
477
|
|
|
508
|
-
|
|
478
|
+
### Enable remote launch
|
|
509
479
|
|
|
510
|
-
|
|
511
|
-
# 1. Configure the agent interactively first (one time).
|
|
512
|
-
cd ~/Movies
|
|
513
|
-
pi # /unbien → setup wizard, /unbien pair, etc
|
|
480
|
+
The launcher only spawns sessions where remote launch is **opted in**:
|
|
514
481
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
# → Daemon registered: id=4e39152d name="Video Editor" cwd=/Users/x/Movies
|
|
482
|
+
- per directory: `allow_remote_launch: true` in `<cwd>/.pi/un-bien/config.json`
|
|
483
|
+
- or machine-wide: `defaults.allow_remote_launch: true` in the global config
|
|
484
|
+
(`~/.pi/extensions/un-bien.json`)
|
|
519
485
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
Now you can:
|
|
486
|
+
The spawn backend is machine-wide: `launch.backend` in the global config —
|
|
487
|
+
`tmux` (default; one shared `un-bien` tmux session, a window per launched Pi)
|
|
488
|
+
or `herdr`. The backend binary must be on PATH: `unbien install` snapshots
|
|
489
|
+
your PATH at install time, so re-run it after installing new tools.
|
|
525
490
|
|
|
526
|
-
|
|
527
|
-
unbien daemons # list + state
|
|
528
|
-
unbien daemon status # uptime, pid, restart count
|
|
529
|
-
unbien daemon send 4e39152d "Cut the first 30 seconds of latest clip"
|
|
530
|
-
unbien daemon stop # stop all
|
|
531
|
-
unbien daemon restart # restart all
|
|
532
|
-
```
|
|
491
|
+
### Launch names
|
|
533
492
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
493
|
+
A `session_launch` request may carry a `name`. On the tmux backend the
|
|
494
|
+
launched Pi gets it as `pi -n <name>` — pi's native session display name —
|
|
495
|
+
which the extension resolves as the session-scoped agent name: the mesh
|
|
496
|
+
join, cwd lock, `room_meta`, and the app's session tile all show it instead
|
|
497
|
+
of the path-derived default. It is per-process (never inherited by
|
|
498
|
+
subagents or child processes) and never persisted — a manual `pi` in the
|
|
499
|
+
same directory keeps its configured `agent_name`. `/unbien rename` still
|
|
500
|
+
wins once it runs. The herdr backend uses the name as the workspace label
|
|
501
|
+
only until it can pass args through to pi.
|
|
538
502
|
|
|
539
503
|
### Removing or uninstalling
|
|
540
504
|
|
|
541
505
|
```bash
|
|
542
|
-
unbien remove
|
|
543
|
-
unbien uninstall # remove the supervisor service (registry kept)
|
|
506
|
+
unbien uninstall # remove the launcher service (pairing + config kept)
|
|
544
507
|
```
|
|
545
508
|
|
|
546
|
-
`uninstall` is reversible — re-running `install` later brings
|
|
547
|
-
|
|
548
|
-
~/.pi/un-bien/daemons.json`.
|
|
509
|
+
`uninstall` is reversible — re-running `install` later brings the launcher
|
|
510
|
+
back. Pairing and identity live in the state root and are never touched.
|
|
549
511
|
|
|
550
512
|
### Where to find logs
|
|
551
513
|
|
|
552
|
-
| Platform | Command
|
|
553
|
-
| -------- |
|
|
554
|
-
| Linux | `journalctl --user -u unbien-
|
|
555
|
-
| macOS | `tail -f ~/.
|
|
556
|
-
|
|
557
|
-
Each spawned daemon's stderr is forwarded into the supervisor's log
|
|
558
|
-
with a `[<cwd>]` prefix, so a single log stream shows every agent.
|
|
514
|
+
| Platform | Command |
|
|
515
|
+
| -------- | ------------------------------------------------------- |
|
|
516
|
+
| Linux | `journalctl --user -u unbien-launcher -f` |
|
|
517
|
+
| macOS | `tail -f ~/.local/state/un-bien/launcher.log` |
|
|
518
|
+
| Windows | `Get-Content ~\.local\state\un-bien\launcher.log -Wait` |
|
|
559
519
|
|
|
560
520
|
### Caveats
|
|
561
521
|
|
|
562
|
-
- **
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
- **
|
|
570
|
-
|
|
571
|
-
come back automatically.
|
|
572
|
-
- **One daemon per cwd.** The `roomIdForCwd` derivation makes daemons
|
|
573
|
-
by-path; two daemons in the same folder is rejected at `create` time.
|
|
522
|
+
- **Pairing still happens interactively.** The launcher doesn't show a QR; it
|
|
523
|
+
only trusts owners already paired via `/unbien pair` in a Pi session on
|
|
524
|
+
this machine.
|
|
525
|
+
- **Tool execution is not gated.** A launched Pi inherits the same Pi config
|
|
526
|
+
an interactive run uses — Bash, Edit, Write etc. all execute without
|
|
527
|
+
prompting. Configure Pi's tool permissions to taste before enabling
|
|
528
|
+
`allow_remote_launch`.
|
|
529
|
+
- **Same identity, same relay.** The launcher reads the machine's global
|
|
530
|
+
config — `/unbien config` shows exactly what it will use.
|
|
574
531
|
|
|
575
532
|
---
|
|
576
533
|
|
|
@@ -578,17 +535,14 @@ with a `[<cwd>]` prefix, so a single log stream shows every agent.
|
|
|
578
535
|
|
|
579
536
|
### Files
|
|
580
537
|
|
|
581
|
-
| Path
|
|
582
|
-
|
|
|
583
|
-
| `~/.pi/extensions/un-bien.json`
|
|
584
|
-
| `<cwd>/.pi/un-bien/config.json`
|
|
585
|
-
| `~/.
|
|
586
|
-
| `~/.
|
|
587
|
-
| `~/.
|
|
588
|
-
| `~/.
|
|
589
|
-
| `~/.pi/un-bien/cron.json` · `cron.jsonl` | Per-machine | Cron registry + fire/skip audit log |
|
|
590
|
-
| `~/.pi/un-bien/supervisor.sock` | Per-machine | Supervisor control socket |
|
|
591
|
-
| `~/.pi/un-bien/skills/agent-network/SKILL.md` | Per-user | Agent skill the LLM reads |
|
|
538
|
+
| Path | Scope | What's in it |
|
|
539
|
+
| ------------------------------------------------------ | ----------------- | ------------------------------------------------------------------------------ |
|
|
540
|
+
| `~/.pi/extensions/un-bien.json` | Per-user (global) | `relay` URL, `defaults`, `identity`, `debug` — the global settings (see below) |
|
|
541
|
+
| `<cwd>/.pi/un-bien/config.json` | Per-directory | `agent_name`, `auto_start_relay`, `allow_remote_launch` |
|
|
542
|
+
| `~/.local/state/un-bien/identity.json` | Per-machine | Paired identity keypair (file identity backend; `0600`) |
|
|
543
|
+
| `~/.local/state/un-bien/peers.json` | Per-machine | Paired mobile devices |
|
|
544
|
+
| `~/.local/state/un-bien/sessions/<name>/` | Per-session | Broker socket + `audit.jsonl` |
|
|
545
|
+
| `~/.local/state/un-bien/skills/agent-network/SKILL.md` | Per-user | Agent skill the LLM reads |
|
|
592
546
|
|
|
593
547
|
### Global settings — `~/.pi/extensions/un-bien.json`
|
|
594
548
|
|
|
@@ -606,13 +560,19 @@ fields are optional:
|
|
|
606
560
|
// Pin auto-start once instead of dropping a file into every repo.
|
|
607
561
|
"defaults": { "auto_start_relay": true },
|
|
608
562
|
|
|
563
|
+
// Remote-launch backend a `session_launch` request uses on THIS machine:
|
|
564
|
+
// "tmux" (default; one shared tmux session, a window per launched Pi) or
|
|
565
|
+
// "herdr". Machine-wide choice — whether remote launch is enabled at all
|
|
566
|
+
// stays the per-cwd `allow_remote_launch` flag.
|
|
567
|
+
"launch": { "backend": "tmux" },
|
|
568
|
+
|
|
609
569
|
// Machine-identity storage. `storage` selects the PRIMARY backend for this
|
|
610
570
|
// Pi's long-term Ed25519 seed: "keychain" (OS-secured, default) or "file"
|
|
611
571
|
// (a 0600 seed file — the SSH-private-key model: cat-able, portable,
|
|
612
572
|
// works headless). `path` overrides the file-backend location
|
|
613
|
-
// (default ~/.
|
|
573
|
+
// (default ~/.local/state/un-bien/identity.json). The unselected backend is still
|
|
614
574
|
// READ to recover an existing identity, but never written.
|
|
615
|
-
"identity": { "storage": "keychain", "path": "~/.
|
|
575
|
+
"identity": { "storage": "keychain", "path": "~/.local/state/un-bien/identity.json" },
|
|
616
576
|
|
|
617
577
|
// File-based diagnostic logs. Off by default. Read from config (not env)
|
|
618
578
|
// because the daemon fork usually runs detached without a shell's env.
|
|
@@ -635,14 +595,23 @@ Written by the `/unbien` setup wizard:
|
|
|
635
595
|
| Variable | Purpose |
|
|
636
596
|
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
637
597
|
| `UNBIEN_RELAY` | Relay URL override (highest precedence, ahead of the config file). CI / one-off use. |
|
|
638
|
-
| `
|
|
639
|
-
| `
|
|
598
|
+
| `UNBIEN_STATE_DIR` | Absolute override of the **state** dir itself. The knob for relocating state. Highest precedence of the state knobs. |
|
|
599
|
+
| `UNBIEN_DIR` | Legacy absolute override of the **state** dir itself (no suffix appended). Lower precedence than `UNBIEN_STATE_DIR`. |
|
|
600
|
+
| `UNBIEN_HOME` | Legacy stand-in `$HOME`; state lives at `<UNBIEN_HOME>/.pi/un-bien`. Lower precedence than `UNBIEN_DIR`. |
|
|
640
601
|
| `PI_CODING_AGENT_DIR` | The Pi host's settings root (default `~/.pi`); the global config lives at `<PI_CODING_AGENT_DIR>/extensions/un-bien.json`. |
|
|
641
|
-
| `UNBIEN_DIRECT_CONFIG` | Inline per-cwd config (JSON) instead of a `.pi/un-bien/config.json` file —
|
|
642
|
-
|
|
643
|
-
`
|
|
644
|
-
|
|
645
|
-
|
|
602
|
+
| `UNBIEN_DIRECT_CONFIG` | Inline per-cwd config (JSON) instead of a `.pi/un-bien/config.json` file — CI / one-off use. |
|
|
603
|
+
|
|
604
|
+
The state root resolves as `UNBIEN_STATE_DIR` > `UNBIEN_DIR` > `UNBIEN_HOME` >
|
|
605
|
+
`${XDG_STATE_HOME:-~/.local/state}/un-bien` — the XDG-style default. `UNBIEN_DIR`/
|
|
606
|
+
`UNBIEN_HOME` relocate un-bien **state** (sessions, cwd locks, paired identity) and stay honored for older deployments. On first use
|
|
607
|
+
of the new default, a one-time best-effort migration moves any legacy
|
|
608
|
+
`~/.pi/un-bien` state (peers.json included) into the new root.
|
|
609
|
+
`PI_CODING_AGENT_DIR` relocates only the global **config**, so it can sit
|
|
610
|
+
beside the coding agent's own settings.
|
|
611
|
+
|
|
612
|
+
**Deprecated**: the relay no longer defaults its SQLite DB to a CWD-relative
|
|
613
|
+
`data/mesh.db` — see the relay README for its `UNBIEN_MESH_DB_PATH` /
|
|
614
|
+
state-root resolution.
|
|
646
615
|
|
|
647
616
|
Override the relay for a single run without persisting:
|
|
648
617
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuEH;8EAC8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuEH;8EAC8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,CAAA;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/actions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,IAAI,iBAAiB,GAA+B,IAAI,
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/actions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,IAAI,iBAAiB,GAA+B,IAAI,CAAA;AAExD;;;GAGG;AACH,MAAM,aAAa,GAAwB;IACzC,OAAO,KAAI,CAAC;IACZ,YAAY;QACV,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI;QACF,OAAO,SAAS,CAAA;IAClB,CAAC;CACF,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,EAAE,aAAa,CAAA;QAC/B,IAAI,IAAI,EAAE,CAAC;YACT,iBAAiB,GAAG,IAAI,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,OAAO,iBAAiB,IAAI,aAAa,CAAA;AAC3C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,2BAA2B;IACzC,iBAAiB,GAAG,IAAI,CAAA;AAC1B,CAAC"}
|
package/dist/bin/launcher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/bin/launcher.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/bin/launcher.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEvD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAA;IACpC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CACT,gDAAgD,MAAM,CAAC,MAAM,GAAG;QAC9D,QAAQ,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CACvD,CAAA;IAED,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,IAAI,YAAY;YAAE,OAAM;QACxB,YAAY,GAAG,IAAI,CAAA;QACnB,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,kBAAkB,CAAC,CAAA;QAC3D,MAAM,CAAC,IAAI,EAAE,CAAA;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAA;IACD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC9C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,sCAAsC;IACtC,OAAO,CAAC,KAAK,CACX,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAChF,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { Ed25519Keypair } from "../pairing/crypto.js";
|
|
3
|
+
import type { SelfRevoke } from "../mesh/self_revoke.js";
|
|
4
|
+
import type { MeshTopologySnapshot } from "../mesh/siblings.js";
|
|
5
|
+
import type { Envelope } from "../session/envelope.js";
|
|
6
|
+
import type { MeshNode } from "../session/mesh_node.js";
|
|
7
|
+
import type { AcquiredLock } from "../session/cwd_lock.js";
|
|
8
|
+
import type { RelayClient } from "../transport/relay_client.js";
|
|
9
|
+
import type { PlainPeerChannel } from "../transport/peer_channel.js";
|
|
10
|
+
import type { ThinkingLevel } from "../protocol/types.js";
|
|
11
|
+
/** App↔Pi room meta projected by the ROOT session (see index.ts `_myRoomMeta`). */
|
|
12
|
+
export type RoomMeta = {
|
|
13
|
+
name: string;
|
|
14
|
+
cwd: string;
|
|
15
|
+
model?: string;
|
|
16
|
+
thinking?: ThinkingLevel;
|
|
17
|
+
working?: boolean;
|
|
18
|
+
sessionId?: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* The seam between index.ts (composition root) and the `/unbien` command
|
|
22
|
+
* modules.
|
|
23
|
+
*
|
|
24
|
+
* index.ts owns every piece of mutable module state and every lifecycle
|
|
25
|
+
* helper the command handlers touch. Command modules MUST NOT import from
|
|
26
|
+
* `../index.js` (that would be a circular import); instead index.ts builds
|
|
27
|
+
* one `CommandDeps` object (accessor closures over its module state plus
|
|
28
|
+
* direct function references) and passes it to `registerUnbienCommands`,
|
|
29
|
+
* which threads it into every handler that needs it.
|
|
30
|
+
*
|
|
31
|
+
* Members are added exactly as the moved code requires them — nothing
|
|
32
|
+
* speculative. Mutable state that commands write is a get/set pair; state
|
|
33
|
+
* they only read is `readonly`.
|
|
34
|
+
*/
|
|
35
|
+
export interface CommandDeps {
|
|
36
|
+
/** Remote state machine: `idle` → `started` (`paired` is derived). */
|
|
37
|
+
state: "idle" | "started";
|
|
38
|
+
/** Live relay WS connection, null when off. */
|
|
39
|
+
relay: RelayClient | null;
|
|
40
|
+
/** URL used by the current relay connection (http(s):// canonical form). */
|
|
41
|
+
relayUrl: string | null;
|
|
42
|
+
/** Local UDS mesh node, null when not joined. */
|
|
43
|
+
meshNode: MeshNode | null;
|
|
44
|
+
/** Mesh session name (LOCAL_SESSION_NAME once joined). */
|
|
45
|
+
sessionName: string | null;
|
|
46
|
+
/** Authoritative local-mesh peer count (broker `list_peers`). */
|
|
47
|
+
sessionPeerCount: number;
|
|
48
|
+
/** Cached Ed25519 identity of this connect cycle. */
|
|
49
|
+
cachedEd25519: Ed25519Keypair | null;
|
|
50
|
+
/** Last-known model name (root session projection). */
|
|
51
|
+
currentModel: string | undefined;
|
|
52
|
+
/** Last-known thinking level (root session projection). */
|
|
53
|
+
currentThinking: ThinkingLevel | undefined;
|
|
54
|
+
/** THE App↔Pi room id for the current chat session. */
|
|
55
|
+
myRoomId: string | null;
|
|
56
|
+
/** Room meta hello payload persisted for reconnect replay. */
|
|
57
|
+
myRoomMeta: RoomMeta | null;
|
|
58
|
+
/** Shortid of the most recently attached peer (UX hint only). */
|
|
59
|
+
peerShort: string;
|
|
60
|
+
/** Epoch of this Pi process's session (stamped on first start). */
|
|
61
|
+
sessionStartedAt: number | null;
|
|
62
|
+
/** Per-(cwd,name) singleton lock backing the mesh registration. */
|
|
63
|
+
cwdLock: AcquiredLock | null;
|
|
64
|
+
/** Name the cwd-lock actually reserved (`name` or `name#N`). */
|
|
65
|
+
lockedName: string | null;
|
|
66
|
+
/** Relay candidate generation (invalidates in-flight starts/stops). */
|
|
67
|
+
relayLifecycleGeneration: number;
|
|
68
|
+
/** True when a relay start was deferred because no session id existed yet
|
|
69
|
+
* (design 01M1CAW0); the root session_start re-runs the start once the id
|
|
70
|
+
* is available. */
|
|
71
|
+
relayStartDeferred: boolean;
|
|
72
|
+
/** Root replacement authority epoch (session replacements). */
|
|
73
|
+
rootLifecycleGeneration: number;
|
|
74
|
+
/** Mesh join candidate generation. */
|
|
75
|
+
meshJoinGeneration: number;
|
|
76
|
+
/** SelfRevoke topology producer for the relay path. */
|
|
77
|
+
selfRevoke: SelfRevoke | null;
|
|
78
|
+
/** Epoch guarding the SelfRevoke producer identity. */
|
|
79
|
+
selfRevokeEpoch: number;
|
|
80
|
+
/** Producer epoch that last published a verified topology. */
|
|
81
|
+
selfRevokeTopologyReadyEpoch: number;
|
|
82
|
+
/** Last topology snapshot published by the producer. */
|
|
83
|
+
selfRevokeTopology: MeshTopologySnapshot | null;
|
|
84
|
+
/** Auto-listener dispose fn for the current relay connection. */
|
|
85
|
+
stopAutoListener: (() => void) | null;
|
|
86
|
+
/** Cached "any device is paired machine-wide" flag (peers.json). */
|
|
87
|
+
readonly hasGlobalPairings: boolean;
|
|
88
|
+
/** Connected owner channels, keyed by canonical owner pubkey. */
|
|
89
|
+
readonly activePeers: Map<string, PlainPeerChannel>;
|
|
90
|
+
/** Set by session_shutdown; blocks outgoing candidates until rearm. */
|
|
91
|
+
readonly disposed: boolean;
|
|
92
|
+
/** Always-fresh session_start ctx (model/registry fallback). */
|
|
93
|
+
readonly lastEventCtx: Pick<ExtensionContext, "compact" | "abort" | "ui"> | null;
|
|
94
|
+
/** The ROOT session's ExtensionAPI (never a subagent child's). */
|
|
95
|
+
readonly pi: ExtensionAPI | null;
|
|
96
|
+
/** The root session's pi sessionId, null pre-sessionManager. */
|
|
97
|
+
readonly rootSessionId: string | null;
|
|
98
|
+
/** True while `generation` is the current root lifecycle epoch. */
|
|
99
|
+
isCurrentRootLifecycle(generation: number): boolean;
|
|
100
|
+
/** Friendly (configured or derived) agent name for a cwd. */
|
|
101
|
+
displayName(cwd: string): string;
|
|
102
|
+
/** Room id for the current chat session, derived from the stable pi
|
|
103
|
+
* session id — or null when no session id exists yet, in which case the
|
|
104
|
+
* caller must NOT announce/join a room (design 01M1CAW0; the cwd-derived
|
|
105
|
+
* fallback is retired). */
|
|
106
|
+
deriveRoomId(cwd: string, name: string): string | null;
|
|
107
|
+
/** Friendly model name for room_meta. */
|
|
108
|
+
currentModelName(): string | undefined;
|
|
109
|
+
/** The ROOT session's state record (turn/agentRun/sessionManager). */
|
|
110
|
+
rootState(): {
|
|
111
|
+
sessionManager?: {
|
|
112
|
+
getSessionId(): string;
|
|
113
|
+
} | null;
|
|
114
|
+
};
|
|
115
|
+
/** Full teardown of relay-side state (relay off, bridge detached). */
|
|
116
|
+
goIdle(): void;
|
|
117
|
+
/** Reconnect backoff entry for a closed relay. */
|
|
118
|
+
onRelayClose(closedRelay: RelayClient): void;
|
|
119
|
+
/** Attach the pair_request auto-listener to a live relay. */
|
|
120
|
+
installAutoListener(relay: RelayClient): () => void;
|
|
121
|
+
/** Repaint the footer status line from current state. */
|
|
122
|
+
refreshFooter(ctx?: {
|
|
123
|
+
ui?: {
|
|
124
|
+
setStatus?: unknown;
|
|
125
|
+
setTitle?: unknown;
|
|
126
|
+
};
|
|
127
|
+
} | null): void;
|
|
128
|
+
/** Tear down an owner's live channel + report the revocation. */
|
|
129
|
+
revokeActiveOwnerRuntime(canonicalOwnerPubkey: string): void;
|
|
130
|
+
/** Attach the cross-PC bridge once relay + leader are both up. */
|
|
131
|
+
attachBridgeIfReady(): void;
|
|
132
|
+
/** Broadcast relay connectivity state to RPC clients. */
|
|
133
|
+
emitRelayState(force?: boolean): void;
|
|
134
|
+
/** Re-query the broker for the authoritative local peer count. */
|
|
135
|
+
refreshSessionPeerCount(peer: MeshNode, ctx?: Pick<ExtensionContext, "ui"> | null): void;
|
|
136
|
+
/** Queue an inbound mesh message for agent delivery. */
|
|
137
|
+
deliverMeshMessageToAgent(env: Envelope): void;
|
|
138
|
+
/** Reads peers.json and refreshes the global-pairings cache + footer. */
|
|
139
|
+
refreshPairingsCache(): void;
|
|
140
|
+
/** Tear down a connected owner's channel (revoke / disconnect). */
|
|
141
|
+
detachPeerChannel(appPeerId: string): void;
|
|
142
|
+
/** RPC control channel verbs (`relay:toggle` / `relay:on` / `relay:off`). */
|
|
143
|
+
handleControl(cmd: string): Promise<void>;
|
|
144
|
+
/** Relay connectivity label for status output. */
|
|
145
|
+
relayStatus(): "connected" | "reconnecting" | "disconnected";
|
|
146
|
+
/** Test-visible state: `idle` | `started` | derived `paired`. */
|
|
147
|
+
getState(): "idle" | "started" | "paired";
|
|
148
|
+
/** Hidden dev-only e2e UI harness (`/unbien test <scenario>`). */
|
|
149
|
+
runTestScenario(scenario: string): string;
|
|
150
|
+
/** ctx.ui.notify that never throws (stale-ctx safe). */
|
|
151
|
+
safeNotify(message: string, level?: "info" | "warning" | "error", preferred?: {
|
|
152
|
+
ui?: unknown;
|
|
153
|
+
} | null): void;
|
|
154
|
+
/** Rename this agent (mesh + relay room) — `/unbien rename`. */
|
|
155
|
+
renameAgent(newName: string): Promise<void>;
|
|
156
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/commands/deps.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Record that `sessionId` was born from the app fork request `req`. Best-effort. */
|
|
2
|
+
export declare function writeForkLink(sessionDir: string, sessionId: string, req: string): void;
|
|
3
|
+
/** Read + delete the fork request id for `sessionId`, or undefined when none. */
|
|
4
|
+
export declare function takeForkLink(sessionDir: string, sessionId: string): string | undefined;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fork-born linkage: a tiny marker persisted by `_cmdFork`'s `withSession`
|
|
3
|
+
* (running in the NEW forked session) and consumed by that session's FIRST
|
|
4
|
+
* `session_sync_end`, which echoes the app's originating fork request id as
|
|
5
|
+
* `forked_from_req` so the app can auto-navigate to the new session.
|
|
6
|
+
*
|
|
7
|
+
* Why a FILE and not a module variable: `ctx.fork` replaces the AgentSession,
|
|
8
|
+
* and the pi TUI host re-evaluates this extension module fresh for the new
|
|
9
|
+
* session (jiti moduleCache:false), so a module-level stash set in withSession
|
|
10
|
+
* would be lost before the new session handles the app's session_sync. The
|
|
11
|
+
* marker is keyed by the new session id and lives in the session dir, so it
|
|
12
|
+
* survives the re-eval (and a process restart) and is unambiguous.
|
|
13
|
+
*
|
|
14
|
+
* Consumed ONCE (take = read + unlink): the app navigates on the first sync;
|
|
15
|
+
* leaving it would re-fire the jump on every reconnect.
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
function _linkPath(sessionDir, sessionId) {
|
|
20
|
+
return join(sessionDir, `.unbien-fork-${sessionId}.json`);
|
|
21
|
+
}
|
|
22
|
+
/** Record that `sessionId` was born from the app fork request `req`. Best-effort. */
|
|
23
|
+
export function writeForkLink(sessionDir, sessionId, req) {
|
|
24
|
+
try {
|
|
25
|
+
writeFileSync(_linkPath(sessionDir, sessionId), JSON.stringify({ req, ts: Date.now() }));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
/* best-effort — a missing link just means no auto-nav */
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Read + delete the fork request id for `sessionId`, or undefined when none. */
|
|
32
|
+
export function takeForkLink(sessionDir, sessionId) {
|
|
33
|
+
const path = _linkPath(sessionDir, sessionId);
|
|
34
|
+
try {
|
|
35
|
+
if (!existsSync(path))
|
|
36
|
+
return undefined;
|
|
37
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
38
|
+
unlinkSync(path);
|
|
39
|
+
return typeof parsed.req === "string" ? parsed.req : undefined;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=fork_link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fork_link.js","sourceRoot":"","sources":["../../src/commands/fork_link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,SAAS,SAAS,CAAC,UAAkB,EAAE,SAAiB;IACtD,OAAO,IAAI,CAAC,UAAU,EAAE,gBAAgB,SAAS,OAAO,CAAC,CAAA;AAC3D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,aAAa,CAC3B,UAAkB,EAClB,SAAiB,EACjB,GAAW;IAEX,IAAI,CAAC;QACH,aAAa,CACX,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CACxC,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,SAAiB;IAEjB,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAC7C,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,SAAS,CAAA;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAsB,CAAA;QAC1E,UAAU,CAAC,IAAI,CAAC,CAAA;QAChB,OAAO,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/unbien` housekeeping commands: service install/uninstall, the
|
|
3
|
+
* agent-network skill deploy, extension-dir/skill-path resolution, and the
|
|
4
|
+
* `unbien claude` CLI launcher.
|
|
5
|
+
*
|
|
6
|
+
* None of these touch index.ts module state, so they take no CommandDeps —
|
|
7
|
+
* everything they use is imported from pi-independent modules. Carved out
|
|
8
|
+
* of index.ts (phase 1 of the index.ts carve-up).
|
|
9
|
+
*
|
|
10
|
+
* NOTE: this file lives one directory deeper than index.ts used to, so the
|
|
11
|
+
* import.meta.url-based path math (extension dir, packaged skill, mesh
|
|
12
|
+
* server) climbs one extra level — behavior is otherwise identical.
|
|
13
|
+
*/
|
|
14
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
15
|
+
/**
|
|
16
|
+
* `linkCli` controls whether we symlink `un-bien` into `~/.local/bin/`. The
|
|
17
|
+
* slash-command path passes `true` (user is inside Pi's TUI — they installed
|
|
18
|
+
* via `pi install npm:un-bien` and need us to expose the CLI for them). The
|
|
19
|
+
* standalone-CLI path passes `false` because the user is already running our
|
|
20
|
+
* binary from PATH (they did `npm install -g un-bien`), so re-linking would
|
|
21
|
+
* point their `un-bien` at the Pi-extension copy and diverge on upgrades.
|
|
22
|
+
*/
|
|
23
|
+
/** Returns true on success, false when install failed (so the standalone CLI
|
|
24
|
+
* can exit non-zero — e.g. the Cockpit / CI detect failure by exit code).
|
|
25
|
+
* We do NOT process.exit here: this also runs inside the Pi TUI, where exiting
|
|
26
|
+
* would kill the session. */
|
|
27
|
+
export declare function _cmdInstall(ctx: Pick<ExtensionContext, "ui">, opts?: {
|
|
28
|
+
linkCli?: boolean;
|
|
29
|
+
}): boolean;
|
|
30
|
+
export declare function _cmdUninstall(ctx: Pick<ExtensionContext, "ui">, opts?: {
|
|
31
|
+
linkCli?: boolean;
|
|
32
|
+
}): void;
|
|
33
|
+
export declare function _deployAgentNetworkSkill(): void;
|
|
34
|
+
export declare function _cmdClaudeCli(args: string[]): Promise<void>;
|