@geohar/unbien-cli 0.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.
Files changed (50) hide show
  1. package/README.md +72 -0
  2. package/dist/client.d.ts +89 -0
  3. package/dist/client.js +210 -0
  4. package/dist/client.js.map +1 -0
  5. package/dist/commands.d.ts +59 -0
  6. package/dist/commands.js +273 -0
  7. package/dist/commands.js.map +1 -0
  8. package/dist/connect.d.ts +2 -0
  9. package/dist/connect.js +475 -0
  10. package/dist/connect.js.map +1 -0
  11. package/dist/identity.d.ts +2 -0
  12. package/dist/identity.js +30 -0
  13. package/dist/identity.js.map +1 -0
  14. package/dist/invite.d.ts +10 -0
  15. package/dist/invite.js +28 -0
  16. package/dist/invite.js.map +1 -0
  17. package/dist/main.d.ts +3 -0
  18. package/dist/main.js +20 -0
  19. package/dist/main.js.map +1 -0
  20. package/dist/panels.d.ts +40 -0
  21. package/dist/panels.js +155 -0
  22. package/dist/panels.js.map +1 -0
  23. package/dist/picker.d.ts +6 -0
  24. package/dist/picker.js +95 -0
  25. package/dist/picker.js.map +1 -0
  26. package/dist/plan.d.ts +30 -0
  27. package/dist/plan.js +132 -0
  28. package/dist/plan.js.map +1 -0
  29. package/dist/reduce.d.ts +45 -0
  30. package/dist/reduce.js +123 -0
  31. package/dist/reduce.js.map +1 -0
  32. package/dist/render.d.ts +13 -0
  33. package/dist/render.js +91 -0
  34. package/dist/render.js.map +1 -0
  35. package/dist/replay.d.ts +2 -0
  36. package/dist/replay.js +57 -0
  37. package/dist/replay.js.map +1 -0
  38. package/dist/settings.d.ts +27 -0
  39. package/dist/settings.js +31 -0
  40. package/dist/settings.js.map +1 -0
  41. package/dist/store.d.ts +13 -0
  42. package/dist/store.js +20 -0
  43. package/dist/store.js.map +1 -0
  44. package/dist/theme.d.ts +7 -0
  45. package/dist/theme.js +110 -0
  46. package/dist/theme.js.map +1 -0
  47. package/dist/tui.d.ts +78 -0
  48. package/dist/tui.js +265 -0
  49. package/dist/tui.js.map +1 -0
  50. package/package.json +58 -0
