remote-pi 0.4.2 → 0.5.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 (77) hide show
  1. package/README.md +33 -0
  2. package/dist/daemon/client.js +5 -2
  3. package/dist/daemon/client.js.map +1 -1
  4. package/dist/daemon/control_protocol.d.ts +68 -0
  5. package/dist/daemon/control_protocol.js.map +1 -1
  6. package/dist/daemon/cron_log.d.ts +45 -0
  7. package/dist/daemon/cron_log.js +72 -0
  8. package/dist/daemon/cron_log.js.map +1 -0
  9. package/dist/daemon/cron_registry.d.ts +80 -0
  10. package/dist/daemon/cron_registry.js +194 -0
  11. package/dist/daemon/cron_registry.js.map +1 -0
  12. package/dist/daemon/id.d.ts +6 -0
  13. package/dist/daemon/id.js +6 -0
  14. package/dist/daemon/id.js.map +1 -1
  15. package/dist/daemon/install.d.ts +9 -2
  16. package/dist/daemon/install.js +54 -10
  17. package/dist/daemon/install.js.map +1 -1
  18. package/dist/daemon/registry.d.ts +17 -1
  19. package/dist/daemon/registry.js +34 -4
  20. package/dist/daemon/registry.js.map +1 -1
  21. package/dist/daemon/rpc_child.d.ts +64 -1
  22. package/dist/daemon/rpc_child.js +164 -8
  23. package/dist/daemon/rpc_child.js.map +1 -1
  24. package/dist/daemon/supervisor.d.ts +44 -0
  25. package/dist/daemon/supervisor.js +265 -22
  26. package/dist/daemon/supervisor.js.map +1 -1
  27. package/dist/index.d.ts +68 -11
  28. package/dist/index.js +0 -0
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/mesh_server.js +19 -10
  31. package/dist/mcp/mesh_server.js.map +1 -1
  32. package/dist/pairing/qr.d.ts +8 -1
  33. package/dist/pairing/qr.js +13 -3
  34. package/dist/pairing/qr.js.map +1 -1
  35. package/dist/protocol/codec.js +1 -0
  36. package/dist/protocol/codec.js.map +1 -1
  37. package/dist/protocol/types.d.ts +11 -0
  38. package/dist/rooms.d.ts +20 -0
  39. package/dist/rooms.js +35 -0
  40. package/dist/rooms.js.map +1 -1
  41. package/dist/session/address.d.ts +49 -0
  42. package/dist/session/address.js +58 -0
  43. package/dist/session/address.js.map +1 -0
  44. package/dist/session/broker.d.ts +79 -3
  45. package/dist/session/broker.js +155 -28
  46. package/dist/session/broker.js.map +1 -1
  47. package/dist/session/broker_remote.d.ts +30 -10
  48. package/dist/session/broker_remote.js +77 -39
  49. package/dist/session/broker_remote.js.map +1 -1
  50. package/dist/session/cwd_lock.d.ts +7 -2
  51. package/dist/session/cwd_lock.js +39 -9
  52. package/dist/session/cwd_lock.js.map +1 -1
  53. package/dist/session/global_config.d.ts +12 -2
  54. package/dist/session/global_config.js +16 -3
  55. package/dist/session/global_config.js.map +1 -1
  56. package/dist/session/ipc.d.ts +27 -0
  57. package/dist/session/ipc.js +22 -0
  58. package/dist/session/ipc.js.map +1 -0
  59. package/dist/session/leader_election.js +8 -2
  60. package/dist/session/leader_election.js.map +1 -1
  61. package/dist/session/local_config.d.ts +36 -6
  62. package/dist/session/local_config.js +103 -28
  63. package/dist/session/local_config.js.map +1 -1
  64. package/dist/session/mesh_message.d.ts +20 -0
  65. package/dist/session/mesh_message.js +28 -0
  66. package/dist/session/mesh_message.js.map +1 -0
  67. package/dist/session/mesh_node.d.ts +15 -1
  68. package/dist/session/mesh_node.js +26 -5
  69. package/dist/session/mesh_node.js.map +1 -1
  70. package/dist/session/peer.d.ts +19 -2
  71. package/dist/session/peer.js +45 -9
  72. package/dist/session/peer.js.map +1 -1
  73. package/dist/session/tools.js +14 -12
  74. package/dist/session/tools.js.map +1 -1
  75. package/package.json +2 -1
  76. package/service-templates/task-scheduler.xml.template +38 -0
  77. package/skills/agent-network/SKILL.md +63 -26
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipc.js","sourceRoot":"","sources":["../../src/session/ipc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAuB3D,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,OAAa,UAAU,EAAE;IACrD,OAAO,IAAI,KAAK,OAAO,CAAC;AAC1B,CAAC;AAED,0DAA0D;AAC1D,SAAS,IAAI,CAAC,CAAS;IACrB,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,MAAc,EACd,QAAgB,EAChB,OAAa,UAAU,EAAE,EACzB,IAAa;IAEb,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,IAAI,QAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC;QACxD,OAAO,0BAA0B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;IACvD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { createConnection, createServer } from "node:net";
2
2
  import { existsSync, lstatSync, unlinkSync } from "node:fs";
