remote-pi 0.1.2 → 0.2.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 (99) hide show
  1. package/README.md +195 -36
  2. package/dist/bin/supervisord.d.ts +2 -0
  3. package/dist/bin/supervisord.js +44 -0
  4. package/dist/bin/supervisord.js.map +1 -0
  5. package/dist/config.d.ts +49 -5
  6. package/dist/config.js +73 -9
  7. package/dist/config.js.map +1 -1
  8. package/dist/daemon/client.d.ts +20 -0
  9. package/dist/daemon/client.js +128 -0
  10. package/dist/daemon/client.js.map +1 -0
  11. package/dist/daemon/control_protocol.d.ts +100 -0
  12. package/dist/daemon/control_protocol.js +63 -0
  13. package/dist/daemon/control_protocol.js.map +1 -0
  14. package/dist/daemon/id.d.ts +18 -0
  15. package/dist/daemon/id.js +30 -0
  16. package/dist/daemon/id.js.map +1 -0
  17. package/dist/daemon/install.d.ts +132 -0
  18. package/dist/daemon/install.js +312 -0
  19. package/dist/daemon/install.js.map +1 -0
  20. package/dist/daemon/registry.d.ts +47 -0
  21. package/dist/daemon/registry.js +123 -0
  22. package/dist/daemon/registry.js.map +1 -0
  23. package/dist/daemon/rpc_child.d.ts +76 -0
  24. package/dist/daemon/rpc_child.js +130 -0
  25. package/dist/daemon/rpc_child.js.map +1 -0
  26. package/dist/daemon/supervisor.d.ts +38 -0
  27. package/dist/daemon/supervisor.js +301 -0
  28. package/dist/daemon/supervisor.js.map +1 -0
  29. package/dist/index.d.ts +62 -8
  30. package/dist/index.js +1232 -304
  31. package/dist/index.js.map +1 -1
  32. package/dist/mesh/canonical.d.ts +30 -0
  33. package/dist/mesh/canonical.js +61 -0
  34. package/dist/mesh/canonical.js.map +1 -0
  35. package/dist/mesh/client.d.ts +31 -0
  36. package/dist/mesh/client.js +56 -0
  37. package/dist/mesh/client.js.map +1 -0
  38. package/dist/mesh/encoding.d.ts +36 -0
  39. package/dist/mesh/encoding.js +53 -0
  40. package/dist/mesh/encoding.js.map +1 -0
  41. package/dist/mesh/self_revoke.d.ts +111 -0
  42. package/dist/mesh/self_revoke.js +182 -0
  43. package/dist/mesh/self_revoke.js.map +1 -0
  44. package/dist/mesh/siblings.d.ts +62 -0
  45. package/dist/mesh/siblings.js +95 -0
  46. package/dist/mesh/siblings.js.map +1 -0
  47. package/dist/mesh/types.d.ts +34 -0
  48. package/dist/mesh/types.js +11 -0
  49. package/dist/mesh/types.js.map +1 -0
  50. package/dist/mesh/verify.d.ts +17 -0
  51. package/dist/mesh/verify.js +77 -0
  52. package/dist/mesh/verify.js.map +1 -0
  53. package/dist/pairing/qr.d.ts +16 -5
  54. package/dist/pairing/qr.js +27 -8
  55. package/dist/pairing/qr.js.map +1 -1
  56. package/dist/pairing/storage.d.ts +41 -0
  57. package/dist/pairing/storage.js +158 -21
  58. package/dist/pairing/storage.js.map +1 -1
  59. package/dist/protocol/types.d.ts +23 -0
  60. package/dist/session/broker.d.ts +74 -0
  61. package/dist/session/broker.js +142 -4
  62. package/dist/session/broker.js.map +1 -1
  63. package/dist/session/broker_remote.d.ts +110 -0
  64. package/dist/session/broker_remote.js +397 -0
  65. package/dist/session/broker_remote.js.map +1 -0
  66. package/dist/session/cwd_lock.d.ts +28 -0
  67. package/dist/session/cwd_lock.js +89 -0
  68. package/dist/session/cwd_lock.js.map +1 -0
  69. package/dist/session/global_config.d.ts +9 -0
  70. package/dist/session/global_config.js +9 -0
  71. package/dist/session/global_config.js.map +1 -1
  72. package/dist/session/leader_election.d.ts +16 -0
  73. package/dist/session/leader_election.js +22 -0
  74. package/dist/session/leader_election.js.map +1 -1
  75. package/dist/session/local_config.d.ts +12 -5
  76. package/dist/session/local_config.js +24 -3
  77. package/dist/session/local_config.js.map +1 -1
  78. package/dist/session/peer.d.ts +28 -1
  79. package/dist/session/peer.js +69 -2
  80. package/dist/session/peer.js.map +1 -1
  81. package/dist/session/peer_inventory.d.ts +13 -0
  82. package/dist/session/peer_inventory.js +48 -0
  83. package/dist/session/peer_inventory.js.map +1 -0
  84. package/dist/session/setup_wizard.d.ts +32 -8
  85. package/dist/session/setup_wizard.js +45 -33
  86. package/dist/session/setup_wizard.js.map +1 -1
  87. package/dist/session/tools.d.ts +15 -7
  88. package/dist/session/tools.js +145 -31
  89. package/dist/session/tools.js.map +1 -1
  90. package/dist/transport/pi_forward_client.d.ts +29 -0
  91. package/dist/transport/pi_forward_client.js +62 -0
  92. package/dist/transport/pi_forward_client.js.map +1 -0
  93. package/dist/ui/footer.js +8 -6
  94. package/dist/ui/footer.js.map +1 -1
  95. package/docs/daemon.md +289 -0
  96. package/package.json +10 -3
  97. package/service-templates/launchd.plist.template +35 -0
  98. package/service-templates/systemd.service.template +19 -0
  99. package/skills/agent-network/SKILL.md +273 -294
