@geohar/un-bien 0.8.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +258 -320
  2. package/dist/actions/handlers.js.map +1 -1
  3. package/dist/actions/registry.js.map +1 -1
  4. package/dist/bin/launcher.js +38 -0
  5. package/dist/bin/launcher.js.map +1 -0
  6. package/dist/commands/deps.d.ts +156 -0
  7. package/dist/commands/deps.js +2 -0
  8. package/dist/commands/deps.js.map +1 -0
  9. package/dist/commands/fork_link.d.ts +4 -0
  10. package/dist/commands/fork_link.js +45 -0
  11. package/dist/commands/fork_link.js.map +1 -0
  12. package/dist/commands/housekeeping.d.ts +34 -0
  13. package/dist/commands/housekeeping.js +275 -0
  14. package/dist/commands/housekeeping.js.map +1 -0
  15. package/dist/commands/info.d.ts +43 -0
  16. package/dist/commands/info.js +127 -0
  17. package/dist/commands/info.js.map +1 -0
  18. package/dist/commands/lifecycle.d.ts +45 -0
  19. package/dist/commands/lifecycle.js +708 -0
  20. package/dist/commands/lifecycle.js.map +1 -0
  21. package/dist/commands/pairing.d.ts +26 -0
  22. package/dist/commands/pairing.js +167 -0
  23. package/dist/commands/pairing.js.map +1 -0
  24. package/dist/commands/register.d.ts +12 -0
  25. package/dist/commands/register.js +255 -0
  26. package/dist/commands/register.js.map +1 -0
  27. package/dist/commands/relay.d.ts +28 -0
  28. package/dist/commands/relay.js +81 -0
  29. package/dist/commands/relay.js.map +1 -0
  30. package/dist/commands/session_ops.d.ts +52 -0
  31. package/dist/commands/session_ops.js +75 -0
  32. package/dist/commands/session_ops.js.map +1 -0
  33. package/dist/config.d.ts +30 -2
  34. package/dist/config.js.map +1 -1
  35. package/dist/daemon/install.d.ts +36 -37
  36. package/dist/daemon/install.js +49 -73
  37. package/dist/daemon/install.js.map +1 -1
  38. package/dist/enrich_tool_args.d.ts +9 -0
  39. package/dist/enrich_tool_args.js +171 -0
  40. package/dist/enrich_tool_args.js.map +1 -0
  41. package/dist/extension_ui_bridge.js.map +1 -1
  42. package/dist/image_codec.d.ts +22 -0
  43. package/dist/image_codec.js +149 -0
  44. package/dist/image_codec.js.map +1 -0
  45. package/dist/index.d.ts +32 -127
  46. package/dist/index.js +957 -4042
  47. package/dist/index.js.map +1 -1
  48. package/dist/launch.d.ts +42 -0
  49. package/dist/launch.js +206 -0
  50. package/dist/launch.js.map +1 -0
  51. package/dist/launcher/launcher.d.ts +6 -0
  52. package/dist/launcher/launcher.js +207 -0
  53. package/dist/launcher/launcher.js.map +1 -0
  54. package/dist/mcp/mesh_result.js.map +1 -1
  55. package/dist/mcp/mesh_server.js.map +1 -1
  56. package/dist/mesh/canonical.js +1 -1
  57. package/dist/mesh/canonical.js.map +1 -1
  58. package/dist/mesh/client.js.map +1 -1
  59. package/dist/mesh/encoding.js.map +1 -1
  60. package/dist/mesh/self_revoke.js.map +1 -1
  61. package/dist/mesh/siblings.js.map +1 -1
  62. package/dist/mesh/verify.js +1 -1
  63. package/dist/mesh/verify.js.map +1 -1
  64. package/dist/pairing/crypto.js +0 -1
  65. package/dist/pairing/crypto.js.map +1 -1
  66. package/dist/pairing/peer_trust.d.ts +20 -0
  67. package/dist/pairing/peer_trust.js +82 -0
  68. package/dist/pairing/peer_trust.js.map +1 -0
  69. package/dist/pairing/qr.js.map +1 -1
  70. package/dist/pairing/storage.js +4 -3
  71. package/dist/pairing/storage.js.map +1 -1
  72. package/dist/panel_bridge.d.ts +3 -1
  73. package/dist/panel_bridge.js +11 -10
  74. package/dist/panel_bridge.js.map +1 -1
  75. package/dist/paths.d.ts +22 -8
  76. package/dist/paths.js +37 -10
  77. package/dist/paths.js.map +1 -1
  78. package/dist/protocol/codec.js.map +1 -1
  79. package/dist/rooms.d.ts +16 -0
  80. package/dist/rooms.js +23 -4
  81. package/dist/rooms.js.map +1 -1
  82. package/dist/session/bridge.js.map +1 -1
  83. package/dist/session/broker.js.map +1 -1
  84. package/dist/session/broker_remote.js.map +1 -1
  85. package/dist/session/capabilities.d.ts +11 -0
  86. package/dist/session/capabilities.js +35 -0
  87. package/dist/session/capabilities.js.map +1 -0
  88. package/dist/session/cwd_lock.js +3 -3
  89. package/dist/session/cwd_lock.js.map +1 -1
  90. package/dist/session/debug_log.js +15 -5
  91. package/dist/session/debug_log.js.map +1 -1
  92. package/dist/session/envelope.js.map +1 -1
  93. package/dist/session/global_config.d.ts +1 -1
  94. package/dist/session/global_config.js +1 -1
  95. package/dist/session/global_config.js.map +1 -1
  96. package/dist/session/ipc.d.ts +2 -2
  97. package/dist/session/ipc.js.map +1 -1
  98. package/dist/session/leader_election.js.map +1 -1
  99. package/dist/session/local_config.d.ts +37 -0
  100. package/dist/session/local_config.js +47 -1
  101. package/dist/session/local_config.js.map +1 -1
  102. package/dist/session/mesh_node.d.ts +1 -1
  103. package/dist/session/mesh_node.js +1 -1
  104. package/dist/session/mesh_node.js.map +1 -1
  105. package/dist/session/peer.js.map +1 -1
  106. package/dist/session/peer_inventory.js.map +1 -1
  107. package/dist/session/peer_limits.js.map +1 -1
  108. package/dist/session/received_images.d.ts +63 -0
  109. package/dist/session/received_images.js +273 -0
  110. package/dist/session/received_images.js.map +1 -0
  111. package/dist/session/relay_lifecycle.d.ts +219 -0
  112. package/dist/session/relay_lifecycle.js +764 -0
  113. package/dist/session/relay_lifecycle.js.map +1 -0
  114. package/dist/session/rpc_envelope.d.ts +28 -0
  115. package/dist/session/rpc_envelope.js +10 -1
  116. package/dist/session/rpc_envelope.js.map +1 -1
  117. package/dist/session/rpc_handlers.d.ts +53 -0
  118. package/dist/session/rpc_handlers.js +268 -0
  119. package/dist/session/rpc_handlers.js.map +1 -0
  120. package/dist/session/rpc_inbound.d.ts +42 -7
  121. package/dist/session/rpc_inbound.js +56 -1
  122. package/dist/session/rpc_inbound.js.map +1 -1
  123. package/dist/session/setup_wizard.js.map +1 -1
  124. package/dist/session/tools.js.map +1 -1
  125. package/dist/session/wizard.js.map +1 -1
  126. package/dist/state_migration.d.ts +45 -0
  127. package/dist/state_migration.js +104 -0
  128. package/dist/state_migration.js.map +1 -0
  129. package/dist/subagent_rooms.d.ts +68 -0
  130. package/dist/subagent_rooms.js +919 -0
  131. package/dist/subagent_rooms.js.map +1 -0
  132. package/dist/test_hooks.d.ts +180 -0
  133. package/dist/test_hooks.js +98 -0
  134. package/dist/test_hooks.js.map +1 -0
  135. package/dist/transport/peer_channel.d.ts +18 -1
  136. package/dist/transport/peer_channel.js +42 -12
  137. package/dist/transport/peer_channel.js.map +1 -1
  138. package/dist/transport/pi_forward_client.js.map +1 -1
  139. package/dist/transport/relay_client.d.ts +24 -2
  140. package/dist/transport/relay_client.js +6 -3
  141. package/dist/transport/relay_client.js.map +1 -1
  142. package/dist/ui/footer.js.map +1 -1
  143. package/docs/daemon.md +170 -179
  144. package/package.json +13 -11
  145. package/service-templates/launchd.plist.template +8 -7
  146. package/service-templates/systemd.service.template +5 -4
  147. package/service-templates/task-launcher.vbs.template +5 -5
  148. package/service-templates/task-scheduler.xml.template +1 -1
  149. package/dist/bin/supervisord.js +0 -86
  150. package/dist/bin/supervisord.js.map +0 -1
  151. package/dist/daemon/client.d.ts +0 -20
  152. package/dist/daemon/client.js +0 -131
  153. package/dist/daemon/client.js.map +0 -1
  154. package/dist/daemon/control_protocol.d.ts +0 -176
  155. package/dist/daemon/control_protocol.js +0 -63
  156. package/dist/daemon/control_protocol.js.map +0 -1
  157. package/dist/daemon/cron_log.d.ts +0 -45
  158. package/dist/daemon/cron_log.js +0 -71
  159. package/dist/daemon/cron_log.js.map +0 -1
  160. package/dist/daemon/cron_registry.d.ts +0 -80
  161. package/dist/daemon/cron_registry.js +0 -198
  162. package/dist/daemon/cron_registry.js.map +0 -1
  163. package/dist/daemon/id.d.ts +0 -24
  164. package/dist/daemon/id.js +0 -36
  165. package/dist/daemon/id.js.map +0 -1
  166. package/dist/daemon/registry.d.ts +0 -63
  167. package/dist/daemon/registry.js +0 -153
  168. package/dist/daemon/registry.js.map +0 -1
  169. package/dist/daemon/rpc_child.d.ts +0 -194
  170. package/dist/daemon/rpc_child.js +0 -419
  171. package/dist/daemon/rpc_child.js.map +0 -1
  172. package/dist/daemon/supervisor.d.ts +0 -93
  173. package/dist/daemon/supervisor.js +0 -666
  174. package/dist/daemon/supervisor.js.map +0 -1
  175. /package/dist/bin/{supervisord.d.ts → launcher.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuEH;8EAC8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAuEH;8EAC8E;AAC9E,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,CAAA;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/actions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,IAAI,iBAAiB,GAA+B,IAAI,CAAC;AAEzD;;;GAGG;AACH,MAAM,aAAa,GAAwB;IACzC,OAAO,KAAI,CAAC;IACZ,YAAY;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,IAAI;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,EAAE,aAAa,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACT,iBAAiB,GAAG,IAAI,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,OAAO,iBAAiB,IAAI,aAAa,CAAC;AAC5C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,2BAA2B;IACzC,iBAAiB,GAAG,IAAI,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/actions/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AASH,IAAI,iBAAiB,GAA+B,IAAI,CAAA;AAExD;;;GAGG;AACH,MAAM,aAAa,GAAwB;IACzC,OAAO,KAAI,CAAC;IACZ,YAAY;QACV,OAAO,EAAE,CAAA;IACX,CAAC;IACD,IAAI;QACF,OAAO,SAAS,CAAA;IAClB,CAAC;CACF,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,GAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,GAAG,EAAE,aAAa,CAAA;QAC/B,IAAI,IAAI,EAAE,CAAC;YACT,iBAAiB,GAAG,IAAI,CAAA;YACxB,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qEAAqE;IACvE,CAAC;IACD,OAAO,iBAAiB,IAAI,aAAa,CAAA;AAC3C,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,2BAA2B;IACzC,iBAAiB,GAAG,IAAI,CAAA;AAC1B,CAAC"}
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `pi-unbien-launcher` — the regime-2 machine-launcher daemon.
4
+ *
5
+ * A lightweight mesh peer (NOT a pi session) that lets a paired app launch a
6
+ * session on THIS machine even when no pi is running here. Reads the machine's
7
+ * un-bien config for identity + relay + launch backend, joins the machine-level
8
+ * control room, advertises `remote_launch`, and spawns tmux/herdr on request.
9
+ *
10
+ * Run by hand during bring-up:
11
+ * pnpm build && node dist/bin/launcher.js
12
+ * (An OS-service unit for keepalive is a separate install step.)
13
+ */
14
+ import { startLauncher } from "../launcher/launcher.js";
15
+ async function main() {
16
+ const handle = await startLauncher();
17
+ // eslint-disable-next-line no-console
18
+ console.log(`[un-bien launcher] listening on control room ${handle.roomId} ` +
19
+ `(epk ${handle.epk.slice(0, 16)}…) — Ctrl-C to stop`);
20
+ let shuttingDown = false;
21
+ const shutdown = (signal) => {
22
+ if (shuttingDown)
23
+ return;
24
+ shuttingDown = true;
25
+ // eslint-disable-next-line no-console
26
+ console.log(`[un-bien launcher] ${signal} — shutting down`);
27
+ handle.stop();
28
+ process.exit(0);
29
+ };
30
+ process.on("SIGINT", () => shutdown("SIGINT"));
31
+ process.on("SIGTERM", () => shutdown("SIGTERM"));
32
+ }
33
+ main().catch((err) => {
34
+ // eslint-disable-next-line no-console
35
+ console.error(`[un-bien launcher] fatal: ${err instanceof Error ? err.message : String(err)}`);
36
+ process.exit(1);
37
+ });
38
+ //# sourceMappingURL=launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launcher.js","sourceRoot":"","sources":["../../src/bin/launcher.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEvD,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,CAAA;IACpC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CACT,gDAAgD,MAAM,CAAC,MAAM,GAAG;QAC9D,QAAQ,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,qBAAqB,CACvD,CAAA;IAED,IAAI,YAAY,GAAG,KAAK,CAAA;IACxB,MAAM,QAAQ,GAAG,CAAC,MAAc,EAAE,EAAE;QAClC,IAAI,YAAY;YAAE,OAAM;QACxB,YAAY,GAAG,IAAI,CAAA;QACnB,sCAAsC;QACtC,OAAO,CAAC,GAAG,CAAC,sBAAsB,MAAM,kBAAkB,CAAC,CAAA;QAC3D,MAAM,CAAC,IAAI,EAAE,CAAA;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAA;IACD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC9C,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAA;AAClD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,sCAAsC;IACtC,OAAO,CAAC,KAAK,CACX,6BAA6B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAChF,CAAA;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
@@ -0,0 +1,156 @@
1
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+ import type { Ed25519Keypair } from "../pairing/crypto.js";
3
+ import type { SelfRevoke } from "../mesh/self_revoke.js";
4
+ import type { MeshTopologySnapshot } from "../mesh/siblings.js";
5
+ import type { Envelope } from "../session/envelope.js";
6
+ import type { MeshNode } from "../session/mesh_node.js";
7
+ import type { AcquiredLock } from "../session/cwd_lock.js";
8
+ import type { RelayClient } from "../transport/relay_client.js";
9
+ import type { PlainPeerChannel } from "../transport/peer_channel.js";
10
+ import type { ThinkingLevel } from "../protocol/types.js";
11
+ /** App↔Pi room meta projected by the ROOT session (see index.ts `_myRoomMeta`). */
12
+ export type RoomMeta = {
13
+ name: string;
14
+ cwd: string;
15
+ model?: string;
16
+ thinking?: ThinkingLevel;
17
+ working?: boolean;
18
+ sessionId?: string;
19
+ };
20
+ /**
21
+ * The seam between index.ts (composition root) and the `/unbien` command
22
+ * modules.
23
+ *
24
+ * index.ts owns every piece of mutable module state and every lifecycle
25
+ * helper the command handlers touch. Command modules MUST NOT import from
26
+ * `../index.js` (that would be a circular import); instead index.ts builds
27
+ * one `CommandDeps` object (accessor closures over its module state plus
28
+ * direct function references) and passes it to `registerUnbienCommands`,
29
+ * which threads it into every handler that needs it.
30
+ *
31
+ * Members are added exactly as the moved code requires them — nothing
32
+ * speculative. Mutable state that commands write is a get/set pair; state
33
+ * they only read is `readonly`.
34
+ */
35
+ export interface CommandDeps {
36
+ /** Remote state machine: `idle` → `started` (`paired` is derived). */
37
+ state: "idle" | "started";
38
+ /** Live relay WS connection, null when off. */
39
+ relay: RelayClient | null;
40
+ /** URL used by the current relay connection (http(s):// canonical form). */
41
+ relayUrl: string | null;
42
+ /** Local UDS mesh node, null when not joined. */
43
+ meshNode: MeshNode | null;
44
+ /** Mesh session name (LOCAL_SESSION_NAME once joined). */
45
+ sessionName: string | null;
46
+ /** Authoritative local-mesh peer count (broker `list_peers`). */
47
+ sessionPeerCount: number;
48
+ /** Cached Ed25519 identity of this connect cycle. */
49
+ cachedEd25519: Ed25519Keypair | null;
50
+ /** Last-known model name (root session projection). */
51
+ currentModel: string | undefined;
52
+ /** Last-known thinking level (root session projection). */
53
+ currentThinking: ThinkingLevel | undefined;
54
+ /** THE App↔Pi room id for the current chat session. */
55
+ myRoomId: string | null;
56
+ /** Room meta hello payload persisted for reconnect replay. */
57
+ myRoomMeta: RoomMeta | null;
58
+ /** Shortid of the most recently attached peer (UX hint only). */
59
+ peerShort: string;
60
+ /** Epoch of this Pi process's session (stamped on first start). */
61
+ sessionStartedAt: number | null;
62
+ /** Per-(cwd,name) singleton lock backing the mesh registration. */
63
+ cwdLock: AcquiredLock | null;
64
+ /** Name the cwd-lock actually reserved (`name` or `name#N`). */
65
+ lockedName: string | null;
66
+ /** Relay candidate generation (invalidates in-flight starts/stops). */
67
+ relayLifecycleGeneration: number;
68
+ /** True when a relay start was deferred because no session id existed yet
69
+ * (design 01M1CAW0); the root session_start re-runs the start once the id
70
+ * is available. */
71
+ relayStartDeferred: boolean;
72
+ /** Root replacement authority epoch (session replacements). */
73
+ rootLifecycleGeneration: number;
74
+ /** Mesh join candidate generation. */
75
+ meshJoinGeneration: number;
76
+ /** SelfRevoke topology producer for the relay path. */
77
+ selfRevoke: SelfRevoke | null;
78
+ /** Epoch guarding the SelfRevoke producer identity. */
79
+ selfRevokeEpoch: number;
80
+ /** Producer epoch that last published a verified topology. */
81
+ selfRevokeTopologyReadyEpoch: number;
82
+ /** Last topology snapshot published by the producer. */
83
+ selfRevokeTopology: MeshTopologySnapshot | null;
84
+ /** Auto-listener dispose fn for the current relay connection. */
85
+ stopAutoListener: (() => void) | null;
86
+ /** Cached "any device is paired machine-wide" flag (peers.json). */
87
+ readonly hasGlobalPairings: boolean;
88
+ /** Connected owner channels, keyed by canonical owner pubkey. */
89
+ readonly activePeers: Map<string, PlainPeerChannel>;
90
+ /** Set by session_shutdown; blocks outgoing candidates until rearm. */
91
+ readonly disposed: boolean;
92
+ /** Always-fresh session_start ctx (model/registry fallback). */
93
+ readonly lastEventCtx: Pick<ExtensionContext, "compact" | "abort" | "ui"> | null;
94
+ /** The ROOT session's ExtensionAPI (never a subagent child's). */
95
+ readonly pi: ExtensionAPI | null;
96
+ /** The root session's pi sessionId, null pre-sessionManager. */
97
+ readonly rootSessionId: string | null;
98
+ /** True while `generation` is the current root lifecycle epoch. */
99
+ isCurrentRootLifecycle(generation: number): boolean;
100
+ /** Friendly (configured or derived) agent name for a cwd. */
101
+ displayName(cwd: string): string;
102
+ /** Room id for the current chat session, derived from the stable pi
103
+ * session id — or null when no session id exists yet, in which case the
104
+ * caller must NOT announce/join a room (design 01M1CAW0; the cwd-derived
105
+ * fallback is retired). */
106
+ deriveRoomId(cwd: string, name: string): string | null;
107
+ /** Friendly model name for room_meta. */
108
+ currentModelName(): string | undefined;
109
+ /** The ROOT session's state record (turn/agentRun/sessionManager). */
110
+ rootState(): {
111
+ sessionManager?: {
112
+ getSessionId(): string;
113
+ } | null;
114
+ };
115
+ /** Full teardown of relay-side state (relay off, bridge detached). */
116
+ goIdle(): void;
117
+ /** Reconnect backoff entry for a closed relay. */
118
+ onRelayClose(closedRelay: RelayClient): void;
119
+ /** Attach the pair_request auto-listener to a live relay. */
120
+ installAutoListener(relay: RelayClient): () => void;
121
+ /** Repaint the footer status line from current state. */
122
+ refreshFooter(ctx?: {
123
+ ui?: {
124
+ setStatus?: unknown;
125
+ setTitle?: unknown;
126
+ };
127
+ } | null): void;
128
+ /** Tear down an owner's live channel + report the revocation. */
129
+ revokeActiveOwnerRuntime(canonicalOwnerPubkey: string): void;
130
+ /** Attach the cross-PC bridge once relay + leader are both up. */
131
+ attachBridgeIfReady(): void;
132
+ /** Broadcast relay connectivity state to RPC clients. */
133
+ emitRelayState(force?: boolean): void;
134
+ /** Re-query the broker for the authoritative local peer count. */
135
+ refreshSessionPeerCount(peer: MeshNode, ctx?: Pick<ExtensionContext, "ui"> | null): void;
136
+ /** Queue an inbound mesh message for agent delivery. */
137
+ deliverMeshMessageToAgent(env: Envelope): void;
138
+ /** Reads peers.json and refreshes the global-pairings cache + footer. */
139
+ refreshPairingsCache(): void;
140
+ /** Tear down a connected owner's channel (revoke / disconnect). */
141
+ detachPeerChannel(appPeerId: string): void;
142
+ /** RPC control channel verbs (`relay:toggle` / `relay:on` / `relay:off`). */
143
+ handleControl(cmd: string): Promise<void>;
144
+ /** Relay connectivity label for status output. */
145
+ relayStatus(): "connected" | "reconnecting" | "disconnected";
146
+ /** Test-visible state: `idle` | `started` | derived `paired`. */
147
+ getState(): "idle" | "started" | "paired";
148
+ /** Hidden dev-only e2e UI harness (`/unbien test <scenario>`). */
149
+ runTestScenario(scenario: string): string;
150
+ /** ctx.ui.notify that never throws (stale-ctx safe). */
151
+ safeNotify(message: string, level?: "info" | "warning" | "error", preferred?: {
152
+ ui?: unknown;
153
+ } | null): void;
154
+ /** Rename this agent (mesh + relay room) — `/unbien rename`. */
155
+ renameAgent(newName: string): Promise<void>;
156
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=deps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deps.js","sourceRoot":"","sources":["../../src/commands/deps.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ /** Record that `sessionId` was born from the app fork request `req`. Best-effort. */
2
+ export declare function writeForkLink(sessionDir: string, sessionId: string, req: string): void;
3
+ /** Read + delete the fork request id for `sessionId`, or undefined when none. */
4
+ export declare function takeForkLink(sessionDir: string, sessionId: string): string | undefined;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Fork-born linkage: a tiny marker persisted by `_cmdFork`'s `withSession`
3
+ * (running in the NEW forked session) and consumed by that session's FIRST
4
+ * `session_sync_end`, which echoes the app's originating fork request id as
5
+ * `forked_from_req` so the app can auto-navigate to the new session.
6
+ *
7
+ * Why a FILE and not a module variable: `ctx.fork` replaces the AgentSession,
8
+ * and the pi TUI host re-evaluates this extension module fresh for the new
9
+ * session (jiti moduleCache:false), so a module-level stash set in withSession
10
+ * would be lost before the new session handles the app's session_sync. The
11
+ * marker is keyed by the new session id and lives in the session dir, so it
12
+ * survives the re-eval (and a process restart) and is unambiguous.
13
+ *
14
+ * Consumed ONCE (take = read + unlink): the app navigates on the first sync;
15
+ * leaving it would re-fire the jump on every reconnect.
16
+ */
17
+ import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
18
+ import { join } from "node:path";
19
+ function _linkPath(sessionDir, sessionId) {
20
+ return join(sessionDir, `.unbien-fork-${sessionId}.json`);
21
+ }
22
+ /** Record that `sessionId` was born from the app fork request `req`. Best-effort. */
23
+ export function writeForkLink(sessionDir, sessionId, req) {
24
+ try {
25
+ writeFileSync(_linkPath(sessionDir, sessionId), JSON.stringify({ req, ts: Date.now() }));
26
+ }
27
+ catch {
28
+ /* best-effort — a missing link just means no auto-nav */
29
+ }
30
+ }
31
+ /** Read + delete the fork request id for `sessionId`, or undefined when none. */
32
+ export function takeForkLink(sessionDir, sessionId) {
33
+ const path = _linkPath(sessionDir, sessionId);
34
+ try {
35
+ if (!existsSync(path))
36
+ return undefined;
37
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
38
+ unlinkSync(path);
39
+ return typeof parsed.req === "string" ? parsed.req : undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ //# sourceMappingURL=fork_link.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fork_link.js","sourceRoot":"","sources":["../../src/commands/fork_link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,SAAS,SAAS,CAAC,UAAkB,EAAE,SAAiB;IACtD,OAAO,IAAI,CAAC,UAAU,EAAE,gBAAgB,SAAS,OAAO,CAAC,CAAA;AAC3D,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,aAAa,CAC3B,UAAkB,EAClB,SAAiB,EACjB,GAAW;IAEX,IAAI,CAAC;QACH,aAAa,CACX,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,EAChC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CACxC,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,SAAiB;IAEjB,MAAM,IAAI,GAAG,SAAS,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IAC7C,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,SAAS,CAAA;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAsB,CAAA;QAC1E,UAAU,CAAC,IAAI,CAAC,CAAA;QAChB,OAAO,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAA;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `/unbien` housekeeping commands: service install/uninstall, the
3
+ * agent-network skill deploy, extension-dir/skill-path resolution, and the
4
+ * `unbien claude` CLI launcher.
5
+ *
6
+ * None of these touch index.ts module state, so they take no CommandDeps —
7
+ * everything they use is imported from pi-independent modules. Carved out
8
+ * of index.ts (phase 1 of the index.ts carve-up).
9
+ *
10
+ * NOTE: this file lives one directory deeper than index.ts used to, so the
11
+ * import.meta.url-based path math (extension dir, packaged skill, mesh
12
+ * server) climbs one extra level — behavior is otherwise identical.
13
+ */
14
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
15
+ /**
16
+ * `linkCli` controls whether we symlink `un-bien` into `~/.local/bin/`. The
17
+ * slash-command path passes `true` (user is inside Pi's TUI — they installed
18
+ * via `pi install npm:un-bien` and need us to expose the CLI for them). The
19
+ * standalone-CLI path passes `false` because the user is already running our
20
+ * binary from PATH (they did `npm install -g un-bien`), so re-linking would
21
+ * point their `un-bien` at the Pi-extension copy and diverge on upgrades.
22
+ */
23
+ /** Returns true on success, false when install failed (so the standalone CLI
24
+ * can exit non-zero — e.g. the Cockpit / CI detect failure by exit code).
25
+ * We do NOT process.exit here: this also runs inside the Pi TUI, where exiting
26
+ * would kill the session. */
27
+ export declare function _cmdInstall(ctx: Pick<ExtensionContext, "ui">, opts?: {
28
+ linkCli?: boolean;
29
+ }): boolean;
30
+ export declare function _cmdUninstall(ctx: Pick<ExtensionContext, "ui">, opts?: {
31
+ linkCli?: boolean;
32
+ }): void;
33
+ export declare function _deployAgentNetworkSkill(): void;
34
+ export declare function _cmdClaudeCli(args: string[]): Promise<void>;
@@ -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>;