@@ -0,0 +1,475 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Attach to a live pi session over the relay and drive it: transcript in,
4
+ * prompts out. Rendering is the same reducer + pi components the replay
5
+ * prototype uses, so a live turn and a fixture replay draw identically.
6
+ */
7
+ import { createInterface } from "node:readline";
8
+ import { createInterface as createPromptInterface } from "node:readline/promises";
9
+ import { SessionClient } from "./client.js";
10
+ import { applyTheme, availableThemes } from "./theme.js";
11
+ import { loadOrCreateIdentity } from "./identity.js";
12
+ import { parseInvite } from "./invite.js";
13
+ import { findCommand, } from "./commands.js";
14
+ import { PanelStore } from "./panels.js";
15
+ import { pickSession } from "./picker.js";
16
+ import { entriesToEnvelopes, reduce } from "./reduce.js";
17
+ import { Shell } from "./tui.js";
18
+ import { renderAgentsPanel, renderPlanPanel, summariseAgents, summarisePlan, } from "./panels.js";
19
+ import { renderStreaming, renderThinking, renderTranscript } from "./render.js";
20
+ import { loadSettings, saveSettings, settingsPath } from "./settings.js";
21
+ import { loadPeers, rememberPeer } from "./store.js";
22
+ function parseArgs(argv) {
23
+ const positional = [];
24
+ const flags = new Map();
25
+ for (let i = 0; i < argv.length; i++) {
26
+ const arg = argv[i];
27
+ if (arg === "--list")
28
+ flags.set("list", "1");
29
+ else if (arg === "--list-themes")
30
+ flags.set("list-themes", "1");
31
+ else if (arg === "--debug")
32
+ flags.set("debug", "1");
33
+ else if (arg.startsWith("--"))
34
+ flags.set(arg.slice(2), argv[++i] ?? "");
35
+ else
36
+ positional.push(arg);
37
+ }
38
+ return { target: positional[0], flags };
39
+ }
40
+ const { target, flags } = parseArgs(process.argv.slice(2));
41
+ if (flags.has("list-themes")) {
42
+ console.log((await availableThemes()).join("\n"));
43
+ process.exit(0);
44
+ }
45
+ /**
46
+ * Either a fresh `unbien://pair?…` invite, or a machine we already paired with
47
+ * — pairing is machine-level, so a remembered peer needs no token.
48
+ */
49
+ function resolveTarget() {
50
+ const explicitRelay = flags.get("relay");
51
+ if (target?.startsWith("unbien://")) {
52
+ const relayUrl = explicitRelay ?? process.env["UNBIEN_RELAY"];
53
+ if (!relayUrl)
54
+ return null;
55
+ return { invite: parseInvite(target), relayUrl };
56
+ }
57
+ const peers = loadPeers();
58
+ const peer = target
59
+ ? peers.find((p) => p.epk.startsWith(target) || p.name === target)
60
+ : peers[peers.length - 1];
61
+ if (!peer)
62
+ return null;
63
+ return {
64
+ // A remembered peer has no token; `room` is chosen after listing.
65
+ invite: { token: "", epk: peer.epk, roomId: "main" },
66
+ // A pairing is only valid on the relay it was made on, so the peer's own
67
+ // relay beats the ambient env var — which names whatever this shell last
68
+ // pointed a pi at, not where this peer lives.
69
+ relayUrl: explicitRelay ?? peer.relayUrl,
70
+ };
71
+ }
72
+ const resolved = resolveTarget();
73
+ if (!resolved) {
74
+ console.error("usage:\n" +
75
+ " unbien connect '<unbien://pair?...>' # first run: pair with a machine\n" +
76
+ " unbien connect [<epk-prefix>] --list # list that machine's sessions\n" +
77
+ " unbien connect [<epk-prefix>] --session <id> # pi session id\n" +
78
+ " unbien connect [<epk-prefix>] --session-name <name>\n" +
79
+ "options: --relay <url> (default $UNBIEN_RELAY) --name <device>\n" +
80
+ " --theme <name> (default: your pi theme setting) --list-themes");
81
+ if (loadPeers().length === 0) {
82
+ console.error("\nno paired machines yet — run `/unbien pair` in a session.");
83
+ }
84
+ process.exit(1);
85
+ }
86
+ /**
87
+ * Registered BEFORE any async work: if startup stalls (relay, rooms, attach)
88
+ * there is no shell yet to handle keys, and raw mode left on by the picker
89
+ * suppresses the default Ctrl-C. Without this the process is unkillable from
90
+ * the terminal it is running in.
91
+ */
92
+ // Declared BEFORE hardQuit: a SIGINT during startup runs it while the rest of
93
+ // this module is still initialising, and a `let` read in its temporal dead
94
+ // zone would throw instead of exiting.
95
+ let shell = null;
96
+ let quitting = false;
97
+ function hardQuit(reason) {
98
+ if (quitting)
99
+ process.exit(130);
100
+ quitting = true;
101
+ // Once the shell exists, pi owns the terminal — let its teardown run rather
102
+ // than restoring stdin by hand (which loses the original raw-mode state).
103
+ if (shell) {
104
+ shell.quit();
105
+ return;
106
+ }
107
+ try {
108
+ if (process.stdin.isTTY)
109
+ process.stdin.setRawMode(false);
110
+ }
111
+ catch {
112
+ /* stdin already torn down */
113
+ }
114
+ process.stderr.write(`\n[exit] ${reason}\n`);
115
+ process.exit(130);
116
+ }
117
+ process.on("SIGINT", () => hardQuit("interrupted"));
118
+ process.on("SIGTERM", () => hardQuit("terminated"));
119
+ const debug = flags.has("debug");
120
+ function trace(direction, detail) {
121
+ if (debug)
122
+ process.stderr.write(`[${direction}] ${detail}\n`);
123
+ }
124
+ const settings = loadSettings();
125
+ const appliedTheme = await applyTheme(flags.get("theme") ?? settings.theme);
126
+ if (appliedTheme.startsWith("dark ("))
127
+ console.error(`[theme] ${appliedTheme}`);
128
+ const { invite, relayUrl } = resolved;
129
+ const client = new SessionClient(relayUrl, loadOrCreateIdentity(), invite);
130
+ const width = process.stdout.columns ?? 100;
131
+ /** Frames seen so far; the transcript is re-reduced from the whole stream. */
132
+ const seen = [];
133
+ const panels = new PanelStore();
134
+ /** The walked session log, kept so commands can derive forks and turns. */
135
+ let walkedEntries = [];
136
+ let drawn = 0;
137
+ let cwd = process.cwd();
138
+ function emit(lines) {
139
+ if (shell)
140
+ shell.print(lines);
141
+ else
142
+ for (const line of lines)
143
+ console.log(line);
144
+ }
145
+ function draw() {
146
+ const lines = renderTranscript(reduce(seen), width, cwd, !settings.showThinking);
147
+ if (shell) {
148
+ // The shell owns the screen, so hand it the whole transcript: history
149
+ // replay re-reduces from scratch and would otherwise duplicate rows.
150
+ shell.setTranscript(lines);
151
+ }
152
+ else {
153
+ for (const line of lines.slice(drawn))
154
+ console.log(line);
155
+ }
156
+ drawn = lines.length;
157
+ }
158
+ /** Assistant text accumulated from deltas while a turn is in flight. */
159
+ let streaming = "";
160
+ /** Reasoning accumulated separately: it is replaced, never merged into text. */
161
+ let reasoning = "";
162
+ function paintLive() {
163
+ if (!shell)
164
+ return;
165
+ const parts = [];
166
+ if (settings.streamThinking && reasoning) {
167
+ parts.push(...renderThinking(reasoning, width));
168
+ }
169
+ if (streaming)
170
+ parts.push(...renderStreaming(streaming, width));
171
+ shell.setLive(parts);
172
+ }
173
+ function applyStreaming(rpc) {
174
+ if (!shell)
175
+ return;
176
+ const event = rpc.assistantMessageEvent;
177
+ switch (rpc.type) {
178
+ case "message_start":
179
+ streaming = "";
180
+ reasoning = "";
181
+ shell.setLive([]);
182
+ return;
183
+ case "message_update":
184
+ if (event?.type === "text_delta" && event.delta) {
185
+ streaming += event.delta;
186
+ paintLive();
187
+ }
188
+ else if (event?.type === "thinking_delta" && event.delta) {
189
+ reasoning += event.delta;
190
+ // Reasoning ends when the visible answer starts, so only paint while
191
+ // no text has arrived — otherwise it lingers above the real reply.
192
+ if (!streaming)
193
+ paintLive();
194
+ }
195
+ return;
196
+ case "message_end":
197
+ // draw() is about to put the settled message in the transcript.
198
+ streaming = "";
199
+ reasoning = "";
200
+ shell.setLive([]);
201
+ return;
202
+ }
203
+ }
204
+ /**
205
+ * Frames that can change the SETTLED transcript. Everything else (streaming
206
+ * deltas, partial tool output, turn lifecycle) only moves the live region or
207
+ * the spinner — redrawing the whole transcript for those means re-reducing and
208
+ * re-rendering thousands of entries hundreds of times per turn, which starves
209
+ * the event loop and makes the spinner stutter.
210
+ */
211
+ const TRANSCRIPT_FRAMES = new Set([
212
+ "message_end",
213
+ "tool_execution_start",
214
+ "tool_execution_end",
215
+ "compaction_end",
216
+ "extension_ui_request",
217
+ "entry_appended",
218
+ ]);
219
+ /**
220
+ * The pinned panel widgets, re-rendered whenever a panel arrives or a mode
221
+ * changes — mirroring pi-plan's widget, which lives above the composer and has
222
+ * hidden / collapsed / expanded states.
223
+ */
224
+ function paintWidgets() {
225
+ if (!shell)
226
+ return;
227
+ const lines = [];
228
+ const plan = panels.get("plan");
229
+ const agents = panels.get("subagents");
230
+ if (settings.planMode === "expanded") {
231
+ lines.push(...renderPlanPanel(plan, {
232
+ showDone: settings.planShowDone,
233
+ showContext: settings.planShowContext,
234
+ maxRows: settings.planMaxRows,
235
+ }));
236
+ }
237
+ else if (settings.planMode === "collapsed") {
238
+ lines.push(...summarisePlan(plan));
239
+ }
240
+ if (settings.subagentsMode === "expanded") {
241
+ if (lines.length > 0)
242
+ lines.push("");
243
+ lines.push(...renderAgentsPanel(agents));
244
+ }
245
+ else if (settings.subagentsMode === "collapsed") {
246
+ lines.push(...summariseAgents(agents));
247
+ }
248
+ shell.setWidgets(lines);
249
+ }
250
+ client.on("envelope", (env) => {
251
+ const kind = env.rpc ? "rpc" : env.evt ? "evt" : "ub";
252
+ const inner = (env.rpc ?? env.evt ?? env.ub);
253
+ trace("in", `${kind} ${inner?.type ?? "?"}`);
254
+ // Panels are ephemeral view state, not transcript.
255
+ if (panels.apply(env)) {
256
+ paintWidgets();
257
+ return;
258
+ }
259
+ const rpc = env.rpc;
260
+ if (rpc)
261
+ applyStreaming(rpc);
262
+ seen.push(env);
263
+ if (!rpc || TRANSCRIPT_FRAMES.has(String(rpc.type)))
264
+ draw();
265
+ // Busy state comes from the turn lifecycle; the running tool's name makes the
266
+ // indicator say what it is waiting on rather than just that it is waiting.
267
+ if (rpc?.type === "turn_start" || rpc?.type === "agent_start") {
268
+ shell?.setStatus({ working: true, activity: "thinking" });
269
+ }
270
+ else if (rpc?.type === "tool_execution_start") {
271
+ shell?.setStatus({
272
+ working: true,
273
+ activity: String(rpc.toolName ?? "tool"),
274
+ });
275
+ }
276
+ else if (rpc?.type === "tool_execution_end") {
277
+ shell?.setStatus({ working: true, activity: "thinking" });
278
+ }
279
+ else if (rpc?.type === "turn_end" ||
280
+ rpc?.type === "agent_end" ||
281
+ rpc?.type === "agent_settled") {
282
+ shell?.setStatus({ working: false, activity: undefined });
283
+ }
284
+ });
285
+ client.on("relayControl", (frame) => {
286
+ trace("relay", String(frame.type ?? Object.keys(frame).join(",")));
287
+ });
288
+ client.on("control", (frame) => {
289
+ trace("in", `control ${String(frame.type)}`);
290
+ if (frame.type === "pair_error") {
291
+ console.error(`[pair failed] ${String(frame.message ?? frame.code ?? "")}`);
292
+ process.exit(1);
293
+ }
294
+ if (frame.type === "error" && frame.code === "unknown_peer") {
295
+ console.error("[not paired] run `/unbien pair` and pass the new invite.");
296
+ process.exit(1);
297
+ }
298
+ });
299
+ client.on("close", () => {
300
+ console.error("[relay] connection closed");
301
+ process.exit(1);
302
+ });
303
+ function describeSession(room, index) {
304
+ const label = room.name ?? room.sessionId?.slice(0, 8) ?? room.room_id;
305
+ const child = room.parent ? " (subagent)" : "";
306
+ const id = room.sessionId?.slice(0, 8) ?? room.room_id;
307
+ return ` ${index + 1}. ${label}${child}\n ${room.cwd ?? "?"} [${id}]`;
308
+ }
309
+ /** `--session` selects by IDENTITY: the pi sessionId (prefix ok) or room id. */
310
+ function matchesSessionId(room, id) {
311
+ return room.sessionId?.startsWith(id) === true || room.room_id === id;
312
+ }
313
+ async function pickRoom(rooms) {
314
+ if (rooms.length === 1)
315
+ return rooms[0];
316
+ // A non-TTY stdin (piped input, CI) can't drive a highlight list.
317
+ if (!process.stdin.isTTY) {
318
+ console.error("\nSessions on this machine:\n");
319
+ rooms.forEach((room, i) => console.error(describeSession(room, i)));
320
+ const rl = createPromptInterface({
321
+ input: process.stdin,
322
+ output: process.stderr,
323
+ });
324
+ const answer = await rl.question("\nattach to # ");
325
+ rl.close();
326
+ return rooms[Number(answer.trim()) - 1] ?? null;
327
+ }
328
+ return pickSession(rooms);
329
+ }
330
+ try {
331
+ await client.connect();
332
+ }
333
+ catch (err) {
334
+ console.error(`[relay] could not connect to ${relayUrl}: ${String(err)}`);
335
+ process.exit(1);
336
+ }
337
+ // A token means this is a first pairing; a remembered machine skips straight
338
+ // to routing, since the extension auto-attaches any peer it already trusts.
339
+ if (invite.token) {
340
+ client.pair(flags.get("name") ?? "unbien-proxy");
341
+ rememberPeer({
342
+ epk: invite.epk,
343
+ relayUrl,
344
+ name: flags.get("name") ?? "unbien-proxy",
345
+ pairedAt: new Date().toISOString(),
346
+ });
347
+ console.error("[paired] machine remembered — future runs need no token");
348
+ }
349
+ const rooms = await client.listRooms();
350
+ if (rooms.length === 0) {
351
+ console.error("[sessions] none open — is a pi running on that machine?");
352
+ process.exit(1);
353
+ }
354
+ if (flags.has("list")) {
355
+ console.error("Sessions on this machine:\n");
356
+ rooms.forEach((room, i) => console.error(describeSession(room, i)));
357
+ process.exit(0);
358
+ }
359
+ const wantedId = flags.get("session");
360
+ const wantedName = flags.get("session-name");
361
+ let chosen;
362
+ if (wantedId) {
363
+ chosen = rooms.find((r) => matchesSessionId(r, wantedId)) ?? null;
364
+ if (!chosen)
365
+ console.error(`[sessions] no session with id "${wantedId}"`);
366
+ }
367
+ else if (wantedName) {
368
+ // Names are user-set and NOT unique, so an ambiguous one must not silently
369
+ // pick a session — that would attach to an arbitrary agent.
370
+ const named = rooms.filter((r) => r.name === wantedName);
371
+ if (named.length > 1) {
372
+ console.error(`[sessions] "${wantedName}" is ambiguous — use --session:`);
373
+ named.forEach((room, i) => console.error(describeSession(room, i)));
374
+ process.exit(1);
375
+ }
376
+ chosen = named[0] ?? null;
377
+ if (!chosen)
378
+ console.error(`[sessions] no session named "${wantedName}"`);
379
+ }
380
+ else {
381
+ chosen = await pickRoom(rooms);
382
+ }
383
+ if (!chosen)
384
+ process.exit(1);
385
+ client.room = chosen.room_id;
386
+ cwd = chosen.cwd ?? cwd;
387
+ console.error(`[attached] ${chosen.name ?? chosen.room_id} — ${chosen.cwd ?? "?"}\n` +
388
+ "type a prompt, /help for commands, Ctrl-C to exit\n");
389
+ // The first frame to a trusted peer is what triggers the extension's attach.
390
+ client.requestSync();
391
+ function commandContext() {
392
+ return {
393
+ client,
394
+ panels,
395
+ entries: () => walkedEntries,
396
+ settings,
397
+ saveSettings: () => {
398
+ saveSettings(settings);
399
+ paintWidgets();
400
+ },
401
+ settingsPath: settingsPath(),
402
+ print: emit,
403
+ quit: () => (shell ? shell.quit() : process.exit(0)),
404
+ choose: (title, items) => shell ? shell.choose(title, items) : (items[0] ?? null),
405
+ chooseAction: (title, items, hint, keys) => shell
406
+ ? shell.chooseAction(title, items, hint, keys)
407
+ : Promise.resolve(null),
408
+ };
409
+ }
410
+ async function submit(text) {
411
+ const found = findCommand(text);
412
+ if (found) {
413
+ try {
414
+ await found.command.run(commandContext(), found.args);
415
+ }
416
+ catch (err) {
417
+ emit([` /${found.command.name} failed: ${String(err)}`]);
418
+ }
419
+ return;
420
+ }
421
+ if (text.startsWith("/steer "))
422
+ client.steer(text.slice(7));
423
+ else if (text.startsWith("/"))
424
+ emit([` unknown command: ${text}`]);
425
+ else {
426
+ trace("out", `prompt room=${client.room} chars=${text.length}`);
427
+ client.prompt(text);
428
+ }
429
+ }
430
+ /**
431
+ * History is pulled AFTER the prompt box is up. `get_entries` waits on the
432
+ * extension, and blocking the shell on it left the terminal blank for as long
433
+ * as that took — with keystrokes going nowhere.
434
+ */
435
+ async function loadHistory() {
436
+ const entries = await client.getEntries();
437
+ walkedEntries = entries;
438
+ if (entries.length === 0)
439
+ return;
440
+ // History is the AUTHORITATIVE prefix: it goes before anything that arrived
441
+ // live while we were fetching, and the transcript is rebuilt in log order.
442
+ seen.unshift(...entriesToEnvelopes(entries));
443
+ drawn = 0;
444
+ draw();
445
+ }
446
+ if (process.stdin.isTTY) {
447
+ shell = new Shell({ session: chosen.name ?? chosen.room_id, cwd: chosen.cwd ?? cwd }, (text) => void submit(text), () => {
448
+ // The relay socket is a live handle; leaving it open is what keeps the
449
+ // process alive after the TUI has gone.
450
+ try {
451
+ client.close();
452
+ }
453
+ catch {
454
+ /* already down */
455
+ }
456
+ process.exit(0);
457
+ });
458
+ shell.start();
459
+ // The footer's model comes from pi's own state, not from room_meta.
460
+ client
461
+ .request("get_state")
462
+ .then((state) => shell?.setStatus({ model: state?.model?.id }))
463
+ .catch(() => { });
464
+ void loadHistory();
465
+ }
466
+ else {
467
+ await loadHistory();
468
+ const rl = createInterface({ input: process.stdin, terminal: false });
469
+ for await (const line of rl) {
470
+ const text = line.trim();
471
+ if (text)
472
+ await submit(text);
473
+ }
474
+ }
475
+ //# sourceMappingURL=connect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type Ed25519Keypair } from "@geohar/un-bien/client";
2
+ export declare function loadOrCreateIdentity(path?: string): Ed25519Keypair;
@@ -0,0 +1,30 @@
1
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { dirname, join } from "node:path";
4
+ import { ed25519KeypairFromSeed, generateEd25519Keypair, } from "@geohar/un-bien/client";
5
+ /**
6
+ * This client's own owner identity. It is a SEPARATE owner device from the
7
+ * phone — it pairs on its own token and is revoked on its own, so losing the
8
+ * laptop never implies re-pairing the phone.
9
+ */
10
+ const IDENTITY_PATH = join(homedir(), ".local", "state", "un-bien", "proxy-identity.json");
11
+ export function loadOrCreateIdentity(path = IDENTITY_PATH) {
12
+ try {
13
+ const stored = JSON.parse(readFileSync(path, "utf8"));
14
+ if (stored.seed) {
15
+ return ed25519KeypairFromSeed(Buffer.from(stored.seed, "base64"));
16
+ }
17
+ }
18
+ catch {
19
+ // No identity yet (or an unreadable one) — mint a fresh one below.
20
+ }
21
+ const keypair = generateEd25519Keypair();
22
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
23
+ writeFileSync(path, JSON.stringify({
24
+ seed: Buffer.from(keypair.secretKey.slice(0, 32)).toString("base64"),
25
+ publicKey: Buffer.from(keypair.publicKey).toString("base64"),
26
+ }), { mode: 0o600 });
27
+ chmodSync(path, 0o600);
28
+ return keypair;
29
+ }
30
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,wBAAwB,CAAA;AAE/B;;;;GAIG;AACH,MAAM,aAAa,GAAG,IAAI,CACxB,OAAO,EAAE,EACT,QAAQ,EACR,OAAO,EACP,SAAS,EACT,qBAAqB,CACtB,CAAA;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAI,GAAG,aAAa;IACvD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAsB,CAAA;QAC1E,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;QACnE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;IACrE,CAAC;IAED,MAAM,OAAO,GAAG,sBAAsB,EAAE,CAAA;IACxC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC1D,aAAa,CACX,IAAI,EACJ,IAAI,CAAC,SAAS,CAAC;QACb,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACpE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;KAC7D,CAAC,EACF,EAAE,IAAI,EAAE,KAAK,EAAE,CAChB,CAAA;IACD,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACtB,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /** A parsed `unbien://pair?t=…&epk=…&n=…&rm=…` invite from `/unbien pair`. */
2
+ export interface PairingInvite {
3
+ /** Single-use pairing token — opaque, echoed verbatim in `pair_request`. */
4
+ token: string;
5
+ /** Destination pi's Ed25519 public key; the outer envelope's routing `peer`. */
6
+ epk: string;
7
+ sessionName?: string;
8
+ roomId: string;
9
+ }
10
+ export declare function parseInvite(raw: string): PairingInvite;
package/dist/invite.js ADDED
@@ -0,0 +1,28 @@
1
+ import { canonicalizeEd25519PublicKey } from "@geohar/un-bien/client";
2
+ export function parseInvite(raw) {
3
+ let url;
4
+ try {
5
+ url = new URL(raw.trim());
6
+ }
7
+ catch {
8
+ throw new Error(`not a pairing URI: ${raw}`);
9
+ }
10
+ if (url.protocol !== "unbien:" || url.host !== "pair") {
11
+ throw new Error(`not a pairing URI: ${raw}`);
12
+ }
13
+ const token = url.searchParams.get("t");
14
+ const epk = url.searchParams.get("epk");
15
+ if (!token)
16
+ throw new Error("pairing URI has no token (t)");
17
+ if (!epk)
18
+ throw new Error("pairing URI has no peer key (epk)");
19
+ return {
20
+ token,
21
+ // The QR carries base64url; the relay routes by standard padded base64, so
22
+ // canonicalize or every (peer, room) lookup misses.
23
+ epk: canonicalizeEd25519PublicKey(epk) ?? epk,
24
+ sessionName: url.searchParams.get("n") ?? undefined,
25
+ roomId: url.searchParams.get("rm") ?? "main",
26
+ };
27
+ }
28
+ //# sourceMappingURL=invite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.js","sourceRoot":"","sources":["../src/invite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAA;AAYrE,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,GAAQ,CAAA;IACZ,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAA;IAC9C,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,EAAE,CAAC,CAAA;IAC9C,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACvC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;IACvC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAA;IAC3D,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAA;IAE9D,OAAO;QACL,KAAK;QACL,2EAA2E;QAC3E,oDAAoD;QACpD,GAAG,EAAE,4BAA4B,CAAC,GAAG,CAAC,IAAI,GAAG;QAC7C,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,SAAS;QACnD,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM;KAC7C,CAAA;AACH,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ /** Single front door: `unbien <command>`. */
3
+ export {};
package/dist/main.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ /** Single front door: `unbien <command>`. */
3
+ const COMMANDS = new Map([
4
+ ["connect", () => import("./connect.js")],
5
+ ["replay", () => import("./replay.js")],
6
+ ]);
7
+ const [command] = process.argv.slice(2);
8
+ const load = command ? COMMANDS.get(command) : undefined;
9
+ if (!load) {
10
+ console.error("usage: unbien <command> [options]\n\n" +
11
+ " connect attach to a live pi session over the relay\n" +
12
+ " replay render a captured envelope stream from a file\n\n" +
13
+ "run `unbien <command>` with no arguments for its options.");
14
+ process.exit(command ? 1 : 0);
15
+ }
16
+ // The subcommands parse `process.argv.slice(2)` themselves, so drop the verb.
17
+ process.argv.splice(2, 1);
18
+ await load();
19
+ export {};
20
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,6CAA6C;AAE7C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC;IACvB,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;CACxC,CAAC,CAAA;AAEF,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AACvC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;AAExD,IAAI,CAAC,IAAI,EAAE,CAAC;IACV,OAAO,CAAC,KAAK,CACX,uCAAuC;QACrC,0DAA0D;QAC1D,+DAA+D;QAC/D,2DAA2D,CAC9D,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC/B,CAAC;AAED,8EAA8E;AAC9E,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AACzB,MAAM,IAAI,EAAE,CAAA"}
@@ -0,0 +1,40 @@
1
+ import type { EnvelopeMessage } from "./reduce.js";
2
+ export interface PanelItem {
3
+ id: string;
4
+ kind: string;
5
+ title: string;
6
+ status: string | null;
7
+ deps?: string[];
8
+ tainted?: boolean;
9
+ }
10
+ export interface Panel {
11
+ key: string;
12
+ title: string;
13
+ items: PanelItem[];
14
+ }
15
+ export declare class PanelStore {
16
+ private readonly panels;
17
+ /** Returns true when the envelope was a panel update. */
18
+ apply(env: EnvelopeMessage): boolean;
19
+ get(key: string): Panel | undefined;
20
+ keys(): string[];
21
+ }
22
+ /**
23
+ * The plan as the app shows it: dependency waves, an `Available now` group you
24
+ * can pick up immediately, and a trailing `Done` — the layering pi-plan's own
25
+ * widget conveys by order, surfaced here as titled sections.
26
+ */
27
+ export interface PlanViewOptions {
28
+ /** Include finished items. */
29
+ showDone?: boolean;
30
+ /** Include non-plan kinds (design / note context). */
31
+ showContext?: boolean;
32
+ /** Cap on rendered rows before a "…N more" trailer. */
33
+ maxRows?: number;
34
+ }
35
+ export declare function renderPlanPanel(panel: Panel | undefined, options?: PlanViewOptions): string[];
36
+ /** pi-plan's collapsed form: one line of counts, and how to expand. */
37
+ export declare function summarisePlan(panel: Panel | undefined): string[];
38
+ export declare function summariseAgents(panel: Panel | undefined): string[];
39
+ /** Subagents chronologically, with type badge — the app's agents panel. */
40
+ export declare function renderAgentsPanel(panel: Panel | undefined): string[];