@@ -1,27 +1,39 @@
1
1
  import { Type } from "typebox";
2
2
  const NOT_IN_SESSION = "Not in a session. Run /remote-pi join first";
3
- const DEFAULT_TIMEOUT_MS = 30_000;
3
+ const ACK_TIMEOUT_MS = 5_000;
4
+ const LEGACY_REQUEST_TIMEOUT_MS = 30_000;
5
+ const LIST_PEERS_TIMEOUT_MS = 2_000;
4
6
  /**
5
- * Registers two native tools the Pi LLM can invoke to talk to other agents
6
- * in the same UDS session (plano 19 transport):
7
- * - `agent_send` — fire-and-forget delivery
8
- * - `agent_request` — request/reply with `re` correlation + timeout
7
+ * Registers the native tools the Pi LLM uses to talk to other agents in the
8
+ * same UDS session (plano 19 transport + plan/25 Wave 0 ACK protocol):
9
9
  *
10
- * Both tools are registered unconditionally. When this Pi is not currently
11
- * joined to a session, the tool returns a structured error string instead
12
- * of throwing, so the LLM can react and tell the user.
10
+ * - `agent_send` — unified delivery with broker-level ACK. Returns
11
+ * a status so the LLM can decide whether to retry.
12
+ * For unicast targets the broker auto-replies with
13
+ * `received | busy | denied`. For broadcast/multicast
14
+ * the tool is fire-and-forget (status `sent`).
15
+ * - `agent_request` — **deprecated**. Still works (send + block on reply
16
+ * via `re` correlation) but the LLM should migrate
17
+ * to the event-driven send+inbox pattern. Each call
18
+ * emits a one-shot warning to stderr.
19
+ *
20
+ * Reply pattern (new world): when you receive a message you want to answer,
21
+ * send back another envelope with `re=<original-id>`. The original sender
22
+ * sees that reply in its inbox during a future turn.
13
23
  *
14
24
  * `getSessionPeer` is a getter (not a captured value) so changes to the
15
25
  * underlying `_sessionPeer` module variable are observed live.
16
26
  */