3
3
  import { setTimeout as delay } from "node:timers/promises";
4
+ import { usesNamedPipe } from "./ipc.js";
4
5
  const MAX_ATTEMPTS = 20;
5
6
  const BASE_BACKOFF_MS = 30;
6
7
  const JITTER_MS = 70;
@@ -13,12 +14,17 @@ const PROBE_TIMEOUT_MS = 500;
13
14
  * Returns the role + the live handle (server for leader, socket for follower).
14
15
  */
15
16
  export async function joinOrLead(sockPath) {
17
+ const pipe = usesNamedPipe();
16
18
  for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
17
- if (existsSync(sockPath)) {
19
+ // Windows named pipes have no file to `existsSync`; always connect-probe
20
+ // first and never `unlink` (the pipe auto-disappears when its owner exits).
21
+ // POSIX keeps the existsSync fast-path + stale-socket cleanup.
22
+ if (pipe || existsSync(sockPath)) {
18
23
  const sock = await _tryConnect(sockPath);
19
24
  if (sock)
20
25
  return { role: "follower", socket: sock };
21
- _removeStaleSock(sockPath);
26
+ if (!pipe)
27
+ _removeStaleSock(sockPath);
22
28
  }
23
29
  const server = await _tryBind(sockPath);
24
30
  if (server)
@@ -1 +1 @@
1
- {"version":3,"file":"leader_election.js","sourceRoot":"","sources":["../../src/session/leader_election.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"leader_election.js","sourceRoot":"","sources":["../../src/session/leader_election.ts"],"names":[],"mappings":"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"}
@@ -9,16 +9,46 @@ export interface LocalConfig {
9
9
  */
10
10
  auto_start_relay?: boolean;
11
11
  }
12
- /** Returns true when `<cwd>/.pi/remote-pi/config.json` exists on disk. */
12
+ /**
13
+ * Normalize a name segment to a mesh-safe token: trim, replace the addressing
14
+ * separators (`/ : @ #`) and whitespace runs with `-`, collapse repeats, strip
15
+ * edges. The `@` is included so a sanitized name can never contain the address
16
+ * separator — `<cwd>@<name>` stays unambiguous on the wire. Returns undefined
17
+ * when the input isn't a usable non-empty string, sanitizes to empty, or is a
18
+ * reserved addressing keyword (`broadcast` / `broker`). Used by the broker's
19
+ * `sanitizeMeshName` to keep the `<nome>` half of a peer address safe to
20
+ * compose (plan/38).
21
+ */
22
+ export declare function sanitizeSegment(v: unknown): string | undefined;
23
+ /**
24
+ * Migrate a persisted `agent_name` to the plan/38 leaf-name model (decision E).
25
+ * Two legacy shapes get rewritten on read so a pre-fix config never fossilizes a
26
+ * runtime accident as if it were an explicit choice:
27
+ *
28
+ * - **`#N` collision suffix** — could only have come from a broker/lock
29
+ * assignment (the user can't type `#`: `sanitizeSegment` maps it to `-`), so
30
+ * a trailing `#<digits>` is stripped and the clean base re-derived.
31
+ * - **legacy `parent/folder`** — the old `defaultAgentName` shape; the `/`
32
+ * means it predates the leaf-only model, so we keep only the leaf segment.
33
+ *
34
+ * Returns the cleaned name, or undefined when nothing usable remains (so the
35
+ * caller falls back to `defaultAgentName(cwd)`).
36
+ */
37
+ export declare function migrateAgentName(raw: string): string | undefined;
38
+ /**
39
+ * True when a local config is available for this cwd — either inline via
40
+ * `REMOTE_PI_DIRECT_CONFIG` or as `<cwd>/.pi/remote-pi/config.json` on disk.
41
+ */
13
42
  export declare function localConfigExists(cwd: string): boolean;
14
43
  export declare function loadLocalConfig(cwd: string): LocalConfig;
15
44
  export declare function saveLocalConfig(cwd: string, patch: Partial<LocalConfig>): void;
16
45
  /**
17
- * Default agent name when none is configured: `<parent>/<folder>` of the
18
- * given cwd. Falls back gracefully when the parent isn't meaningful
19
- * (root, current dir, single-segment paths) in those cases just the
20
- * folder name. Purpose: surface a non-empty string the user can accept
21
- * by pressing enter in the wizard.
46
+ * Default agent name when none is configured (plan/38 decision D): the **leaf**
47
+ * of the cwd, `basename(cwd)`. The cwd now travels as its own address axis
48
+ * (`<cwd>@<nome>`), so the name no longer needs the `parent/folder` prefix that
49
+ * used to disambiguate folders the broker keys peers by `(cwd, nome)`, and a
50
+ * clean leaf means `#N` almost never fires. Falls back to `"agent"` for a
51
+ * path with no usable basename (root / empty).
22
52
  */
23
53
  export declare function defaultAgentName(cwd: string): string;
24
54
  /** Resolves auto_start_relay with backward-compat (undefined → true). */
@@ -2,32 +2,112 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { basename, dirname, join } from "node:path";
3
3
  const LOCAL_DIR = ".pi/remote-pi";
4
4
  const LOCAL_FILE = "config.json";
5
+ /**
6
+ * Escape hatch: when set, carries the WHOLE local config as inline JSON,
7
+ * bypassing the on-disk `config.json`. For CI/ops/daemons that inject config
8
+ * via env instead of writing a file — mirrors `REMOTE_PI_RELAY` for the relay
9
+ * URL. Takes precedence over the file; an unset/empty/unparseable value falls
10
+ * back to the file (never fatal).
11
+ */
12
+ const DIRECT_CONFIG_ENV = "REMOTE_PI_DIRECT_CONFIG";
5
13
  function pathFor(cwd) {
6
14
  return join(cwd, LOCAL_DIR, LOCAL_FILE);
7
15
  }
8
- /** Returns true when `<cwd>/.pi/remote-pi/config.json` exists on disk. */
16
+ /**
17
+ * Normalize a name segment to a mesh-safe token: trim, replace the addressing
18
+ * separators (`/ : @ #`) and whitespace runs with `-`, collapse repeats, strip
19
+ * edges. The `@` is included so a sanitized name can never contain the address
20
+ * separator — `<cwd>@<name>` stays unambiguous on the wire. Returns undefined
21
+ * when the input isn't a usable non-empty string, sanitizes to empty, or is a
22
+ * reserved addressing keyword (`broadcast` / `broker`). Used by the broker's
23
+ * `sanitizeMeshName` to keep the `<nome>` half of a peer address safe to
24
+ * compose (plan/38).
25
+ */
26
+ export function sanitizeSegment(v) {
27
+ if (typeof v !== "string")
28
+ return undefined;
29
+ const token = v.trim().replace(/[/:@#\s]+/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
30
+ if (!token)
31
+ return undefined;
32
+ if (token.toLowerCase() === "broadcast" || token.toLowerCase() === "broker")
33
+ return undefined;
34
+ return token;
35
+ }
36
+ /**
37
+ * Migrate a persisted `agent_name` to the plan/38 leaf-name model (decision E).
38
+ * Two legacy shapes get rewritten on read so a pre-fix config never fossilizes a
39
+ * runtime accident as if it were an explicit choice:
40
+ *
41
+ * - **`#N` collision suffix** — could only have come from a broker/lock
42
+ * assignment (the user can't type `#`: `sanitizeSegment` maps it to `-`), so
43
+ * a trailing `#<digits>` is stripped and the clean base re-derived.
44
+ * - **legacy `parent/folder`** — the old `defaultAgentName` shape; the `/`
45
+ * means it predates the leaf-only model, so we keep only the leaf segment.
46
+ *
47
+ * Returns the cleaned name, or undefined when nothing usable remains (so the
48
+ * caller falls back to `defaultAgentName(cwd)`).
49
+ */
50
+ export function migrateAgentName(raw) {
51
+ // Legacy `parent/folder` (or any path-ish value) → keep the trailing segment.
52
+ const leaf = raw.includes("/") ? raw.slice(raw.lastIndexOf("/") + 1) : raw;
53
+ // Drop a runtime collision suffix a pre-fix build may have frozen into config.
54
+ const clean = leaf.replace(/#\d+$/, "").trim();
55
+ return clean.length > 0 ? clean : undefined;
56
+ }
57
+ /**
58
+ * Parse a raw JSON string into a LocalConfig, surfacing only known fields.
59
+ * Returns null when the input isn't a usable JSON object. Legacy `session_name`
60
+ * from pre-refactor configs is silently dropped — the local UDS mesh is now
61
+ * always a single fixed session, so the field has no meaning.
62
+ */
63
+ function parseLocalConfig(raw) {
64
+ let parsed;
65
+ try {
66
+ parsed = JSON.parse(raw);
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
72
+ return null;
73
+ const src = parsed;
74
+ const cfg = {};
75
+ if (typeof src["agent_name"] === "string") {
76
+ // Migrate on read (plan/38 decision E): strip a frozen `#N` and the legacy
77
+ // `parent/folder` shape so neither fossilizes as an explicit name.
78
+ const migrated = migrateAgentName(src["agent_name"]);
79
+ if (migrated)
80
+ cfg.agent_name = migrated;
81
+ }
82
+ if (typeof src["auto_start_relay"] === "boolean")
83
+ cfg.auto_start_relay = src["auto_start_relay"];
84
+ return cfg;
85
+ }
86
+ /** Inline config from `REMOTE_PI_DIRECT_CONFIG`, when set + parseable; else null. */
87
+ function directConfig() {
88
+ const raw = process.env[DIRECT_CONFIG_ENV];
89
+ if (!raw || raw.trim().length === 0)
90
+ return null;
91
+ return parseLocalConfig(raw);
92
+ }
93
+ /**
94
+ * True when a local config is available for this cwd — either inline via
95
+ * `REMOTE_PI_DIRECT_CONFIG` or as `<cwd>/.pi/remote-pi/config.json` on disk.
96
+ */
9
97
  export function localConfigExists(cwd) {
10
- return existsSync(pathFor(cwd));
98
+ return directConfig() !== null || existsSync(pathFor(cwd));
11
99
  }
12
100
  export function loadLocalConfig(cwd) {
101
+ // Precedence: inline `REMOTE_PI_DIRECT_CONFIG` env wins over the file. An
102
+ // unset/empty/malformed env falls through to the on-disk config.json.
103
+ const direct = directConfig();
104
+ if (direct)
105
+ return direct;
13
106
  const p = pathFor(cwd);
14
107
  if (!existsSync(p))
15
108
  return {};
16
109
  try {
17
- const raw = readFileSync(p, "utf8");
18
- const parsed = JSON.parse(raw);
19
- if (!parsed || typeof parsed !== "object")
20
- return {};
21
- // Only surface known fields. Legacy `session_name` from pre-refactor
22
- // configs is silently dropped — the local UDS mesh is now always a
23
- // single fixed session, so the field has no meaning.
24
- const src = parsed;
25
- const cfg = {};
26
- if (typeof src["agent_name"] === "string")
27
- cfg.agent_name = src["agent_name"];
28
- if (typeof src["auto_start_relay"] === "boolean")
29
- cfg.auto_start_relay = src["auto_start_relay"];
30
- return cfg;
110
+ return parseLocalConfig(readFileSync(p, "utf8")) ?? {};
31
111
  }
32
112
  catch {
33
113
  return {};
@@ -46,20 +126,15 @@ export function saveLocalConfig(cwd, patch) {
46
126
  writeFileSync(p, JSON.stringify(next, null, 2));
47
127
  }
48
128
  /**
49
- * Default agent name when none is configured: `<parent>/<folder>` of the
50
- * given cwd. Falls back gracefully when the parent isn't meaningful
51
- * (root, current dir, single-segment paths) in those cases just the
52
- * folder name. Purpose: surface a non-empty string the user can accept
53
- * by pressing enter in the wizard.
129
+ * Default agent name when none is configured (plan/38 decision D): the **leaf**
130
+ * of the cwd, `basename(cwd)`. The cwd now travels as its own address axis
131
+ * (`<cwd>@<nome>`), so the name no longer needs the `parent/folder` prefix that
132
+ * used to disambiguate folders the broker keys peers by `(cwd, nome)`, and a
133
+ * clean leaf means `#N` almost never fires. Falls back to `"agent"` for a
134
+ * path with no usable basename (root / empty).
54
135
  */
55
136
  export function defaultAgentName(cwd) {
56
- const folder = basename(cwd);
57
- const parent = basename(dirname(cwd));
58
- if (!folder)
59
- return "agent";
60
- if (!parent || parent === "/" || parent === folder || parent === ".")
61
- return folder;
62
- return `${parent}/${folder}`;
137
+ return basename(cwd) || "agent";
63
138
  }
64
139
  /** Resolves auto_start_relay with backward-compat (undefined → true). */
65
140
  export function effectiveAutoStartRelay(cfg) {
@@ -1 +1 @@
1
- {"version":3,"file":"local_config.js","sourceRoot":"","sources":["../../src/session/local_config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"local_config.js","sourceRoot":"","sources":["../../src/session/local_config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Plan/35: split a mesh envelope body into a human-readable sender label and
3
+ * the message text.
4
+ *
5
+ * Since the address (`from`) became a path/route — great for replies,
6
+ * unreadable as a label — a sender MAY shape the body as `{ name, text }`:
7
+ * `name` is a display-only nickname, `text` is the content. `from` stays the
8
+ * reply-to route untouched, so the 5-field envelope schema is unchanged — this
9
+ * is purely a body convention, not a new field.
10
+ *
11
+ * Fallbacks keep every legacy/cross-path message working:
12
+ * - a string body → the text verbatim, label = `fallbackName` (the route);
13
+ * - any other shape → JSON-stringified, label = `fallbackName`;
14
+ * - `{ name }` only → label = name, text = the JSON of the body;
15
+ * - `{ text }` only → label = `fallbackName`, text = text.
16
+ */
17
+ export declare function meshMessageDisplay(body: unknown, fallbackName: string): {
18
+ name: string;
19
+ text: string;
20
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Plan/35: split a mesh envelope body into a human-readable sender label and
3
+ * the message text.
4
+ *
5
+ * Since the address (`from`) became a path/route — great for replies,
6
+ * unreadable as a label — a sender MAY shape the body as `{ name, text }`:
7
+ * `name` is a display-only nickname, `text` is the content. `from` stays the
8
+ * reply-to route untouched, so the 5-field envelope schema is unchanged — this
9
+ * is purely a body convention, not a new field.
10
+ *
11
+ * Fallbacks keep every legacy/cross-path message working:
12
+ * - a string body → the text verbatim, label = `fallbackName` (the route);
13
+ * - any other shape → JSON-stringified, label = `fallbackName`;
14
+ * - `{ name }` only → label = name, text = the JSON of the body;
15
+ * - `{ text }` only → label = `fallbackName`, text = text.
16
+ */
17
+ export function meshMessageDisplay(body, fallbackName) {
18
+ if (body && typeof body === "object" && !Array.isArray(body)) {
19
+ const o = body;
20
+ const name = typeof o["name"] === "string" ? o["name"] : undefined;
21
+ const text = typeof o["text"] === "string" ? o["text"] : undefined;
22
+ if (name !== undefined || text !== undefined) {
23
+ return { name: name ?? fallbackName, text: text ?? JSON.stringify(body) };
24
+ }
25
+ }
26
+ return { name: fallbackName, text: typeof body === "string" ? body : JSON.stringify(body) };
27
+ }
28
+ //# sourceMappingURL=mesh_message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mesh_message.js","sourceRoot":"","sources":["../../src/session/mesh_message.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAa,EACb,YAAoB;IAEpB,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,MAAM,CAAY,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAE,CAAC,CAAC,MAAM,CAAY,CAAC,CAAC,CAAC,SAAS,CAAC;QAC/E,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,IAAI,YAAY,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;AAC9F,CAAC"}
@@ -43,6 +43,10 @@ export interface MeshNodeOptions {
43
43
  sockPath: string;
44
44
  /** Requested mesh name (broker may add a #N collision suffix). */
45
45
  name: string;
46
+ /** Working directory, forwarded to the broker in `register` so peers are
47
+ * keyed by (cwd, name) and a same-folder same-name reincarnation takes over
48
+ * instead of colliding into `#N`. Optional (legacy peers omit it). */
49
+ cwd?: string;
46
50
  /** Optional audit log path passed through to SessionPeer. */
47
51
  auditPath?: string;
48
52
  /** Self-managed relay bridge — brought up if this node leads. */
@@ -118,8 +122,18 @@ export declare class MeshNode {
118
122
  onMessage(handler: (env: Envelope) => void): () => void;
119
123
  /** Subscribe to post-failover reconnects. Returns an unsubscribe fn. */
120
124
  onReconnect(handler: () => void): () => void;
121
- /** Assigned mesh name (after any #N collision suffix). */
125
+ /** Assigned clean mesh name (after any #N collision suffix). */
122
126
  name(): string;
127
+ /** Canonical mesh address (`[<pc>:]<cwd>@<nome>`) — echo, never compose. */
128
+ address(): string;
129
+ /**
130
+ * Rename this peer on the broker via a soft leave+rejoin (re-registers under
131
+ * `newName`; the broker may append a `#N` on collision — returns the assigned
132
+ * name). Keeps the process + onMessage handlers alive. Does NOT touch the
133
+ * cross-PC bridge or the relay room — the caller must cycle the relay so the
134
+ * App↔Pi room (keyed by `(cwd, name)`, plan/41) follows the new name.
135
+ */
136
+ rename(newName: string): Promise<string>;
123
137
  /** "leader" | "follower". */
124
138
  currentRole(): "leader" | "follower";
125
139
  /** The locally-hosted Broker when leader, else null. */
@@ -2,7 +2,7 @@ import { SessionPeer } from "./peer.js";
2
2
  import { RelayClient } from "../transport/relay_client.js";
3
3
  import { attachCrossPcBridge } from "./bridge.js";
4
4
  import { getOrCreateEd25519Keypair } from "../pairing/storage.js";
5
- import { roomIdForCwd } from "../rooms.js";
5
+ import { roomIdFor } from "../rooms.js";
6
6
  import { toWebSocketUrl } from "../config.js";
7
7
  export class MeshNode {
8
8
  peer_;
@@ -22,6 +22,8 @@ export class MeshNode {
22
22
  constructor(opts) {
23
23
  this.log = opts.log ?? (() => { });
24
24
  const peerOpts = { sockPath: opts.sockPath, name: opts.name };
25
+ if (opts.cwd !== undefined)
26
+ peerOpts.cwd = opts.cwd;
25
27
  if (opts.auditPath !== undefined)
26
28
  peerOpts.auditPath = opts.auditPath;
27
29
  this.peer_ = new SessionPeer(peerOpts);
@@ -105,8 +107,12 @@ export class MeshNode {
105
107
  else {
106
108
  if (!this.keypair)
107
109
  this.keypair = params.keypair ?? (await getOrCreateEd25519Keypair());
108
- const roomId = roomIdForCwd(params.cwd);
109
- const roomMeta = { name: params.sessionName ?? this.peer_.name(), cwd: params.cwd };
110
+ // plan/41: room is keyed by (cwd, name) so two agents in the same folder
111
+ // get distinct App↔Pi rooms. Use the SAME name as room_meta.name so the
112
+ // derivation and the announced label agree.
113
+ const roomName = params.sessionName ?? this.peer_.name();
114
+ const roomId = roomIdFor(params.cwd, roomName);
115
+ const roomMeta = { name: roomName, cwd: params.cwd };
110
116
  const r = new RelayClient(toWebSocketUrl(params.relayUrl), this.keypair);
111
117
  try {
112
118
  await r.connect({ roomId, roomMeta });
@@ -252,10 +258,24 @@ export class MeshNode {
252
258
  onReconnect(handler) {
253
259
  return this.peer_.onReconnect(handler);
254
260
  }
255
- /** Assigned mesh name (after any #N collision suffix). */
261
+ /** Assigned clean mesh name (after any #N collision suffix). */
256
262
  name() {
257
263
  return this.peer_.name();
258
264
  }
265
+ /** Canonical mesh address (`[<pc>:]<cwd>@<nome>`) — echo, never compose. */
266
+ address() {
267
+ return this.peer_.address();
268
+ }
269
+ /**
270
+ * Rename this peer on the broker via a soft leave+rejoin (re-registers under
271
+ * `newName`; the broker may append a `#N` on collision — returns the assigned
272
+ * name). Keeps the process + onMessage handlers alive. Does NOT touch the
273
+ * cross-PC bridge or the relay room — the caller must cycle the relay so the
274
+ * App↔Pi room (keyed by `(cwd, name)`, plan/41) follows the new name.
275
+ */
276
+ async rename(newName) {
277
+ return this.peer_.rename(newName);
278
+ }
259
279
  /** "leader" | "follower". */
260
280
  currentRole() {
261
281
  return this.peer_.currentRole();
@@ -271,7 +291,8 @@ export class MeshNode {
271
291
  async listPeers(timeoutMs = 2_000) {
272
292
  const reply = await this.peer_.request("broker", { type: "list_peers" }, timeoutMs);
273
293
  const body = reply.body;
274
- return (body?.peers ?? []).filter((p) => p !== this.peer_.name());
294
+ // Peers are ADDRESSES now — filter self by address, not the clean name.
295
+ return (body?.peers ?? []).filter((p) => p !== this.peer_.address());
275
296
  }
276
297
  /** Tear down the bridge (if any) and leave the mesh. */
277
298
  async close() {
@@ -1 +1 @@
1
- {"version":3,"file":"mesh_node.js","sourceRoot":"","sources":["../../src/session/mesh_node.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mesh_node.js","sourceRoot":"","sources":["../../src/session/mesh_node.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,14 @@ export type ReconnectHandler = () => void;
14
14
  export interface SessionPeerOptions {
15
15
  sockPath: string;
16
16
  name: string;
17
+ /**
18
+ * Working directory of this agent. Sent in the `register` so the broker can
19
+ * key peers by the (cwd, name) pair: two agents in the SAME folder with the
20
+ * same name are the SAME logical agent reincarnating (switch_session /
21
+ * restart), so the broker take-over the name instead of suffixing `#N`.
22
+ * Optional for backward-compat with peers that predate this field.
23
+ */
24
+ cwd?: string;
17
25
  auditPath?: string;
18
26
  /** Per-request default timeout (ms). Override per call if needed. */
19
27
  defaultTimeoutMs?: number;
@@ -28,8 +36,13 @@ export interface AckResult {
28
36
  }
29
37
  export declare class SessionPeer {
30
38
  private readonly opts;
31
- /** Name actually assigned by the broker (may differ via #N collision suffix). */
39
+ /** Clean leaf name actually assigned by the broker (may carry a `#N`
40
+ * collision suffix). Used for display + self-filtering. */
32
41
  private assignedName;
42
+ /** Canonical address assigned by the broker (`[<pc>:]<cwd>@<nome>`, or just
43
+ * the name for a legacy broker). This is the routing/identity key the mesh
44
+ * uses; callers ECHO it, never compose it. */
45
+ private assignedAddress;
33
46
  private role;
34
47
  private broker;
35
48
  private socket;
@@ -44,8 +57,12 @@ export declare class SessionPeer {
44
57
  constructor(opts: SessionPeerOptions);
45
58
  /** Joins or leads the session at `sockPath`. Resolves with the assigned name. */
46
59
  start(): Promise<string>;
47
- /** Returns the name as assigned by the broker (after collision suffix). */
60
+ /** Returns the clean leaf name as assigned by the broker (after any `#N`). */
48
61
  name(): string;
62
+ /** Returns the canonical address (`[<pc>:]<cwd>@<nome>`) assigned by the
63
+ * broker — the key the mesh routes on. Equals `name()` against a legacy
64
+ * broker that returns no address. */
65
+ address(): string;
49
66
  /** Returns "leader" or "follower" — current role. */
50
67
  currentRole(): "leader" | "follower";
51
68
  /** Returns the locally-hosted Broker when this peer is the leader, or
@@ -7,8 +7,13 @@ const ACK_TIMEOUT_MS = 5_000;
7
7
  const FAILOVER_RETRY_MS = 100;
8
8
  export class SessionPeer {
9
9
  opts;
10
- /** Name actually assigned by the broker (may differ via #N collision suffix). */
10
+ /** Clean leaf name actually assigned by the broker (may carry a `#N`
11
+ * collision suffix). Used for display + self-filtering. */
11
12
  assignedName;
13
+ /** Canonical address assigned by the broker (`[<pc>:]<cwd>@<nome>`, or just
14
+ * the name for a legacy broker). This is the routing/identity key the mesh
15
+ * uses; callers ECHO it, never compose it. */
16
+ assignedAddress;
12
17
  role = "follower";
13
18
  broker = null;
14
19
  socket = null;
@@ -23,16 +28,23 @@ export class SessionPeer {
23
28
  constructor(opts) {
24
29
  this.opts = opts;
25
30
  this.assignedName = opts.name;
31
+ this.assignedAddress = opts.name;
26
32
  }
27
33
  // ── public API ────────────────────────────────────────────────────────────
28
34
  /** Joins or leads the session at `sockPath`. Resolves with the assigned name. */
29
35
  async start() {
30
36
  return this._joinOrLead();
31
37
  }
32
- /** Returns the name as assigned by the broker (after collision suffix). */
38
+ /** Returns the clean leaf name as assigned by the broker (after any `#N`). */
33
39
  name() {
34
40
  return this.assignedName;
35
41
  }
42
+ /** Returns the canonical address (`[<pc>:]<cwd>@<nome>`) assigned by the
43
+ * broker — the key the mesh routes on. Equals `name()` against a legacy
44
+ * broker that returns no address. */
45
+ address() {
46
+ return this.assignedAddress;
47
+ }
36
48
  /** Returns "leader" or "follower" — current role. */
37
49
  currentRole() {
38
50
  return this.role;
@@ -172,7 +184,7 @@ export class SessionPeer {
172
184
  this.buf = "";
173
185
  sock.setEncoding("utf8");
174
186
  sock.on("data", (chunk) => this._onData(chunk));
175
- sock.on("close", () => this._onSocketClose());
187
+ sock.on("close", () => this._onSocketClose(sock));
176
188
  sock.on("error", () => { });
177
189
  }
178
190
  _registerOver(sock) {
@@ -181,18 +193,32 @@ export class SessionPeer {
181
193
  const wait = setTimeout(() => reject(new Error("register_ack timeout")), 5_000);
182
194
  const onceListener = (raw) => {
183
195
  clearTimeout(wait);
196
+ // plan/38: a new broker returns `address_assigned` (canonical key) +
197
+ // `name_assigned` (clean leaf). Read both with cross-fallback so we work
198
+ // against either a new broker OR a legacy one (only `name_assigned`,
199
+ // where address == name).
184
200
  const ack = raw;
185
- if (ack && ack.type === "register_ack" && typeof ack.name_assigned === "string") {
186
- this.assignedName = ack.name_assigned;
201
+ const name = typeof ack?.name_assigned === "string" ? ack.name_assigned : ack?.address_assigned;
202
+ const address = typeof ack?.address_assigned === "string" ? ack.address_assigned : ack?.name_assigned;
203
+ if (ack && ack.type === "register_ack" && typeof name === "string" && typeof address === "string") {
204
+ this.assignedName = name;
205
+ this.assignedAddress = address;
187
206
  this._preAckListener = null;
188
- resolve(ack.name_assigned);
207
+ resolve(name);
189
208
  }
190
209
  else {
191
210
  reject(new Error(`expected register_ack, got: ${JSON.stringify(raw)}`));
192
211
  }
193
212
  };
194
213
  this._preAckListener = onceListener;
195
- const req = JSON.stringify({ type: "register", name: this.opts.name }) + "\n";
214
+ const req = JSON.stringify({
215
+ type: "register",
216
+ name: this.opts.name,
217
+ // Only include cwd when set — keeps the wire identical to the legacy
218
+ // payload for callers that don't supply it (broker treats absent cwd
219
+ // as "no take-over", i.e. the old #N behavior).
220
+ ...(this.opts.cwd !== undefined ? { cwd: this.opts.cwd } : {}),
221
+ }) + "\n";
196
222
  try {
197
223
  sock.write(req);
198
224
  }
@@ -284,13 +310,23 @@ export class SessionPeer {
284
310
  }
285
311
  this.socket.write(serialize(env));
286
312
  }
287
- async _onSocketClose() {
313
+ async _onSocketClose(closedSock) {
288
314
  if (this.leftFlag)
289
315
  return; // intentional leave
316
+ // Only the CURRENT socket dying is a real failover. A close from a socket
317
+ // we've already replaced — `rename()` (teardown + rejoin) or a prior
318
+ // reconnect — must NOT trigger another `_joinOrLead`, or we'd double-
319
+ // register (the broker suffixes the second as `#N`) and leave an orphaned
320
+ // still-open socket as a ghost peer. `this.socket` is null mid-rename
321
+ // (teardown done, rejoin in flight) or already the new socket — either way
322
+ // `!== closedSock`, so we skip. Genuine leader death: `this.socket` is still
323
+ // the (now-closed) follower socket → identity matches → we re-elect.
324
+ if (this.socket !== closedSock)
325
+ return;
290
326
  // Attempt to re-elect once. New leader will bind sockPath; we either
291
327
  // become leader ourselves or rejoin as follower.
292
328
  await delay(FAILOVER_RETRY_MS);
293
- if (this.leftFlag)
329
+ if (this.leftFlag || this.socket !== closedSock)
294
330
  return;
295
331
  try {
296
332
  await this._joinOrLead();