@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.
- package/README.md +100 -131
- 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/client.d.ts +15 -0
- package/dist/client.js +15 -0
- package/dist/client.js.map +1 -0
- 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 +11 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon/install.d.ts +6 -5
- package/dist/daemon/install.js +15 -5
- 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 +852 -2872
- package/dist/index.js.map +1 -1
- package/dist/launch.d.ts +14 -1
- package/dist/launch.js +55 -5
- package/dist/launch.js.map +1 -1
- package/dist/launcher/launcher.js +48 -6
- 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.d.ts +7 -0
- package/dist/pairing/storage.js +22 -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 +223 -0
- package/dist/session/relay_lifecycle.js +802 -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 +14 -3
- 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 +166 -176
- package/package.json +6 -2
- package/service-templates/launchd.plist.template +5 -4
- 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>;
|