17
27
  export function registerAgentTools(pi, getSessionPeer) {
18
28
  const SendParams = Type.Object({
19
- to: Type.String({ description: "Recipient agent name (e.g. 'backend'), 'broadcast', or array of names." }),
29
+ to: Type.String({
30
+ description: "Recipient agent name (e.g. 'backend'), 'broadcast', or array of names. " +
31
+ "Broadcast/multicast are fire-and-forget; unicast returns an ACK status.",
32
+ }),
20
33
  body: Type.Unknown({ description: "Free-form JSON payload. String or object — your choice." }),
21
34
  re: Type.Optional(Type.String({
22
- description: "When you are REPLYING to a message from another agent, set this to that " +
23
- "message's `id`. Required for `agent_request` correlation on the other side " +
24
- "without it, the sender's pending request times out. Skip for unsolicited sends.",
35
+ description: "Set this to the `id` of an incoming message when you are REPLYING to it. " +
36
+ "The peer correlates your answer with their original send via this field.",
25
37
  })),
26
38
  });
27
39
  const RequestParams = Type.Object({
@@ -34,54 +46,141 @@ export function registerAgentTools(pi, getSessionPeer) {
34
46
  pi.registerTool({
35
47
  name: "agent_send",
36
48
  label: "Agent Send",
37
- description: "Send a message to another Pi agent in the current local session. " +
38
- "Two uses: (1) fire-and-forget announcements, status updates, or anything " +
39
- "that doesn't need a reply call without `re`. (2) REPLYING to a question " +
40
- "another agent sent you via `agent_request` call with `re` set to the " +
41
- "incoming message's `id`. Without `re`, the requester times out.",
42
- promptSnippet: "agent_send({to, body, re?}): send/reply to peers. Set `re` to incoming message id when answering an agent_request.",
49
+ description: "Send a message to another Pi agent in the current local session and " +
50
+ "wait for the broker's delivery ACK. Returns one of: `received` (peer " +
51
+ "was idle, will process in its next turn), `busy` (peer mid-turn, " +
52
+ "message dropped you own the retry), `denied` (peer refused), " +
53
+ "`timeout` (no ACK in 5s treat as transport error), `sent` " +
54
+ "(broadcast/multicast no ACK semantics). Use `re` to mark this " +
55
+ "message as a reply to an incoming envelope's `id`.",
56
+ promptSnippet: "agent_send({to, body, re?}): unicast → returns {status: received|busy|denied|timeout}. Broadcast/multicast → fire-and-forget ({status:'sent'}).",
43
57
  parameters: SendParams,
44
58
  execute: async (_toolCallId, params) => {
45
59
  const peer = getSessionPeer();
46
60
  if (!peer) {
61
+ const details = { status: "refused", ok: false, error: NOT_IN_SESSION };
47
62
  return {
48
63
  content: [{ type: "text", text: NOT_IN_SESSION }],
49
- details: { ok: false, error: NOT_IN_SESSION },
64
+ details,
50
65
  };
51
66
  }
52
67
  const { to, body, re } = params;
53
68
  if (to === peer.name()) {
54
69
  const msg = `Refused: cannot agent_send to yourself ("${to}"). Just do the work directly.`;
70
+ const details = { status: "refused", ok: false, error: msg };
55
71
  return {
56
72
  content: [{ type: "text", text: msg }],
57
- details: { ok: false, error: msg },
73
+ details,
58
74
  };
59
75
  }
76
+ const isUnicast = to !== "broadcast";
77
+ // Broadcast: fire-and-forget. Broker doesn't ACK multi-target sends.
78
+ if (!isUnicast) {
79
+ try {
80
+ await peer.send(to, body, re ?? null);
81
+ const details = { status: "sent", ok: true };
82
+ return {
83
+ content: [{ type: "text", text: `Broadcast sent.` }],
84
+ details,
85
+ };
86
+ }
87
+ catch (err) {
88
+ const msg = err instanceof Error ? err.message : String(err);
89
+ const details = { status: "timeout", ok: false, error: msg };
90
+ return {
91
+ content: [{ type: "text", text: `Broadcast failed: ${msg}` }],
92
+ details,
93
+ };
94
+ }
95
+ }
96
+ // Unicast: wait for broker ACK.
60
97
  try {
61
- await peer.send(to, body, re ?? null);
62
- return {
63
- content: [{ type: "text", text: `Sent to ${to}${re ? ` (re=${re})` : ""}.` }],
64
- details: { ok: true },
98
+ const ack = await peer.sendWithAck(to, body, re ?? null, ACK_TIMEOUT_MS);
99
+ const ok = ack.status === "received";
100
+ const details = {
101
+ status: ack.status,
102
+ ok,
103
+ target: ack.target,
65
104
  };
105
+ const text = _formatAck(to, ack.status, re);
106
+ return { content: [{ type: "text", text }], details };
66
107
  }
67
108
  catch (err) {
68
109
  const msg = err instanceof Error ? err.message : String(err);
110
+ const details = { status: "timeout", ok: false, error: msg };
69
111
  return {
70
112
  content: [{ type: "text", text: `Failed to send: ${msg}` }],
71
- details: { ok: false, error: msg },
113
+ details,
114
+ };
115
+ }
116
+ },
117
+ });
118
+ const ListPeersParams = Type.Object({});
119
+ pi.registerTool({
120
+ name: "list_peers",
121
+ label: "List Peers",
122
+ description: "Returns the current peer inventory in this session — local names " +
123
+ "(no prefix) plus cross-PC peers prefixed `<pc_label>:<peer>`. Use " +
124
+ "BEFORE `agent_send` whenever you're unsure who's available, or " +
125
+ "after a `peer_joined` / `peer_left` notification to refresh your " +
126
+ "mental model. Resolves in milliseconds — this is a metadata query " +
127
+ "to the broker, not a turn of another agent.",
128
+ promptSnippet: "list_peers(): returns {peers: string[]} — locals + `<pc>:<peer>` remotes. Cheap; call freely before agent_send.",
129
+ parameters: ListPeersParams,
130
+ execute: async (_toolCallId) => {
131
+ const peer = getSessionPeer();
132
+ if (!peer) {
133
+ return {
134
+ content: [{ type: "text", text: NOT_IN_SESSION }],
135
+ details: { peers: [] },
136
+ };
137
+ }
138
+ try {
139
+ // Internal use of the request/reply primitive is fine — broker
140
+ // replies are synthesised in-process (`_handleBrokerMessage`)
141
+ // without going through `_route`, so they bypass the ACK and
142
+ // busy-gate machinery entirely.
143
+ const reply = await peer.request("broker", { type: "list_peers" }, LIST_PEERS_TIMEOUT_MS);
144
+ const body = reply.body;
145
+ const peers = Array.isArray(body?.peers)
146
+ ? body.peers.filter((p) => typeof p === "string")
147
+ : [];
148
+ // Drop self from the list — the caller is the only one who can't
149
+ // address itself anyway, so listing it is noise.
150
+ const selfName = peer.name();
151
+ const filtered = peers.filter((p) => p !== selfName);
152
+ const text = filtered.length === 0 ? "(no peers)" : filtered.join("\n");
153
+ return {
154
+ content: [{ type: "text", text }],
155
+ details: { peers: filtered },
156
+ };
157
+ }
158
+ catch (err) {
159
+ const msg = err instanceof Error ? err.message : String(err);
160
+ return {
161
+ content: [{ type: "text", text: `list_peers failed: ${msg}` }],
162
+ details: { peers: [] },
72
163
  };
73
164
  }
74
165
  },
75
166
  });
167
+ let _requestDeprecationWarned = false;
76
168
  pi.registerTool({
77
169
  name: "agent_request",
78
- label: "Agent Request",
79
- description: "Send a message to another Pi agent and wait for the reply. Resolves to the responder's " +
80
- "body field. Use when you need an answer from a peer before continuing your turn. " +
81
- "Default timeout 30s; override with `timeout_ms`.",
82
- promptSnippet: "agent_request({to, body, timeout_ms?}): synchronous request/reply with a peer (returns peer's body or {error}).",
170
+ label: "Agent Request (deprecated)",
171
+ description: "DEPRECATED prefer `agent_send` + observing your inbox for the " +
172
+ "reply (correlated by `re=<your-send-id>`). This tool still works: " +
173
+ "it sends a message and synchronously blocks until the peer replies " +
174
+ "or the timeout fires. Default 30s. Will be removed in a future " +
175
+ "release; migrate to the event-driven pattern in the agent-network skill.",
176
+ promptSnippet: "agent_request({to, body, timeout_ms?}): DEPRECATED synchronous request/reply (blocks current turn). Prefer agent_send + inbox observation.",
83
177
  parameters: RequestParams,
84
178
  execute: async (_toolCallId, params) => {
179
+ if (!_requestDeprecationWarned) {
180
+ _requestDeprecationWarned = true;
181
+ console.error("[remote-pi] agent_request is deprecated — migrate to agent_send + " +
182
+ "observe inbox by `re`. See the agent-network skill for the new pattern.");
183
+ }
85
184
  const peer = getSessionPeer();
86
185
  if (!peer) {
87
186
  return {
@@ -99,7 +198,7 @@ export function registerAgentTools(pi, getSessionPeer) {
99
198
  }
100
199
  const timeout = typeof timeout_ms === "number" && timeout_ms > 0
101
200
  ? timeout_ms
102
- : DEFAULT_TIMEOUT_MS;
201
+ : LEGACY_REQUEST_TIMEOUT_MS;
103
202
  try {
104
203
  const reply = await peer.request(to, body, timeout);
105
204
  const text = typeof reply.body === "string"
@@ -120,4 +219,19 @@ export function registerAgentTools(pi, getSessionPeer) {
120
219
  },
121
220
  });
122
221
  }
222
+ function _formatAck(to, status, re) {
223
+ const reSuffix = re ? ` (re=${re})` : "";
224
+ switch (status) {
225
+ case "received":
226
+ return `Delivered to "${to}"${reSuffix} — peer was idle and will process in its next turn.`;
227
+ case "busy":
228
+ return `"${to}" is busy${reSuffix} — message dropped. Retry with backoff or abandon (see agent-network skill).`;
229
+ case "denied":
230
+ return `"${to}" denied the message${reSuffix}. Do not retry; report to user.`;
231
+ case "timeout":
232
+ return `No ACK from "${to}" within ${ACK_TIMEOUT_MS}ms${reSuffix} — transport error. Investigate or retry later.`;
233
+ default:
234
+ return `Sent to "${to}"${reSuffix} — status: ${status}.`;
235
+ }
236
+ }
123
237
  //# sourceMappingURL=tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/session/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/session/tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { RelayClient } from "./relay_client.js";
3
+ import type { Envelope } from "../session/envelope.js";
4
+ /** Outbound API + inbound listener for Pi↔Pi envelope forwarding via relay. */
5
+ export interface PiForwardClientEvents {
6
+ /**
7
+ * Emitted whenever the relay delivers a `pi_envelope_in` frame addressed
8
+ * to this Pi. `fromPc` is the verified Pi-pubkey of the sender (relay
9
+ * authoritative — defense against spoofed `envelope.from`).
10
+ */
11
+ envelope: [env: Envelope, fromPc: string];
12
+ }
13
+ export declare class PiForwardClient extends EventEmitter {
14
+ private readonly relay;
15
+ private readonly onRelayMessage;
16
+ private detached;
17
+ constructor(relay: RelayClient);
18
+ /**
19
+ * Pack `env` in a `pi_envelope` frame addressed to `toPc` and send via
20
+ * the relay WS. Best-effort: if the relay is not connected, the call is
21
+ * silently dropped. The caller (broker_remote) handles the timeout via
22
+ * its outstanding-ACK map — a missing ACK from the destination wrapper
23
+ * surfaces as `status: "timeout"` upstream regardless.
24
+ */
25
+ sendEnvelopeToPi(toPc: string, env: Envelope): void;
26
+ /** Stop listening to the relay. Call from `_goIdle` / shutdown. */
27
+ detach(): void;
28
+ private _handleLine;
29
+ }
@@ -0,0 +1,62 @@
1
+ import { EventEmitter } from "node:events";
2
+ export class PiForwardClient extends EventEmitter {
3
+ relay;
4
+ onRelayMessage;
5
+ detached = false;
6
+ constructor(relay) {
7
+ super();
8
+ this.relay = relay;
9
+ this.onRelayMessage = (line) => this._handleLine(line);
10
+ this.relay.on("message", this.onRelayMessage);
11
+ }
12
+ /**
13
+ * Pack `env` in a `pi_envelope` frame addressed to `toPc` and send via
14
+ * the relay WS. Best-effort: if the relay is not connected, the call is
15
+ * silently dropped. The caller (broker_remote) handles the timeout via
16
+ * its outstanding-ACK map — a missing ACK from the destination wrapper
17
+ * surfaces as `status: "timeout"` upstream regardless.
18
+ */
19
+ sendEnvelopeToPi(toPc, env) {
20
+ if (this.detached)
21
+ return;
22
+ const frame = { type: "pi_envelope", to_pc: toPc, envelope: env };
23
+ try {
24
+ this.relay.send(JSON.stringify(frame));
25
+ }
26
+ catch {
27
+ // relay not connected; broker_remote's pending logic will time out
28
+ }
29
+ }
30
+ /** Stop listening to the relay. Call from `_goIdle` / shutdown. */
31
+ detach() {
32
+ if (this.detached)
33
+ return;
34
+ this.detached = true;
35
+ this.relay.off("message", this.onRelayMessage);
36
+ }
37
+ _handleLine(line) {
38
+ // The relay multiplexes several frame types over the same WS; we only
39
+ // care about `pi_envelope_in`. Other frames (outer-encrypted owner
40
+ // envelopes, control replies) are silently ignored.
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(line);
44
+ }
45
+ catch {
46
+ return;
47
+ }
48
+ if (!parsed || typeof parsed !== "object")
49
+ return;
50
+ const o = parsed;
51
+ if (o.type !== "pi_envelope_in")
52
+ return;
53
+ if (typeof o.from_pc !== "string" || !o.envelope || typeof o.envelope !== "object")
54
+ return;
55
+ // Cheap shape check — full envelope parse happens downstream in broker_remote.
56
+ const env = o.envelope;
57
+ if (typeof env.from !== "string" || typeof env.id !== "string")
58
+ return;
59
+ this.emit("envelope", env, o.from_pc);
60
+ }
61
+ }
62
+ //# sourceMappingURL=pi_forward_client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pi_forward_client.js","sourceRoot":"","sources":["../../src/transport/pi_forward_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA2C3C,MAAM,OAAO,eAAgB,SAAQ,YAAY;IAIlB;IAHZ,cAAc,CAAyB;IAChD,QAAQ,GAAG,KAAK,CAAC;IAEzB,YAA6B,KAAkB;QAC7C,KAAK,EAAE,CAAC;QADmB,UAAK,GAAL,KAAK,CAAa;QAE7C,IAAI,CAAC,cAAc,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;OAMG;IACH,gBAAgB,CAAC,IAAY,EAAE,GAAa;QAC1C,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,MAAM,KAAK,GAAoB,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QACnF,IAAI,CAAC;YACH,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,mEAAmE;QACrE,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM;QACJ,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;IACjD,CAAC;IAEO,WAAW,CAAC,IAAY;QAC9B,sEAAsE;QACtE,mEAAmE;QACnE,oDAAoD;QACpD,IAAI,MAAe,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO;QAClD,MAAM,CAAC,GAAG,MAAoC,CAAC;QAC/C,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO;QACxC,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAE3F,+EAA+E;QAC/E,MAAM,GAAG,GAAG,CAAC,CAAC,QAAoB,CAAC;QACnC,IAAI,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;YAAE,OAAO;QACvE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACxC,CAAC;CACF"}
package/dist/ui/footer.js CHANGED
@@ -21,12 +21,14 @@ export function updateFooter(ctx, state) {
21
21
  else {
22
22
  ctx.ui.setStatus(K_PEER, undefined);
23
23
  }
24
- const titleParts = [];
25
- if (state.session)
26
- titleParts.push(state.session);
27
- if (state.relayOn)
28
- titleParts.push("relay");
24
+ // Terminal title — two parts only: `<agent-name> · <On|Off>`.
25
+ // Pre-2026-05-24 the title carried three segments (`name · local · relay`),
26
+ // but `local` was always the same string (single fixed UDS session) and
27
+ // `relay` repeated information the relay slot already shows. Collapsed
28
+ // to "name + relay state in plain English" — same info, clearer at a
29
+ // glance: terminal tabs read like `backend · On` / `backend · Off`.
29
30
  const prefix = state.agentName?.trim() || "Pi";
30
- ctx.ui.setTitle(titleParts.length ? `${prefix} · ${titleParts.join(" · ")}` : prefix);
31
+ const relayState = state.relayOn ? "On" : "Off";
32
+ ctx.ui.setTitle(`${prefix} · ${relayState}`);
31
33
  }
32
34
  //# sourceMappingURL=footer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../src/ui/footer.ts"],"names":[],"mappings":"AAiCA,MAAM,SAAS,GAAG,mBAAmB,CAAC;AACtC,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAClC,MAAM,MAAM,GAAG,uBAAuB,CAAC;AAEvC,MAAM,UAAU,YAAY,CAAC,GAAkB,EAAE,KAAkB;IACjE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,KAAK,CAAC,OAAO,KAAK,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,GAAG,CAAC,EAAE,CAAC,SAAS,CACd,OAAO,EACP,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,8BAA8B,CAChE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,KAAK,CAAC,OAAO;QAAE,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,KAAK,CAAC,OAAO;QAAE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/C,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,MAAM,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACxF,CAAC"}
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../src/ui/footer.ts"],"names":[],"mappings":"AAiCA,MAAM,SAAS,GAAG,mBAAmB,CAAC;AACtC,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAClC,MAAM,MAAM,GAAG,uBAAuB,CAAC;AAEvC,MAAM,UAAU,YAAY,CAAC,GAAkB,EAAE,KAAkB;IACjE,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,CAAC;QACnC,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,KAAK,CAAC,OAAO,KAAK,KAAK,GAAG,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,GAAG,CAAC,EAAE,CAAC,SAAS,CACd,OAAO,EACP,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,8BAA8B,CAChE,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC;IACvD,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACtC,CAAC;IAED,8DAA8D;IAC9D,4EAA4E;IAC5E,wEAAwE;IACxE,uEAAuE;IACvE,qEAAqE;IACrE,oEAAoE;IACpE,MAAM,MAAM,GAAG,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAC/C,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IAChD,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,MAAM,MAAM,UAAU,EAAE,CAAC,CAAC;AAC/C,CAAC"}