@geohar/un-bien 0.7.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/LICENSE +21 -0
- package/README.md +726 -0
- package/dist/actions/handlers.d.ts +77 -0
- package/dist/actions/handlers.js +26 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +39 -0
- package/dist/actions/registry.js +62 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.d.ts +2 -0
- package/dist/bin/supervisord.js +86 -0
- package/dist/bin/supervisord.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +20 -0
- package/dist/daemon/client.js +131 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +176 -0
- package/dist/daemon/control_protocol.js +63 -0
- package/dist/daemon/control_protocol.js.map +1 -0
- package/dist/daemon/cron_log.d.ts +45 -0
- package/dist/daemon/cron_log.js +71 -0
- package/dist/daemon/cron_log.js.map +1 -0
- package/dist/daemon/cron_registry.d.ts +80 -0
- package/dist/daemon/cron_registry.js +198 -0
- package/dist/daemon/cron_registry.js.map +1 -0
- package/dist/daemon/id.d.ts +24 -0
- package/dist/daemon/id.js +36 -0
- package/dist/daemon/id.js.map +1 -0
- package/dist/daemon/install.d.ts +170 -0
- package/dist/daemon/install.js +603 -0
- package/dist/daemon/install.js.map +1 -0
- package/dist/daemon/registry.d.ts +63 -0
- package/dist/daemon/registry.js +153 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/rpc_child.d.ts +194 -0
- package/dist/daemon/rpc_child.js +419 -0
- package/dist/daemon/rpc_child.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +93 -0
- package/dist/daemon/supervisor.js +666 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension_ui_bridge.d.ts +26 -0
- package/dist/extension_ui_bridge.js +341 -0
- package/dist/extension_ui_bridge.js.map +1 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +5750 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/mesh_result.d.ts +10 -0
- package/dist/mcp/mesh_result.js +42 -0
- package/dist/mcp/mesh_result.js.map +1 -0
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +373 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/mesh/canonical.d.ts +30 -0
- package/dist/mesh/canonical.js +63 -0
- package/dist/mesh/canonical.js.map +1 -0
- package/dist/mesh/client.d.ts +18 -0
- package/dist/mesh/client.js +127 -0
- package/dist/mesh/client.js.map +1 -0
- package/dist/mesh/encoding.d.ts +38 -0
- package/dist/mesh/encoding.js +217 -0
- package/dist/mesh/encoding.js.map +1 -0
- package/dist/mesh/self_revoke.d.ts +73 -0
- package/dist/mesh/self_revoke.js +407 -0
- package/dist/mesh/self_revoke.js.map +1 -0
- package/dist/mesh/siblings.d.ts +49 -0
- package/dist/mesh/siblings.js +159 -0
- package/dist/mesh/siblings.js.map +1 -0
- package/dist/mesh/types.d.ts +34 -0
- package/dist/mesh/types.js +11 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/mesh/verify.d.ts +17 -0
- package/dist/mesh/verify.js +86 -0
- package/dist/mesh/verify.js.map +1 -0
- package/dist/pairing/crypto.d.ts +8 -0
- package/dist/pairing/crypto.js +22 -0
- package/dist/pairing/crypto.js.map +1 -0
- package/dist/pairing/qr.d.ts +59 -0
- package/dist/pairing/qr.js +127 -0
- package/dist/pairing/qr.js.map +1 -0
- package/dist/pairing/storage.d.ts +120 -0
- package/dist/pairing/storage.js +614 -0
- package/dist/pairing/storage.js.map +1 -0
- package/dist/panel_bridge.d.ts +15 -0
- package/dist/panel_bridge.js +409 -0
- package/dist/panel_bridge.js.map +1 -0
- package/dist/paths.d.ts +39 -0
- package/dist/paths.js +51 -0
- package/dist/paths.js.map +1 -0
- package/dist/protocol/codec.d.ts +7 -0
- package/dist/protocol/codec.js +48 -0
- package/dist/protocol/codec.js.map +1 -0
- package/dist/protocol/types.d.ts +404 -0
- package/dist/protocol/types.js +2 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/rooms.d.ts +42 -0
- package/dist/rooms.js +78 -0
- package/dist/rooms.js.map +1 -0
- package/dist/session/bridge.d.ts +37 -0
- package/dist/session/bridge.js +134 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/broker.d.ts +189 -0
- package/dist/session/broker.js +527 -0
- package/dist/session/broker.js.map +1 -0
- package/dist/session/broker_remote.d.ts +74 -0
- package/dist/session/broker_remote.js +581 -0
- package/dist/session/broker_remote.js.map +1 -0
- package/dist/session/cwd_lock.d.ts +33 -0
- package/dist/session/cwd_lock.js +127 -0
- package/dist/session/cwd_lock.js.map +1 -0
- package/dist/session/debug_log.d.ts +3 -0
- package/dist/session/debug_log.js +32 -0
- package/dist/session/debug_log.js.map +1 -0
- package/dist/session/envelope.d.ts +33 -0
- package/dist/session/envelope.js +117 -0
- package/dist/session/envelope.js.map +1 -0
- package/dist/session/global_config.d.ts +33 -0
- package/dist/session/global_config.js +73 -0
- package/dist/session/global_config.js.map +1 -0
- package/dist/session/ipc.d.ts +27 -0
- package/dist/session/ipc.js +22 -0
- package/dist/session/ipc.js.map +1 -0
- package/dist/session/leader_election.d.ts +32 -0
- package/dist/session/leader_election.js +108 -0
- package/dist/session/leader_election.js.map +1 -0
- package/dist/session/local_config.d.ts +67 -0
- package/dist/session/local_config.js +193 -0
- package/dist/session/local_config.js.map +1 -0
- package/dist/session/mesh_node.d.ts +116 -0
- package/dist/session/mesh_node.js +596 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/peer.d.ts +139 -0
- package/dist/session/peer.js +474 -0
- package/dist/session/peer.js.map +1 -0
- package/dist/session/peer_inventory.d.ts +13 -0
- package/dist/session/peer_inventory.js +48 -0
- package/dist/session/peer_inventory.js.map +1 -0
- package/dist/session/peer_limits.d.ts +9 -0
- package/dist/session/peer_limits.js +24 -0
- package/dist/session/peer_limits.js.map +1 -0
- package/dist/session/rpc_envelope.d.ts +108 -0
- package/dist/session/rpc_envelope.js +221 -0
- package/dist/session/rpc_envelope.js.map +1 -0
- package/dist/session/rpc_inbound.d.ts +55 -0
- package/dist/session/rpc_inbound.js +136 -0
- package/dist/session/rpc_inbound.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +39 -0
- package/dist/session/setup_wizard.js +63 -0
- package/dist/session/setup_wizard.js.map +1 -0
- package/dist/session/tools.d.ts +24 -0
- package/dist/session/tools.js +272 -0
- package/dist/session/tools.js.map +1 -0
- package/dist/session/wizard.d.ts +13 -0
- package/dist/session/wizard.js +20 -0
- package/dist/session/wizard.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +52 -0
- package/dist/transport/peer_channel.js +145 -0
- package/dist/transport/peer_channel.js.map +1 -0
- package/dist/transport/pi_forward_client.d.ts +29 -0
- package/dist/transport/pi_forward_client.js +68 -0
- package/dist/transport/pi_forward_client.js.map +1 -0
- package/dist/transport/relay_client.d.ts +96 -0
- package/dist/transport/relay_client.js +210 -0
- package/dist/transport/relay_client.js.map +1 -0
- package/dist/ui/footer.d.ts +32 -0
- package/dist/ui/footer.js +34 -0
- package/dist/ui/footer.js.map +1 -0
- package/docs/daemon.md +289 -0
- package/package.json +92 -0
- package/service-templates/launchd.plist.template +35 -0
- package/service-templates/systemd.service.template +19 -0
- package/service-templates/task-launcher.vbs.template +10 -0
- package/service-templates/task-scheduler.xml.template +38 -0
- package/skills/agent-network/SKILL.md +310 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export interface LocalConfig {
|
|
2
|
+
agent_name?: string;
|
|
3
|
+
/**
|
|
4
|
+
* If true (default), `/unbien` with no args auto-joins the local UDS
|
|
5
|
+
* mesh and starts the relay on a fresh terminal. The field name is
|
|
6
|
+
* historical (plano 21); the UX wording was reworked to "use the relay
|
|
7
|
+
* on this terminal to connect to the remote mesh (mobile + PCs)". Legacy
|
|
8
|
+
* configs without this field are treated as `true` for backward compat.
|
|
9
|
+
*/
|
|
10
|
+
auto_start_relay?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* un-bien remote launch: when true, this machine HONORS `session_launch`
|
|
13
|
+
* requests from a paired owner (spawn a new pi session). Default FALSE —
|
|
14
|
+
* remote process spawn is authority-sensitive, so it's strictly opt-in.
|
|
15
|
+
* Advertised as the `remote_launch` capability only when enabled.
|
|
16
|
+
*/
|
|
17
|
+
allow_remote_launch?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalize a name segment to a mesh-safe token: trim, replace the addressing
|
|
21
|
+
* separators (`/ : @ #`) and whitespace runs with `-`, collapse repeats, strip
|
|
22
|
+
* edges. The `@` is included so a sanitized name can never contain the address
|
|
23
|
+
* separator — `<cwd>@<name>` stays unambiguous on the wire. Returns undefined
|
|
24
|
+
* when the input isn't a usable non-empty string, sanitizes to empty, or is a
|
|
25
|
+
* reserved addressing keyword (`broadcast` / `broker`). Used by the broker's
|
|
26
|
+
* `sanitizeMeshName` to keep the `<nome>` half of a peer address safe to
|
|
27
|
+
* compose (plan/38).
|
|
28
|
+
*/
|
|
29
|
+
export declare function sanitizeSegment(v: unknown): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Migrate a persisted `agent_name` to the plan/38 leaf-name model (decision E).
|
|
32
|
+
* Two legacy shapes get rewritten on read so a pre-fix config never fossilizes a
|
|
33
|
+
* runtime accident as if it were an explicit choice:
|
|
34
|
+
*
|
|
35
|
+
* - **`#N` collision suffix** — could only have come from a broker/lock
|
|
36
|
+
* assignment (the user can't type `#`: `sanitizeSegment` maps it to `-`), so
|
|
37
|
+
* a trailing `#<digits>` is stripped and the clean base re-derived.
|
|
38
|
+
* - **legacy `parent/folder`** — the old `defaultAgentName` shape; the `/`
|
|
39
|
+
* means it predates the leaf-only model, so we keep only the leaf segment.
|
|
40
|
+
*
|
|
41
|
+
* Returns the cleaned name, or undefined when nothing usable remains (so the
|
|
42
|
+
* caller falls back to `defaultAgentName(cwd)`).
|
|
43
|
+
*/
|
|
44
|
+
export declare function migrateAgentName(raw: string): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* True when a local config is available for this cwd — inline via
|
|
47
|
+
* `UNBIEN_DIRECT_CONFIG`, as `<cwd>/.pi/un-bien/config.json` on disk, or a
|
|
48
|
+
* machine-wide `defaults` block in the global config. A global default counts
|
|
49
|
+
* as "configured" so setting it suppresses the first-run wizard and lets
|
|
50
|
+
* session_start auto-init everywhere (the intent of "I've set the default").
|
|
51
|
+
*/
|
|
52
|
+
export declare function localConfigExists(cwd: string): boolean;
|
|
53
|
+
export declare function loadLocalConfig(cwd: string): LocalConfig;
|
|
54
|
+
export declare function saveLocalConfig(cwd: string, patch: Partial<LocalConfig>): void;
|
|
55
|
+
/**
|
|
56
|
+
* Default agent name when none is configured (plan/38 decision D): the **leaf**
|
|
57
|
+
* of the cwd, `basename(cwd)`. The cwd now travels as its own address axis
|
|
58
|
+
* (`<cwd>@<nome>`), so the name no longer needs the `parent/folder` prefix that
|
|
59
|
+
* used to disambiguate folders — the broker keys peers by `(cwd, nome)`, and a
|
|
60
|
+
* clean leaf means `#N` almost never fires. Falls back to `"agent"` for a
|
|
61
|
+
* path with no usable basename (root / empty).
|
|
62
|
+
*/
|
|
63
|
+
export declare function defaultAgentName(cwd: string): string;
|
|
64
|
+
/** Resolves auto_start_relay with backward-compat (undefined → true). */
|
|
65
|
+
export declare function effectiveAutoStartRelay(cfg: LocalConfig): boolean;
|
|
66
|
+
/** Remote launch is OFF unless explicitly enabled (authority-sensitive). */
|
|
67
|
+
export declare function effectiveAllowRemoteLaunch(cfg: LocalConfig): boolean;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
|
+
import { loadConfig } from "../config.js";
|
|
4
|
+
const LOCAL_DIR = ".pi/un-bien";
|
|
5
|
+
const LOCAL_FILE = "config.json";
|
|
6
|
+
/**
|
|
7
|
+
* Escape hatch: when set, carries the WHOLE local config as inline JSON,
|
|
8
|
+
* bypassing the on-disk `config.json`. For CI/ops/daemons that inject config
|
|
9
|
+
* via env instead of writing a file — mirrors `UNBIEN_RELAY` for the relay
|
|
10
|
+
* URL. Takes precedence over the file; an unset/empty/unparseable value falls
|
|
11
|
+
* back to the file (never fatal).
|
|
12
|
+
*/
|
|
13
|
+
const DIRECT_CONFIG_ENV = "UNBIEN_DIRECT_CONFIG";
|
|
14
|
+
function pathFor(cwd) {
|
|
15
|
+
return join(cwd, LOCAL_DIR, LOCAL_FILE);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Normalize a name segment to a mesh-safe token: trim, replace the addressing
|
|
19
|
+
* separators (`/ : @ #`) and whitespace runs with `-`, collapse repeats, strip
|
|
20
|
+
* edges. The `@` is included so a sanitized name can never contain the address
|
|
21
|
+
* separator — `<cwd>@<name>` stays unambiguous on the wire. Returns undefined
|
|
22
|
+
* when the input isn't a usable non-empty string, sanitizes to empty, or is a
|
|
23
|
+
* reserved addressing keyword (`broadcast` / `broker`). Used by the broker's
|
|
24
|
+
* `sanitizeMeshName` to keep the `<nome>` half of a peer address safe to
|
|
25
|
+
* compose (plan/38).
|
|
26
|
+
*/
|
|
27
|
+
export function sanitizeSegment(v) {
|
|
28
|
+
if (typeof v !== "string")
|
|
29
|
+
return undefined;
|
|
30
|
+
const token = v
|
|
31
|
+
.trim()
|
|
32
|
+
.replace(/[/:@#\s]+/g, "-")
|
|
33
|
+
.replace(/-{2,}/g, "-")
|
|
34
|
+
.replace(/^-+|-+$/g, "");
|
|
35
|
+
if (!token)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (token.toLowerCase() === "broadcast" || token.toLowerCase() === "broker")
|
|
38
|
+
return undefined;
|
|
39
|
+
return token;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Migrate a persisted `agent_name` to the plan/38 leaf-name model (decision E).
|
|
43
|
+
* Two legacy shapes get rewritten on read so a pre-fix config never fossilizes a
|
|
44
|
+
* runtime accident as if it were an explicit choice:
|
|
45
|
+
*
|
|
46
|
+
* - **`#N` collision suffix** — could only have come from a broker/lock
|
|
47
|
+
* assignment (the user can't type `#`: `sanitizeSegment` maps it to `-`), so
|
|
48
|
+
* a trailing `#<digits>` is stripped and the clean base re-derived.
|
|
49
|
+
* - **legacy `parent/folder`** — the old `defaultAgentName` shape; the `/`
|
|
50
|
+
* means it predates the leaf-only model, so we keep only the leaf segment.
|
|
51
|
+
*
|
|
52
|
+
* Returns the cleaned name, or undefined when nothing usable remains (so the
|
|
53
|
+
* caller falls back to `defaultAgentName(cwd)`).
|
|
54
|
+
*/
|
|
55
|
+
export function migrateAgentName(raw) {
|
|
56
|
+
// Legacy `parent/folder` (or any path-ish value) → keep the trailing segment.
|
|
57
|
+
const leaf = raw.includes("/") ? raw.slice(raw.lastIndexOf("/") + 1) : raw;
|
|
58
|
+
// Drop a runtime collision suffix a pre-fix build may have frozen into config.
|
|
59
|
+
const clean = leaf.replace(/#\d+$/, "").trim();
|
|
60
|
+
return clean.length > 0 ? clean : undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Parse a raw JSON string into a LocalConfig, surfacing only known fields.
|
|
64
|
+
* Returns null when the input isn't a usable JSON object. Legacy `session_name`
|
|
65
|
+
* from pre-refactor configs is silently dropped — the local UDS mesh is now
|
|
66
|
+
* always a single fixed session, so the field has no meaning.
|
|
67
|
+
*/
|
|
68
|
+
function parseLocalConfig(raw) {
|
|
69
|
+
let parsed;
|
|
70
|
+
try {
|
|
71
|
+
parsed = JSON.parse(raw);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
77
|
+
return null;
|
|
78
|
+
const src = parsed;
|
|
79
|
+
const cfg = {};
|
|
80
|
+
if (typeof src["agent_name"] === "string") {
|
|
81
|
+
// Migrate on read (plan/38 decision E): strip a frozen `#N` and the legacy
|
|
82
|
+
// `parent/folder` shape so neither fossilizes as an explicit name.
|
|
83
|
+
const migrated = migrateAgentName(src["agent_name"]);
|
|
84
|
+
if (migrated)
|
|
85
|
+
cfg.agent_name = migrated;
|
|
86
|
+
}
|
|
87
|
+
if (typeof src["auto_start_relay"] === "boolean")
|
|
88
|
+
cfg.auto_start_relay = src["auto_start_relay"];
|
|
89
|
+
if (typeof src["allow_remote_launch"] === "boolean")
|
|
90
|
+
cfg.allow_remote_launch = src["allow_remote_launch"];
|
|
91
|
+
return cfg;
|
|
92
|
+
}
|
|
93
|
+
/** Inline config from `UNBIEN_DIRECT_CONFIG`, when set + parseable; else null. */
|
|
94
|
+
function directConfig() {
|
|
95
|
+
const raw = process.env[DIRECT_CONFIG_ENV];
|
|
96
|
+
if (!raw || raw.trim().length === 0)
|
|
97
|
+
return null;
|
|
98
|
+
return parseLocalConfig(raw);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Machine-wide fallback for local-config fields, from the `defaults` block of
|
|
102
|
+
* the global `~/.pi/un-bien/config.json` (see `UnBienConfig.defaults`). Lets
|
|
103
|
+
* you pin a default once instead of dropping a `config.json` into every repo.
|
|
104
|
+
* Returns an empty object when no `defaults` block is present, so the whole
|
|
105
|
+
* feature is inert (and every path below identical to before) unless opted in.
|
|
106
|
+
*/
|
|
107
|
+
function globalLocalDefaults() {
|
|
108
|
+
const d = loadConfig().defaults;
|
|
109
|
+
const cfg = {};
|
|
110
|
+
if (d && typeof d.auto_start_relay === "boolean")
|
|
111
|
+
cfg.auto_start_relay = d.auto_start_relay;
|
|
112
|
+
return cfg;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* True when a local config is available for this cwd — inline via
|
|
116
|
+
* `UNBIEN_DIRECT_CONFIG`, as `<cwd>/.pi/un-bien/config.json` on disk, or a
|
|
117
|
+
* machine-wide `defaults` block in the global config. A global default counts
|
|
118
|
+
* as "configured" so setting it suppresses the first-run wizard and lets
|
|
119
|
+
* session_start auto-init everywhere (the intent of "I've set the default").
|
|
120
|
+
*/
|
|
121
|
+
export function localConfigExists(cwd) {
|
|
122
|
+
return (directConfig() !== null ||
|
|
123
|
+
existsSync(pathFor(cwd)) ||
|
|
124
|
+
Object.keys(globalLocalDefaults()).length > 0);
|
|
125
|
+
}
|
|
126
|
+
export function loadLocalConfig(cwd) {
|
|
127
|
+
// Layering (later wins): global `defaults` < per-cwd file / inline env. The
|
|
128
|
+
// inline `UNBIEN_DIRECT_CONFIG` still takes precedence over the on-disk
|
|
129
|
+
// file; an unset/empty/malformed env falls through to it. Any field left
|
|
130
|
+
// unset by the winning source inherits the global default.
|
|
131
|
+
const defaults = globalLocalDefaults();
|
|
132
|
+
const direct = directConfig();
|
|
133
|
+
if (direct)
|
|
134
|
+
return { ...defaults, ...direct };
|
|
135
|
+
const p = pathFor(cwd);
|
|
136
|
+
if (!existsSync(p))
|
|
137
|
+
return { ...defaults };
|
|
138
|
+
try {
|
|
139
|
+
return {
|
|
140
|
+
...defaults,
|
|
141
|
+
...(parseLocalConfig(readFileSync(p, "utf8")) ?? {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return { ...defaults };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export function saveLocalConfig(cwd, patch) {
|
|
149
|
+
const p = pathFor(cwd);
|
|
150
|
+
const current = loadLocalConfig(cwd);
|
|
151
|
+
const next = { ...current, ...patch };
|
|
152
|
+
// Always persist auto_start_relay explicitly (default true) so future reads
|
|
153
|
+
// never need to guess. Backward-compat: legacy files without the field
|
|
154
|
+
// are treated as true on read; we lock that intent in on first save.
|
|
155
|
+
if (typeof next.auto_start_relay !== "boolean")
|
|
156
|
+
next.auto_start_relay = true;
|
|
157
|
+
// Best-effort persistence: a read-only config.json is a legitimate deployment
|
|
158
|
+
// (NixOS/Home Manager symlink into the immutable Nix store, read-only root,
|
|
159
|
+
// EPERM). The name/config sync is cosmetic — it must NEVER crash the pi
|
|
160
|
+
// process with an uncaughtException. `saveLocalConfig` is reached via
|
|
161
|
+
// fire-and-forget async paths (`void _syncNameFromPi()` from `turn_start` /
|
|
162
|
+
// `session_start`), so a sync throw from `mkdirSync`/`writeFileSync` sails
|
|
163
|
+
// past the runner's per-handler try/catch and takes down pi. Guard both fs
|
|
164
|
+
// calls together so a partial attempt can't throw past the caller.
|
|
165
|
+
try {
|
|
166
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
167
|
+
writeFileSync(p, JSON.stringify(next, null, 2));
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
171
|
+
console.warn(`[un-bien] could not persist local config ${p}: ${message}`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Default agent name when none is configured (plan/38 decision D): the **leaf**
|
|
176
|
+
* of the cwd, `basename(cwd)`. The cwd now travels as its own address axis
|
|
177
|
+
* (`<cwd>@<nome>`), so the name no longer needs the `parent/folder` prefix that
|
|
178
|
+
* used to disambiguate folders — the broker keys peers by `(cwd, nome)`, and a
|
|
179
|
+
* clean leaf means `#N` almost never fires. Falls back to `"agent"` for a
|
|
180
|
+
* path with no usable basename (root / empty).
|
|
181
|
+
*/
|
|
182
|
+
export function defaultAgentName(cwd) {
|
|
183
|
+
return basename(cwd) || "agent";
|
|
184
|
+
}
|
|
185
|
+
/** Resolves auto_start_relay with backward-compat (undefined → true). */
|
|
186
|
+
export function effectiveAutoStartRelay(cfg) {
|
|
187
|
+
return cfg.auto_start_relay !== false;
|
|
188
|
+
}
|
|
189
|
+
/** Remote launch is OFF unless explicitly enabled (authority-sensitive). */
|
|
190
|
+
export function effectiveAllowRemoteLaunch(cfg) {
|
|
191
|
+
return cfg.allow_remote_launch === true;
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=local_config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local_config.js","sourceRoot":"","sources":["../../src/session/local_config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { SessionPeer, type AckResult } from "./peer.js";
|
|
2
|
+
import type { Envelope } from "./envelope.js";
|
|
3
|
+
import type { Broker } from "./broker.js";
|
|
4
|
+
import { RelayClient } from "../transport/relay_client.js";
|
|
5
|
+
import type { Ed25519Keypair } from "./../pairing/crypto.js";
|
|
6
|
+
import type { MeshTopologySnapshot } from "../mesh/siblings.js";
|
|
7
|
+
/**
|
|
8
|
+
* MeshNode is the composition point for the local UDS mesh plus the optional
|
|
9
|
+
* cross-PC Relay bridge. Topology is retained independently from the current
|
|
10
|
+
* role, Relay, Broker, or bridge publication lifecycle.
|
|
11
|
+
*/
|
|
12
|
+
/** Self-managed-relay bridge config (MCP path). */
|
|
13
|
+
export interface MeshSelfRelayBridge {
|
|
14
|
+
/** Relay URL in http(s):// form (converted to ws(s):// internally). */
|
|
15
|
+
relayUrl: string;
|
|
16
|
+
/** cwd — derives the relay room id and the room_meta. */
|
|
17
|
+
cwd: string;
|
|
18
|
+
/** Display name for room_meta. Defaults to the assigned mesh name. */
|
|
19
|
+
sessionName?: string;
|
|
20
|
+
/** Advanced/test override; production defaults to five seconds per request. */
|
|
21
|
+
meshRequestTimeoutMs?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface MeshNodeOptions {
|
|
24
|
+
/** UDS broker socket path (e.g. ~/.pi/un-bien/sessions/local/broker.sock). */
|
|
25
|
+
sockPath: string;
|
|
26
|
+
/** Requested mesh name (broker may add a #N collision suffix). */
|
|
27
|
+
name: string;
|
|
28
|
+
cwd?: string;
|
|
29
|
+
takeoverExisting?: boolean;
|
|
30
|
+
auditPath?: string;
|
|
31
|
+
/** Self-managed relay bridge — brought up if this node leads. */
|
|
32
|
+
bridge?: MeshSelfRelayBridge;
|
|
33
|
+
/** Diagnostic logger. Defaults to a no-op (avoids leaking into TUIs). */
|
|
34
|
+
log?: (msg: string) => void;
|
|
35
|
+
}
|
|
36
|
+
export type { AckResult } from "./peer.js";
|
|
37
|
+
export declare class MeshNode {
|
|
38
|
+
private readonly peer_;
|
|
39
|
+
private readonly log;
|
|
40
|
+
private latestTopology;
|
|
41
|
+
private topologyRevision;
|
|
42
|
+
private bridgeGeneration;
|
|
43
|
+
private bridgeAttachInFlight;
|
|
44
|
+
private bridgeAttachQueued;
|
|
45
|
+
private closed;
|
|
46
|
+
private closeInFlight;
|
|
47
|
+
private activeBridge;
|
|
48
|
+
private relay;
|
|
49
|
+
private relayOwned;
|
|
50
|
+
private relayCloseHandler;
|
|
51
|
+
private brokerRemote;
|
|
52
|
+
private piForward;
|
|
53
|
+
private keypair;
|
|
54
|
+
private bridgeParams;
|
|
55
|
+
private reconnectWired;
|
|
56
|
+
private readonly closedOwnedRelays;
|
|
57
|
+
/** Self-managed relay reconnect state. Injected Relay reconnect is host-owned. */
|
|
58
|
+
private relayReconnectTimer;
|
|
59
|
+
private relayBackoffIdx;
|
|
60
|
+
private static readonly RELAY_RECONNECT_BACKOFFS_MS;
|
|
61
|
+
constructor(opts: MeshNodeOptions);
|
|
62
|
+
/** Join (or lead) the mesh. Resolves with the assigned name. */
|
|
63
|
+
connect(): Promise<string>;
|
|
64
|
+
/** Attach an externally-owned Relay. MeshNode never closes this Relay. */
|
|
65
|
+
attachBridge(opts: {
|
|
66
|
+
relay: RelayClient;
|
|
67
|
+
relayUrl: string;
|
|
68
|
+
keypair?: Ed25519Keypair;
|
|
69
|
+
meshRequestTimeoutMs?: number;
|
|
70
|
+
}): Promise<void>;
|
|
71
|
+
/** Retain a canonical immutable topology independently from bridge state. */
|
|
72
|
+
setTopology(snapshot: MeshTopologySnapshot): void;
|
|
73
|
+
hasTopology(): boolean;
|
|
74
|
+
/** Forget bridge parameters and tear down publication, retaining topology. */
|
|
75
|
+
detachBridge(): void;
|
|
76
|
+
private _assertOpen;
|
|
77
|
+
private _wireReconnect;
|
|
78
|
+
private _onReconnect;
|
|
79
|
+
/** One serialized attach loop. Newer generations are drained before exit. */
|
|
80
|
+
private _requestBridge;
|
|
81
|
+
private _attemptBridge;
|
|
82
|
+
private _attemptIsStale;
|
|
83
|
+
private _relayIsClosed;
|
|
84
|
+
private _removeMarker;
|
|
85
|
+
private _closeOwnedRelay;
|
|
86
|
+
private _teardownPublishedBridge;
|
|
87
|
+
private _onSelfRelayClosed;
|
|
88
|
+
private _clearRelayReconnectTimer;
|
|
89
|
+
private _scheduleRelayReconnect;
|
|
90
|
+
private _attemptRelayReconnect;
|
|
91
|
+
/** Announce the local peer set to siblings (Pi broker peer_joined/left). */
|
|
92
|
+
onLocalPeersChanged(local: string[]): void;
|
|
93
|
+
/** True when the cross-PC relay bridge is active (this node is leader). */
|
|
94
|
+
hasBridge(): boolean;
|
|
95
|
+
/** The underlying SessionPeer — for consumers that need it directly (tools). */
|
|
96
|
+
peer(): SessionPeer;
|
|
97
|
+
/** Fire-and-forget send. `to` may be a name, `<pc>:<name>`, or "broadcast". */
|
|
98
|
+
send(to: string | string[], body: unknown, re?: string | null): Promise<void>;
|
|
99
|
+
/** Unicast send + await broker ACK (received/busy/denied/timeout). */
|
|
100
|
+
sendWithAck(to: string, body: unknown, re?: string | null, timeoutMs?: number): Promise<AckResult>;
|
|
101
|
+
/** Send + await the first reply whose `re` matches the outbound id. */
|
|
102
|
+
request(to: string, body: unknown, timeoutMs?: number): Promise<Envelope>;
|
|
103
|
+
/** Subscribe to inbound envelopes. Returns an unsubscribe fn. */
|
|
104
|
+
onMessage(handler: (env: Envelope) => void): () => void;
|
|
105
|
+
/** Subscribe to post-failover reconnects. Returns an unsubscribe fn. */
|
|
106
|
+
onReconnect(handler: () => void): () => void;
|
|
107
|
+
/** Assigned clean mesh name (after any #N collision suffix). */
|
|
108
|
+
name(): string;
|
|
109
|
+
/** Canonical mesh address (`[<pc>:]<cwd>@<nome>`) — echo, never compose. */
|
|
110
|
+
address(): string;
|
|
111
|
+
rename(newName: string): Promise<string>;
|
|
112
|
+
currentRole(): "leader" | "follower";
|
|
113
|
+
localBroker(): Broker | null;
|
|
114
|
+
listPeers(timeoutMs?: number): Promise<string[]>;
|
|
115
|
+
close(): Promise<void>;
|
|
116
|
+
}
|