@geohar/un-bien 0.9.0 → 0.16.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 (140) hide show
  1. package/README.md +100 -131
  2. package/dist/actions/handlers.js.map +1 -1
  3. package/dist/actions/registry.js.map +1 -1
  4. package/dist/bin/launcher.js.map +1 -1
  5. package/dist/client.d.ts +15 -0
  6. package/dist/client.js +15 -0
  7. package/dist/client.js.map +1 -0
  8. package/dist/commands/deps.d.ts +156 -0
  9. package/dist/commands/deps.js +2 -0
  10. package/dist/commands/deps.js.map +1 -0
  11. package/dist/commands/fork_link.d.ts +4 -0
  12. package/dist/commands/fork_link.js +45 -0
  13. package/dist/commands/fork_link.js.map +1 -0
  14. package/dist/commands/housekeeping.d.ts +34 -0
  15. package/dist/commands/housekeeping.js +275 -0
  16. package/dist/commands/housekeeping.js.map +1 -0
  17. package/dist/commands/info.d.ts +43 -0
  18. package/dist/commands/info.js +127 -0
  19. package/dist/commands/info.js.map +1 -0
  20. package/dist/commands/lifecycle.d.ts +45 -0
  21. package/dist/commands/lifecycle.js +708 -0
  22. package/dist/commands/lifecycle.js.map +1 -0
  23. package/dist/commands/pairing.d.ts +26 -0
  24. package/dist/commands/pairing.js +167 -0
  25. package/dist/commands/pairing.js.map +1 -0
  26. package/dist/commands/register.d.ts +12 -0
  27. package/dist/commands/register.js +255 -0
  28. package/dist/commands/register.js.map +1 -0
  29. package/dist/commands/relay.d.ts +28 -0
  30. package/dist/commands/relay.js +81 -0
  31. package/dist/commands/relay.js.map +1 -0
  32. package/dist/commands/session_ops.d.ts +52 -0
  33. package/dist/commands/session_ops.js +75 -0
  34. package/dist/commands/session_ops.js.map +1 -0
  35. package/dist/config.d.ts +11 -1
  36. package/dist/config.js.map +1 -1
  37. package/dist/daemon/install.d.ts +6 -5
  38. package/dist/daemon/install.js +15 -5
  39. package/dist/daemon/install.js.map +1 -1
  40. package/dist/enrich_tool_args.js.map +1 -1
  41. package/dist/extension_ui_bridge.js.map +1 -1
  42. package/dist/image_codec.js.map +1 -1
  43. package/dist/index.d.ts +32 -101
  44. package/dist/index.js +852 -2872
  45. package/dist/index.js.map +1 -1
  46. package/dist/launch.d.ts +14 -1
  47. package/dist/launch.js +55 -5
  48. package/dist/launch.js.map +1 -1
  49. package/dist/launcher/launcher.js +48 -6
  50. package/dist/launcher/launcher.js.map +1 -1
  51. package/dist/mcp/mesh_result.js.map +1 -1
  52. package/dist/mcp/mesh_server.js.map +1 -1
  53. package/dist/mesh/canonical.js +1 -1
  54. package/dist/mesh/canonical.js.map +1 -1
  55. package/dist/mesh/client.js.map +1 -1
  56. package/dist/mesh/encoding.js.map +1 -1
  57. package/dist/mesh/self_revoke.js.map +1 -1
  58. package/dist/mesh/siblings.js.map +1 -1
  59. package/dist/mesh/verify.js +1 -1
  60. package/dist/mesh/verify.js.map +1 -1
  61. package/dist/pairing/crypto.js +0 -1
  62. package/dist/pairing/crypto.js.map +1 -1
  63. package/dist/pairing/peer_trust.js.map +1 -1
  64. package/dist/pairing/qr.js.map +1 -1
  65. package/dist/pairing/storage.d.ts +7 -0
  66. package/dist/pairing/storage.js +22 -3
  67. package/dist/pairing/storage.js.map +1 -1
  68. package/dist/panel_bridge.js +1 -0
  69. package/dist/panel_bridge.js.map +1 -1
  70. package/dist/paths.d.ts +22 -8
  71. package/dist/paths.js +37 -10
  72. package/dist/paths.js.map +1 -1
  73. package/dist/protocol/codec.js.map +1 -1
  74. package/dist/rooms.js +1 -4
  75. package/dist/rooms.js.map +1 -1
  76. package/dist/session/bridge.js.map +1 -1
  77. package/dist/session/broker.js.map +1 -1
  78. package/dist/session/broker_remote.js.map +1 -1
  79. package/dist/session/capabilities.d.ts +11 -0
  80. package/dist/session/capabilities.js +35 -0
  81. package/dist/session/capabilities.js.map +1 -0
  82. package/dist/session/cwd_lock.js +3 -3
  83. package/dist/session/cwd_lock.js.map +1 -1
  84. package/dist/session/debug_log.js +13 -3
  85. package/dist/session/debug_log.js.map +1 -1
  86. package/dist/session/envelope.js.map +1 -1
  87. package/dist/session/global_config.d.ts +1 -1
  88. package/dist/session/global_config.js +1 -1
  89. package/dist/session/global_config.js.map +1 -1
  90. package/dist/session/ipc.d.ts +2 -2
  91. package/dist/session/ipc.js.map +1 -1
  92. package/dist/session/leader_election.js.map +1 -1
  93. package/dist/session/local_config.d.ts +37 -0
  94. package/dist/session/local_config.js +45 -1
  95. package/dist/session/local_config.js.map +1 -1
  96. package/dist/session/mesh_node.d.ts +1 -1
  97. package/dist/session/mesh_node.js +1 -1
  98. package/dist/session/mesh_node.js.map +1 -1
  99. package/dist/session/peer.js.map +1 -1
  100. package/dist/session/peer_inventory.js.map +1 -1
  101. package/dist/session/peer_limits.js.map +1 -1
  102. package/dist/session/received_images.d.ts +63 -0
  103. package/dist/session/received_images.js +273 -0
  104. package/dist/session/received_images.js.map +1 -0
  105. package/dist/session/relay_lifecycle.d.ts +223 -0
  106. package/dist/session/relay_lifecycle.js +802 -0
  107. package/dist/session/relay_lifecycle.js.map +1 -0
  108. package/dist/session/rpc_envelope.d.ts +10 -0
  109. package/dist/session/rpc_envelope.js +9 -0
  110. package/dist/session/rpc_envelope.js.map +1 -1
  111. package/dist/session/rpc_handlers.d.ts +53 -0
  112. package/dist/session/rpc_handlers.js +268 -0
  113. package/dist/session/rpc_handlers.js.map +1 -0
  114. package/dist/session/rpc_inbound.d.ts +41 -6
  115. package/dist/session/rpc_inbound.js +55 -0
  116. package/dist/session/rpc_inbound.js.map +1 -1
  117. package/dist/session/setup_wizard.js.map +1 -1
  118. package/dist/session/tools.js.map +1 -1
  119. package/dist/session/wizard.js.map +1 -1
  120. package/dist/state_migration.d.ts +45 -0
  121. package/dist/state_migration.js +104 -0
  122. package/dist/state_migration.js.map +1 -0
  123. package/dist/subagent_rooms.d.ts +19 -0
  124. package/dist/subagent_rooms.js +146 -14
  125. package/dist/subagent_rooms.js.map +1 -1
  126. package/dist/test_hooks.d.ts +180 -0
  127. package/dist/test_hooks.js +98 -0
  128. package/dist/test_hooks.js.map +1 -0
  129. package/dist/transport/peer_channel.d.ts +11 -0
  130. package/dist/transport/peer_channel.js +34 -11
  131. package/dist/transport/peer_channel.js.map +1 -1
  132. package/dist/transport/pi_forward_client.js.map +1 -1
  133. package/dist/transport/relay_client.d.ts +14 -3
  134. package/dist/transport/relay_client.js +6 -3
  135. package/dist/transport/relay_client.js.map +1 -1
  136. package/dist/ui/footer.js.map +1 -1
  137. package/docs/daemon.md +166 -176
  138. package/package.json +6 -2
  139. package/service-templates/launchd.plist.template +5 -4
  140. package/service-templates/systemd.service.template +3 -2
@@ -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>;
@@ -0,0 +1,275 @@
1
+ import { installService, uninstallService, linkCliBinaries, unlinkCliBinaries, } from "../daemon/install.js";
2
+ import { defaultAgentName, localConfigExists, saveLocalConfig, } from "../session/local_config.js";
3
+ import { skillsDir } from "../session/global_config.js";
4
+ import { spawnSync } from "node:child_process";
5
+ import { copyFileSync, existsSync, mkdirSync, unlinkSync, writeFileSync, } from "node:fs";
6
+ import { tmpdir } from "node:os";
7
+ import { dirname, join, resolve } from "node:path";
8
+ import { createInterface } from "node:readline";
9
+ import { fileURLToPath } from "node:url";
10
+ // ── Install/uninstall the launcher-daemon service ────────────────────────────
11
+ //
12
+ // Installs the un-bien launcher daemon as a user-level system service (systemd
13
+ // `--user` unit on Linux, launchd LaunchAgent on macOS, Task Scheduler on
14
+ // Windows). Once installed the launcher daemon starts at login + survives
15
+ // reboots. Uninstall is the inverse.
16
+ /**
17
+ * `linkCli` controls whether we symlink `un-bien` into `~/.local/bin/`. The
18
+ * slash-command path passes `true` (user is inside Pi's TUI — they installed
19
+ * via `pi install npm:un-bien` and need us to expose the CLI for them). The
20
+ * standalone-CLI path passes `false` because the user is already running our
21
+ * binary from PATH (they did `npm install -g un-bien`), so re-linking would
22
+ * point their `un-bien` at the Pi-extension copy and diverge on upgrades.
23
+ */
24
+ /** Returns true on success, false when install failed (so the standalone CLI
25
+ * can exit non-zero — e.g. the Cockpit / CI detect failure by exit code).
26
+ * We do NOT process.exit here: this also runs inside the Pi TUI, where exiting
27
+ * would kill the session. */
28
+ export function _cmdInstall(ctx, opts = {}) {
29
+ const linkCli = opts.linkCli ?? false;
30
+ try {
31
+ const result = installService();
32
+ const sections = [
33
+ `[un-bien] Launcher daemon service installed (${result.platform}).`,
34
+ ` Unit: ${result.unitPath}`,
35
+ ` Steps:\n${result.log.map((l) => " " + l).join("\n")}`,
36
+ ];
37
+ if (linkCli) {
38
+ const link = linkCliBinaries();
39
+ sections.push(` CLI bins linked into ${link.binDir}:`, link.links.map((l) => ` ${l.name} → ${l.target}`).join("\n"), ` Steps:\n${link.log.map((l) => " " + l).join("\n")}`);
40
+ if (!link.onPath) {
41
+ if (process.platform === "win32") {
42
+ sections.push(` ⚠ ${link.binDir} was just added to your user PATH (it wasn't there yet).`, ` Open a NEW terminal and run \`unbien status\` to verify.`);
43
+ }
44
+ else {
45
+ sections.push(` ⚠ ${link.binDir} is not on $PATH yet. Add this line to ~/.zshrc / ~/.bashrc:`, ` export PATH="$HOME/.local/bin:$PATH"`, ` Then open a new terminal and run \`unbien status\` to verify.`);
46
+ }
47
+ }
48
+ }
49
+ ctx.ui.notify(sections.join("\n"), "info");
50
+ return true;
51
+ }
52
+ catch (err) {
53
+ ctx.ui.notify(`[un-bien] install failed: ${String(err)}`, "error");
54
+ return false;
55
+ }
56
+ }
57
+ export function _cmdUninstall(ctx, opts = {}) {
58
+ const linkCli = opts.linkCli ?? false;
59
+ try {
60
+ const result = uninstallService();
61
+ const sections = [
62
+ `[un-bien] Launcher daemon service uninstalled (${result.platform}).`,
63
+ ` Unit: ${result.unitPath} (${result.removed ? "removed" : "not present"})`,
64
+ ` Steps:\n${result.log.map((l) => " " + l).join("\n")}`,
65
+ ];
66
+ if (linkCli) {
67
+ const unlink = unlinkCliBinaries();
68
+ sections.push(` CLI bins cleanup (${unlink.binDir}):`, unlink.removed
69
+ .map((r) => ` ${r.name} (${r.existed ? "removed" : "not present"})`)
70
+ .join("\n"));
71
+ }
72
+ ctx.ui.notify(sections.join("\n"), "info");
73
+ }
74
+ catch (err) {
75
+ ctx.ui.notify(`[un-bien] uninstall failed: ${String(err)}`, "error");
76
+ }
77
+ }
78
+ // ── Agent-network commands (plano 19) ─────────────────────────────────────────
79
+ function _resolveExtensionDir() {
80
+ // dist/commands/housekeeping.js → dist/commands; skills sit at
81
+ // <extensionRoot>/skills/. When we run from src/ via tsx (dev), this file
82
+ // is in src/commands/ and skills/ is two levels up. We detect by checking
83
+ // both locations.
84
+ const here = fileURLToPath(import.meta.url);
85
+ // dist/commands/housekeeping.js or src/commands/housekeeping.ts → parent =
86
+ // <dist or src>/commands; sibling = ../../skills (dist) / ../skills (src)
87
+ const parent = here.replace(/\/[^/]+$/, "");
88
+ const candidateA = join(parent, "..", "..", "skills"); // dist/commands → ../../skills
89
+ const candidateB = join(parent, "..", "skills"); // src/commands → ../skills
90
+ if (existsSync(candidateA))
91
+ return parent.replace(/\/(dist\/)?commands$/, "");
92
+ if (existsSync(candidateB))
93
+ return parent.replace(/\/commands$/, "");
94
+ return parent.replace(/\/commands$/, "");
95
+ }
96
+ export function _deployAgentNetworkSkill() {
97
+ // Pi SDK spec (core/skills.js): every skill must live at
98
+ // <skillsRoot>/<skill-name>/SKILL.md
99
+ // The skill `name:` frontmatter must equal the parent directory name. We
100
+ // ship the source pre-arranged that way so deploy is a straight copy into
101
+ // `<state root>/skills/agent-network/SKILL.md`.
102
+ const root = _resolveExtensionDir();
103
+ const src1 = join(root, "skills", "agent-network", "SKILL.md");
104
+ const src2 = join(root, "..", "skills", "agent-network", "SKILL.md");
105
+ const src = existsSync(src1) ? src1 : existsSync(src2) ? src2 : null;
106
+ if (!src)
107
+ return;
108
+ const dstDir = join(skillsDir(), "agent-network");
109
+ const dst = join(dstDir, "SKILL.md");
110
+ try {
111
+ mkdirSync(dstDir, { recursive: true });
112
+ copyFileSync(src, dst);
113
+ // Cleanup legacy flat-layout deploy at `<state root>/skills/agent-network.md`
114
+ // (fails the Pi SDK's name-vs-parent-dir validation).
115
+ const legacy = join(skillsDir(), "agent-network.md");
116
+ if (existsSync(legacy)) {
117
+ try {
118
+ unlinkSync(legacy);
119
+ }
120
+ catch {
121
+ /* ignored */
122
+ }
123
+ }
124
+ }
125
+ catch {
126
+ /* best-effort */
127
+ }
128
+ }
129
+ // ── `unbien claude` — launch Claude Code connected to the mesh ─────────────
130
+ /**
131
+ * Resolve the packaged agent-network skill path
132
+ * (`<pkgRoot>/skills/agent-network/SKILL.md`). Single source of truth shared
133
+ * by both runtimes: Pi discovers it via `resources_discover`, and the Claude
134
+ * launcher injects it as a system prompt (see `_cmdClaudeCli`). Returns null
135
+ * if the file is missing (e.g. running before `pnpm build`).
136
+ */
137
+ function _agentNetworkSkillPath() {
138
+ const here = fileURLToPath(import.meta.url); // dist/commands/housekeeping.js (or src/ via tsx)
139
+ const pkgRoot = dirname(dirname(dirname(here))); // package root (dist/commands → ../..; src/commands → ../..)
140
+ const skill = join(pkgRoot, "skills", "agent-network", "SKILL.md");
141
+ return existsSync(skill) ? skill : null;
142
+ }
143
+ export async function _cmdClaudeCli(args) {
144
+ // Contract: `unbien claude [cwd] [claude-flags...]`. The optional cwd is
145
+ // ONLY the leading positional (first token, not a flag); everything after it
146
+ // is forwarded verbatim to the `claude` binary (e.g. `--resume`, `-c`,
147
+ // `-p "prompt"`). Restricting cwd to the leading token avoids mistaking a
148
+ // flag's value (e.g. the id in `--resume <id>`) for the cwd.
149
+ const hasCwdArg = args.length > 0 && !args[0].startsWith("-");
150
+ const targetCwd = hasCwdArg ? args[0] : process.cwd();
151
+ const passthroughArgs = hasCwdArg ? args.slice(1) : args;
152
+ // Wizard when no local config exists
153
+ if (!localConfigExists(targetCwd)) {
154
+ const suggested = defaultAgentName(targetCwd);
155
+ process.stdout.write(`\n[un-bien] No config found for ${targetCwd}\n`);
156
+ process.stdout.write("Let's set up this agent.\n\n");
157
+ const rl = createInterface({
158
+ input: process.stdin,
159
+ output: process.stdout,
160
+ });
161
+ const agentName = await new Promise((res) => rl.question(`Agent name [${suggested}]: `, (ans) => {
162
+ rl.close();
163
+ res(ans.trim() || suggested);
164
+ }));
165
+ saveLocalConfig(targetCwd, {
166
+ agent_name: agentName,
167
+ auto_start_relay: true,
168
+ });
169
+ process.stdout.write(`[un-bien] Config saved: agent="${agentName}"\n\n`);
170
+ }
171
+ // Resolve mesh server script path (dist/mcp/mesh_server.js)
172
+ const here = fileURLToPath(import.meta.url);
173
+ const distRoot = dirname(here); // dist/commands → mesh server at ../mcp/
174
+ const meshServerPath = resolve(distRoot, "..", "mcp/mesh_server.js");
175
+ if (!existsSync(meshServerPath)) {
176
+ console.log(`[un-bien] mesh server not found at ${meshServerPath}. Run pnpm build first.`);
177
+ process.exit(1);
178
+ }
179
+ const absCwd = resolve(targetCwd);
180
+ const SERVER_NAME = "un-bien-mesh";
181
+ // The mesh MCP must be visible ONLY inside a `unbien claude` session — a
182
+ // plain `claude` in the same repo must NOT inherit it (otherwise every
183
+ // ordinary session silently joins the mesh as a stray agent).
184
+ //
185
+ // Older builds registered the server with `claude mcp add -s local`. That
186
+ // scope lives in `~/.claude.json` keyed by the **git repo root** and is
187
+ // inherited by EVERY claude session under that root — which is exactly the
188
+ // leak we're closing. So we no longer write any persistent scope; we load
189
+ // the server through an ephemeral `--mcp-config <tmpfile>` passed on the
190
+ // launch command line (see below). That config is session-only: it is never
191
+ // recorded in any scope `claude mcp list` enumerates, so a normal `claude`
192
+ // sees nothing.
193
+ //
194
+ // Migration: best-effort scrub of the stale `-s local` entry that prior
195
+ // versions left behind (and that is the source of the inherited-mesh bug).
196
+ // Idempotent — a no-op (non-zero, ignored) when the entry is already gone.
197
+ spawnSync("claude", ["mcp", "remove", SERVER_NAME, "-s", "local"], {
198
+ cwd: absCwd,
199
+ stdio: "ignore",
200
+ shell: false,
201
+ });
202
+ // Ephemeral MCP config consumed by `--mcp-config` below. We do NOT bake a
203
+ // `cwd` into it: the server resolves its folder from its own `process.cwd()`,
204
+ // which Claude sets to the directory the session was launched in (verified
205
+ // empirically — NOT the git root, NOT CLAUDE_PROJECT_DIR). We spawn claude
206
+ // with `cwd: absCwd`, the MCP child inherits it, so the server self-identifies
207
+ // as the right agent without leaking that path to any other session.
208
+ // Unique per pid so concurrent `unbien claude` launches don't collide.
209
+ const mcpConfigPath = join(tmpdir(), `un-bien-mesh-mcp-${process.pid}.json`);
210
+ writeFileSync(mcpConfigPath, JSON.stringify({
211
+ mcpServers: {
212
+ [SERVER_NAME]: { command: process.execPath, args: [meshServerPath] },
213
+ },
214
+ }));
215
+ // Inject the agent-network protocol as a system prompt instead of deploying a
216
+ // skill file into ~/.claude. Anyone running `unbien claude` is here to use
217
+ // the mesh, so load the protocol unconditionally — no lazy skill gating, no
218
+ // global skills-dir pollution, and the packaged file is the single source of
219
+ // truth shared with the Pi runtime. Skipped only if the file is missing.
220
+ const skillPath = _agentNetworkSkillPath();
221
+ // Launch flags:
222
+ // --mcp-config <tmpfile> — load the mesh server for
223
+ // THIS session only (never a persistent scope). We intentionally omit
224
+ // `--strict-mcp-config` so the user's own persistent MCP servers stay
225
+ // available alongside the mesh.
226
+ // --dangerously-load-development-channels TAG — enable claude/channel push
227
+ // for our local (non-allowlisted) server, so incoming mesh messages
228
+ // wake Claude instead of waiting for a get_messages poll. Entries must
229
+ // be tagged: `server:<name>` for a manually configured MCP server
230
+ // (`plugin:<name>@<marketplace>` is the plugin form). Shows a one-time
231
+ // confirmation dialog at startup. Works against the `--mcp-config`
232
+ // server in current Claude Code; if a build ever fails to match it, the
233
+ // per-turn `get_messages` poll (mandated by the mesh protocol) still
234
+ // delivers — we lose the wake, not the messages.
235
+ // --dangerously-skip-permissions — auto-approve tool calls
236
+ // --append-system-prompt-file=<skill> — load the mesh protocol
237
+ // `--append-system-prompt-file` uses the glued `--flag=value` form (a SINGLE
238
+ // argv token) on purpose: tools that restore a session by capturing and
239
+ // replaying the live process's argv (e.g. cmux) drop the TRAILING token,
240
+ // which here was the skill path — leaving a dangling `--append-system-prompt-file`
241
+ // → `claude` aborts with "argument missing" and the session never comes back.
242
+ // As one token, the worst case is the whole flag being dropped: claude still
243
+ // starts (just without the injected protocol), which is recoverable instead
244
+ // of fatal. (The other flags stay separate pairs — never last, so unaffected,
245
+ // and we don't risk a parser that may not accept `=`.)
246
+ // Any extra args the user passed (e.g. `--resume`, `-c`) are appended last so
247
+ // they reach the claude binary; ours come first as sensible defaults.
248
+ try {
249
+ spawnSync("claude", [
250
+ "--mcp-config",
251
+ mcpConfigPath,
252
+ "--dangerously-load-development-channels",
253
+ `server:${SERVER_NAME}`,
254
+ "--dangerously-skip-permissions",
255
+ ...(skillPath ? [`--append-system-prompt-file=${skillPath}`] : []),
256
+ ...passthroughArgs,
257
+ ], {
258
+ cwd: absCwd,
259
+ stdio: "inherit",
260
+ shell: false,
261
+ });
262
+ }
263
+ finally {
264
+ // Session over — drop the ephemeral config so it never lingers as a stray
265
+ // file. spawnSync blocks until claude exits, so claude has long since read
266
+ // it. Best-effort: ignore if already gone.
267
+ try {
268
+ unlinkSync(mcpConfigPath);
269
+ }
270
+ catch {
271
+ /* already removed */
272
+ }
273
+ }
274
+ }
275
+ //# sourceMappingURL=housekeeping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"housekeeping.js","sourceRoot":"","sources":["../../src/commands/housekeeping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * `/unbien` info commands: status, peers, devices/list, config, identity.
3
+ *
4
+ * Read-only views over the composition root's state — everything they need
5
+ * from index.ts's module scope comes through `CommandDeps` (see deps.ts).
6
+ * Carved out of index.ts (phase 1 of the index.ts carve-up).
7
+ */
8
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
9
+ import type { CommandDeps } from "./deps.js";
10
+ /**
11
+ * `/unbien status` — full state snapshot. Two lines: local mesh + relay.
12
+ *
13
+ * Always callable; safe when nothing is up (renders the off variants).
14
+ * Reuses the same icons as the footer so terminal + status output stay
15
+ * visually consistent.
16
+ */
17
+ export declare function _cmdStatus(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui">): void;
18
+ /**
19
+ * Plan/25 Wave D: `/unbien peers`.
20
+ *
21
+ * Queries the local broker for the aggregated peer inventory (`list_peers`
22
+ * returns locals + cross-PC entries prefixed with `<pc_label>:`). Formats
23
+ * the result grouped by source so users can see at a glance who's on
24
+ * their machine vs. on a paired sibling Pi.
25
+ */
26
+ export declare function _cmdPeers(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui">): Promise<void>;
27
+ export declare function _cmdList(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui">): Promise<void>;
28
+ /**
29
+ * `/unbien config` — print the effective relay URL and where it came from.
30
+ *
31
+ * Documented in the README ("Verify the active URL and its source") and in
32
+ * CLAUDE.md, but like the `relay` family (issue #119) it had no handler and
33
+ * fell through to the status panel, which shows the URL but not the source —
34
+ * so `env` vs `config` vs `default` was unverifiable without a restart.
35
+ */
36
+ export declare function _cmdConfig(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui">): void;
37
+ /**
38
+ * `/unbien identity` — report NON-SECRET identity state (active EPK, backend,
39
+ * resolved source). The private seed is NEVER shown: command output is
40
+ * LLM-visible, so extraction stays a manual `cat`/keychain op. Read-only
41
+ * (never mints).
42
+ */
43
+ export declare function _cmdIdentity(ctx: Pick<ExtensionContext, "ui">): Promise<void>;
@@ -0,0 +1,127 @@
1
+ import { resolveRelayUrl } from "../config.js";
2
+ import { describeIdentity, listPeers } from "../pairing/storage.js";
3
+ import { _inspectPeerRecord } from "../pairing/peer_trust.js";
4
+ import { formatPeerInventory } from "../session/peer_inventory.js";
5
+ /**
6
+ * `/unbien status` — full state snapshot. Two lines: local mesh + relay.
7
+ *
8
+ * Always callable; safe when nothing is up (renders the off variants).
9
+ * Reuses the same icons as the footer so terminal + status output stay
10
+ * visually consistent.
11
+ */
12
+ export function _cmdStatus(deps, ctx) {
13
+ const relayUrl = deps.relayUrl ?? resolveRelayUrl().url ?? "not configured";
14
+ // Mesh line
15
+ let meshLine;
16
+ if (deps.meshNode) {
17
+ const name = deps.meshNode.name();
18
+ meshLine = `🟢 Local mesh: connected as "${name}" (${deps.sessionPeerCount} peer${deps.sessionPeerCount === 1 ? "" : "s"})`;
19
+ }
20
+ else {
21
+ meshLine = "⚪ Local mesh: not connected";
22
+ }
23
+ // Relay line — paired state is derived from deps.activePeers.size now.
24
+ let relayLine;
25
+ if (deps.state === "idle") {
26
+ relayLine = `⚪ Relay: off (${relayUrl}) — run /unbien to start`;
27
+ }
28
+ else if (deps.activePeers.size > 0) {
29
+ const count = deps.activePeers.size;
30
+ const shortids = [...deps.activePeers.keys()]
31
+ .map((peerId) => peerId.slice(0, 8))
32
+ .join(", ");
33
+ relayLine = `🟢 Relay: ${count} owner${count === 1 ? "" : "s"} online (${shortids}) (${relayUrl})`;
34
+ }
35
+ else {
36
+ relayLine = deps.hasGlobalPairings
37
+ ? `🟢 Relay: on, waiting for an app to connect (${relayUrl})`
38
+ : `🟡 Relay: on, waiting for first pairing (${relayUrl})`;
39
+ }
40
+ ctx.ui.notify(`[un-bien]\n ${meshLine}\n ${relayLine}`, "info");
41
+ }
42
+ /**
43
+ * Plan/25 Wave D: `/unbien peers`.
44
+ *
45
+ * Queries the local broker for the aggregated peer inventory (`list_peers`
46
+ * returns locals + cross-PC entries prefixed with `<pc_label>:`). Formats
47
+ * the result grouped by source so users can see at a glance who's on
48
+ * their machine vs. on a paired sibling Pi.
49
+ */
50
+ export async function _cmdPeers(deps, ctx) {
51
+ if (!deps.meshNode) {
52
+ ctx.ui.notify("[un-bien] Not on the local mesh. Run /unbien to join.", "warning");
53
+ return;
54
+ }
55
+ let peers;
56
+ try {
57
+ const reply = await deps.meshNode.request("broker", { type: "list_peers" }, 2000);
58
+ peers = reply.body?.peers ?? [];
59
+ }
60
+ catch (err) {
61
+ ctx.ui.notify(`[un-bien] peers list failed: ${String(err)}`, "error");
62
+ return;
63
+ }
64
+ // Exclude self from the printed list — `list_peers` returns every peer
65
+ // registered with the broker including the caller, which is noise here.
66
+ const selfName = deps.meshNode.name();
67
+ ctx.ui.notify(`[un-bien] peers:\n${formatPeerInventory(peers, selfName)}`, "info");
68
+ }
69
+ export async function _cmdList(deps, ctx) {
70
+ const peers = await listPeers();
71
+ if (peers.length === 0) {
72
+ ctx.ui.notify("[un-bien] No paired devices.", "info");
73
+ return;
74
+ }
75
+ // Multi-channel (W2D): each peer is either `online` (channel attached
76
+ // right now) or `offline` (in peers.json but not connected). Replaces
77
+ // the singleton " (active)" marker that only ever marked one peer.
78
+ const lines = peers
79
+ .flatMap((record) => {
80
+ const inspected = _inspectPeerRecord(record);
81
+ if (!inspected)
82
+ return [];
83
+ const tag = inspected.runtimeKey !== null &&
84
+ deps.activePeers.has(inspected.runtimeKey)
85
+ ? " 🟢 online"
86
+ : " ⚪ offline";
87
+ return `• ${inspected.rawHandle.slice(0, 8)} — ${inspected.record.name}${tag}`;
88
+ })
89
+ .join("\n");
90
+ ctx.ui.notify(`[un-bien] Paired devices:\n${lines}`, "info");
91
+ }
92
+ /**
93
+ * `/unbien config` — print the effective relay URL and where it came from.
94
+ *
95
+ * Documented in the README ("Verify the active URL and its source") and in
96
+ * CLAUDE.md, but like the `relay` family (issue #119) it had no handler and
97
+ * fell through to the status panel, which shows the URL but not the source —
98
+ * so `env` vs `config` vs `default` was unverifiable without a restart.
99
+ */
100
+ export function _cmdConfig(deps, ctx) {
101
+ const { url, source } = resolveRelayUrl();
102
+ const origin = source === "env"
103
+ ? "UNBIEN_RELAY environment variable"
104
+ : source === "config"
105
+ ? "extensions/un-bien.json (set via /unbien set-relay)"
106
+ : "not set — run /unbien set-relay <url> or set UNBIEN_RELAY";
107
+ const live = deps.relayUrl && deps.relayUrl !== url
108
+ ? `\n ⚠ Live connection still on ${deps.relayUrl} — run /unbien relay stop then /unbien relay start to apply.`
109
+ : "";
110
+ ctx.ui.notify(`[un-bien]\n Relay URL: ${url ?? "(none)"}\n Source: ${source} — ${origin}${live}`, "info");
111
+ }
112
+ /**
113
+ * `/unbien identity` — report NON-SECRET identity state (active EPK, backend,
114
+ * resolved source). The private seed is NEVER shown: command output is
115
+ * LLM-visible, so extraction stays a manual `cat`/keychain op. Read-only
116
+ * (never mints).
117
+ */
118
+ export async function _cmdIdentity(ctx) {
119
+ const info = await describeIdentity();
120
+ const backendLine = info.backend === "file" ? `file (${info.filePath})` : "keychain";
121
+ const epkLine = info.epk ?? "(none yet — minted on first use)";
122
+ const sourceLine = info.detail
123
+ ? `${info.source} — ${info.detail}`
124
+ : info.source;
125
+ ctx.ui.notify(`[un-bien] identity\n Backend: ${backendLine}\n EPK (public): ${epkLine}\n Source: ${sourceLine}`, info.source === "error" ? "error" : "info");
126
+ }
127
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `/unbien` lifecycle commands: root (connect-or-setup), rootInner, setup
3
+ * wizard, start (relay), stop (teardown), join (local UDS mesh).
4
+ *
5
+ * The heaviest handler lives here: `_cmdStart` touches relay startup, the
6
+ * auto-listener, SelfRevoke topology production, and the first-run model/
7
+ * thinking seeding. Everything it needs from index.ts's module scope comes
8
+ * through `CommandDeps` (see deps.ts). Carved out of index.ts (phase 1 of
9
+ * the index.ts carve-up).
10
+ */
11
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
12
+ import type { CommandDeps } from "./deps.js";
13
+ export type RootRestartAuthority = Readonly<{
14
+ rootLifecycleGeneration: number;
15
+ }>;
16
+ /**
17
+ * Root handler for `/unbien`. On first run (no local config) drops into
18
+ * the wizard; on subsequent runs auto-joins the local mesh + starts the
19
+ * relay (if opted in during setup), then prints the status.
20
+ *
21
+ * `/unbien` is intentionally the only command users need day-to-day:
22
+ * idempotent connect + status display.
23
+ */
24
+ export declare function _cmdRoot(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui" | "cwd">, restartAuthority?: RootRestartAuthority): Promise<void>;
25
+ export declare function _cmdRootInner(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui" | "cwd">, rootLifecycleGeneration: number): Promise<void>;
26
+ /**
27
+ * `/unbien setup` — re-run the wizard. Defaults pre-fill from the
28
+ * existing config so it doubles as an "edit" flow.
29
+ */
30
+ export declare function _cmdSetup(ctx: Pick<ExtensionContext, "ui" | "cwd">): Promise<void>;
31
+ export declare function _cmdStart(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui" | "cwd">): Promise<void>;
32
+ /**
33
+ * `/unbien stop` — full teardown. Leaves the local UDS mesh AND closes
34
+ * the relay. Safe when one or both are already off. To resume, run
35
+ * `/unbien` again.
36
+ */
37
+ export declare function _cmdStop(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui">): Promise<void>;
38
+ /**
39
+ * Joins the fixed local UDS mesh ("local" session — see LOCAL_SESSION_NAME).
40
+ * Called by `_cmdRoot` on first run and on subsequent runs when the relay
41
+ * is up and the user hasn't explicitly stopped. The session name is no
42
+ * longer user-configurable: every Pi on the same machine joins the same
43
+ * broker.
44
+ */
45
+ export declare function _cmdJoin(deps: CommandDeps, ctx: Pick<ExtensionContext, "ui" | "cwd">): Promise<void>;