aibroker 0.34.1 → 0.35.1

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.
@@ -16,19 +16,45 @@ import { saveJson } from "../../core/json-store.js";
16
16
  const QUEUE_DIR = join(homedir(), ".aibroker");
17
17
  const QUEUE_FILE = join(QUEUE_DIR, "pailot-queue.json");
18
18
  const DEFAULT_MAX_SIZE = 500;
19
+ /**
20
+ * A byte ceiling, because a count is not a size.
21
+ *
22
+ * The queue held 500 messages and 194 MB of them: three videos at 29.7 MB each,
23
+ * base64, plus a month of screenshots. A client reconnecting asked for
24
+ * everything it had missed, got all of it, wrote it to its own store, and was
25
+ * killed by the watchdog on the next launch trying to parse it.
26
+ *
27
+ * Counting messages bounds nothing when one message can be tens of megabytes.
28
+ */
29
+ const DEFAULT_MAX_BYTES = 16 * 1024 * 1024;
30
+ /**
31
+ * The point past which an attachment is not worth replaying.
32
+ *
33
+ * A queue exists so a client that was offline for a while does not lose the
34
+ * thread. Text is what carries the thread; a 30 MB video is not something a
35
+ * reconnecting phone needs handed to it unasked, and it is what breaks the
36
+ * phone when it does. Big payloads are dropped and the caption says so, which
37
+ * leaves the conversation readable and the attachment retrievable on request.
38
+ */
39
+ const MAX_PAYLOAD_BYTES = 256 * 1024;
40
+ /** Fields that carry bulk. Dropping them leaves the message and its context. */
41
+ const BULK_FIELDS = ["imageBase64", "audioBase64", "data"];
19
42
  /** Content types that get persisted to the queue. */
20
43
  const CONTENT_TYPES = new Set(["text", "voice", "image"]);
21
44
  // --- Module state ---
22
45
  let nextSeq = 1;
23
46
  let messages = [];
24
47
  let maxSize = DEFAULT_MAX_SIZE;
48
+ let maxBytes = DEFAULT_MAX_BYTES;
25
49
  let dirty = false;
26
50
  let flushTimer = null;
27
51
  // --- Persistence ---
28
52
  /** Load the queue from disk. Call once at daemon startup. */
29
- export function loadQueue(maxMessages) {
53
+ export function loadQueue(maxMessages, maxQueueBytes) {
30
54
  if (maxMessages)
31
55
  maxSize = maxMessages;
56
+ if (maxQueueBytes)
57
+ maxBytes = maxQueueBytes;
32
58
  try {
33
59
  mkdirSync(QUEUE_DIR, { recursive: true });
34
60
  const raw = readFileSync(QUEUE_FILE, "utf-8");
@@ -39,6 +65,10 @@ export function loadQueue(maxMessages) {
39
65
  if (Array.isArray(state.messages)) {
40
66
  // Trim to maxSize on load (queue file could have been edited)
41
67
  messages = state.messages.slice(-maxSize);
68
+ // And to the byte budget: a queue written before this limit existed, or
69
+ // edited by hand, must not survive a restart intact and be replayed.
70
+ messages = messages.map(shrinkIfHuge);
71
+ trimToByteBudget();
42
72
  }
43
73
  log(`[MQ] loaded ${messages.length} messages, nextSeq=${nextSeq}`);
44
74
  }
@@ -110,14 +140,68 @@ export function enqueue(sessionId, type, payload) {
110
140
  payload: { ...payload, seq },
111
141
  ts: Date.now(),
112
142
  };
113
- messages.push(entry);
143
+ messages.push(shrinkIfHuge(entry));
114
144
  // Trim circular buffer
115
145
  if (messages.length > maxSize) {
116
146
  messages = messages.slice(-maxSize);
117
147
  }
148
+ trimToByteBudget();
118
149
  scheduleSave();
119
150
  return seq;
120
151
  }
152
+ /** Size of an entry as it would be stored and replayed. */
153
+ function entryBytes(m) {
154
+ try {
155
+ return JSON.stringify(m).length;
156
+ }
157
+ catch {
158
+ return 0;
159
+ }
160
+ }
161
+ /**
162
+ * Strip the bulk from an oversized entry, keeping the message itself.
163
+ *
164
+ * Done at ENQUEUE, not at replay: a payload nobody can be handed is not worth
165
+ * carrying on disk either, and stripping once is cheaper than deciding again
166
+ * for every client that reconnects.
167
+ */
168
+ function shrinkIfHuge(m) {
169
+ if (entryBytes(m) <= MAX_PAYLOAD_BYTES)
170
+ return m;
171
+ const payload = { ...m.payload };
172
+ let dropped = false;
173
+ for (const f of BULK_FIELDS) {
174
+ if (payload[f]) {
175
+ delete payload[f];
176
+ dropped = true;
177
+ }
178
+ }
179
+ if (!dropped)
180
+ return m;
181
+ const caption = typeof payload.caption === "string" ? payload.caption : "";
182
+ payload.caption = `${caption}${caption ? " " : ""}[attachment too large to replay — ask for it again if you need it]`;
183
+ log(`[MQ] seq=${m.seq} exceeded ${Math.round(MAX_PAYLOAD_BYTES / 1024)} KB — stored without its attachment`);
184
+ return { ...m, payload };
185
+ }
186
+ /**
187
+ * Drop the oldest messages until the queue fits its byte budget.
188
+ *
189
+ * Oldest first, because the queue's purpose is recent continuity: a client
190
+ * that has been away long enough to need the far end of the buffer has lost
191
+ * the thread regardless.
192
+ */
193
+ function trimToByteBudget() {
194
+ let total = messages.reduce((n, m) => n + entryBytes(m), 0);
195
+ if (total <= maxBytes)
196
+ return;
197
+ let dropped = 0;
198
+ while (messages.length > 1 && total > maxBytes) {
199
+ total -= entryBytes(messages[0]);
200
+ messages.shift();
201
+ dropped++;
202
+ }
203
+ log(`[MQ] byte budget exceeded — dropped ${dropped} oldest message(s), now ${Math.round(total / 1024)} KB`);
204
+ }
121
205
  /**
122
206
  * Get all messages with seq > afterSeq.
123
207
  * Optionally filter by sessionId (returns all sessions if not specified).
@@ -1 +1 @@
1
- {"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../../src/adapters/pailot/message-queue.ts"],"names":[],"mappings":"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"}
@@ -30,7 +30,32 @@ export declare class HybridSessionManager {
30
30
  private readonly sessions;
31
31
  private _activeIndex;
32
32
  private nextNum;
33
+ private discover?;
34
+ /** True when the last attempt to look could not complete, so the list is last-known. */
35
+ private lastDiscoveryFailed;
36
+ /** When discovery last ran, so a burst of readers costs one enumeration. */
37
+ private lastSyncAt;
38
+ private coalesceMs;
33
39
  constructor(apiBackend: APIBackend);
40
+ /**
41
+ * Where live sessions come from. Injected rather than imported so this stays
42
+ * a registry rather than growing a dependency on a particular terminal.
43
+ */
44
+ setDiscovery(fn: () => Array<{
45
+ id: string;
46
+ name: string;
47
+ paiName?: string | null;
48
+ tabTitle?: string | null;
49
+ }>): void;
50
+ /**
51
+ * Change how long one enumeration is reused for.
52
+ *
53
+ * Exists so tests can assert the two properties separately: that a burst
54
+ * costs one enumeration, and that a fresh look reflects what changed. With a
55
+ * fixed window the second is only observable by waiting, which makes the
56
+ * suite slow and the failure mode ambiguous.
57
+ */
58
+ setCoalesceWindow(ms: number): void;
34
59
  /** Create a new headless (API) session. Delegates to APIBackend. */
35
60
  createApiSession(name: string, cwd: string): HybridSession;
36
61
  /** Register a visual (iTerm2) session. The transport creates the tab and passes the ID. */
@@ -50,11 +75,55 @@ export declare class HybridSessionManager {
50
75
  pruneDeadVisualSessions(liveIds: Set<string>): number;
51
76
  /** Update the name of a session identified by its backend ID. */
52
77
  updateName(backendSessionId: string, newName: string): void;
53
- /** All sessions in creation order. */
78
+ /**
79
+ * All sessions in creation order, after checking what is actually running.
80
+ *
81
+ * For anything a person asked for. Discovery is an AppleScript round trip, so
82
+ * this is the wrong call on a path that runs per message — use
83
+ * `knownSessions()` there.
84
+ */
54
85
  listSessions(): HybridSession[];
86
+ /**
87
+ * What the registry already knows, without going out to look.
88
+ *
89
+ * The read for hot paths: resolving a name for a push, checking that an id
90
+ * still exists on the way through. Those run per message, and an enumeration
91
+ * per message would put a terminal round trip in the delivery loop. Callers
92
+ * that need certainty rather than speed should fall back to `listSessions()`
93
+ * when this misses — cheap in the common case, correct in the rare one.
94
+ */
95
+ knownSessions(): HybridSession[];
96
+ /**
97
+ * Bring the registry in line with what is actually running.
98
+ *
99
+ * Both read paths call this, which is the point: a caller cannot forget to
100
+ * populate, because populating is not the caller's job. Registration by the
101
+ * gateway and by the command that spawns a tab still works and is still
102
+ * useful — it names a session at the moment it is created, before discovery
103
+ * would have anything to go on — this only guarantees the floor.
104
+ *
105
+ * TWO FAILURES THAT ARE NOT THE SAME FACT. Discovery throwing means we could
106
+ * not look; discovery returning nothing means we looked and there is nothing.
107
+ * Folding them together would trade a false "none" for a false "current" —
108
+ * a list that reads as freshly enumerated while being last-known, which is
109
+ * the same lie as a Funnel reporting itself on while refusing connections.
110
+ *
111
+ * So: a throw keeps the known list AND is surfaced to the reader. An honest
112
+ * empty prunes, because a registry that keeps dead rows after looking is
113
+ * showing sessions that do not exist.
114
+ */
115
+ private syncFromLive;
55
116
  /** Get session by 1-based display index. */
56
117
  getByIndex(index: number): HybridSession | undefined;
57
- /** Format the unified session list for display. */
118
+ /**
119
+ * Format the unified session list for display.
120
+ *
121
+ * Discovers first, so "No sessions." can only ever mean there are none —
122
+ * not that nobody had populated the registry yet. Before this, the answer
123
+ * depended on whether a PAILot client had happened to connect since the last
124
+ * daemon restart: ask over a channel before that and you were told the
125
+ * machine was empty, in the same words it would use if it were.
126
+ */
58
127
  formatSessionList(): string;
59
128
  /**
60
129
  * Get a status string for the active session.
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/core/hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,oBAAoB;IAC/B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,OAAO,CAAK;gBAER,UAAU,EAAE,UAAU;IAMlC,oEAAoE;IACpE,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa;IAkB1D,2FAA2F;IAC3F,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,aAAa;IAiBvF,oFAAoF;IACpF,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAYvD,0FAA0F;IAC1F,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAiCvD,6EAA6E;IAC7E,kBAAkB,IAAI,IAAI;IAW1B,0DAA0D;IAC1D,IAAI,aAAa,IAAI,aAAa,GAAG,SAAS,CAE7C;IAED;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM;IAoBrD,iEAAiE;IACjE,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ3D,sCAAsC;IACtC,YAAY,IAAI,aAAa,EAAE;IAI/B,4CAA4C;IAC5C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMpD,mDAAmD;IACnD,iBAAiB,IAAI,MAAM;IAU3B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,GAAG,IAAI;CASpC;AAED,wEAAwE;AACxE,eAAO,IAAI,aAAa,EAAE,oBAAoB,GAAG,IAAW,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAErE"}
1
+ {"version":3,"file":"hybrid.d.ts","sourceRoot":"","sources":["../../src/core/hybrid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAapD,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,mBAAmB;IACnB,IAAI,EAAE,WAAW,CAAC;IAClB,yBAAyB;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,qBAAa,oBAAoB;IAC/B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,QAAQ,CAAC,CAA+F;IAChH,wFAAwF;IACxF,OAAO,CAAC,mBAAmB,CAAS;IACpC,4EAA4E;IAC5E,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAoB;gBAE1B,UAAU,EAAE,UAAU;IAIlC;;;OAGG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,GAAG,IAAI;IAIpH;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAMnC,oEAAoE;IACpE,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa;IAkB1D,2FAA2F;IAC3F,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,aAAa;IAiBvF,oFAAoF;IACpF,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAYvD,0FAA0F;IAC1F,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAiCvD,6EAA6E;IAC7E,kBAAkB,IAAI,IAAI;IAW1B,0DAA0D;IAC1D,IAAI,aAAa,IAAI,aAAa,GAAG,SAAS,CAE7C;IAED;;;OAGG;IACH,uBAAuB,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM;IAoBrD,iEAAiE;IACjE,UAAU,CAAC,gBAAgB,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ3D;;;;;;OAMG;IACH,YAAY,IAAI,aAAa,EAAE;IAK/B;;;;;;;;OAQG;IACH,aAAa,IAAI,aAAa,EAAE;IAIhC;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,YAAY;IAoDpB,4CAA4C;IAC5C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAMpD;;;;;;;;OAQG;IACH,iBAAiB,IAAI,MAAM;IAqB3B;;;;OAIG;IACH,kBAAkB,IAAI,MAAM,GAAG,IAAI;CASpC;AAED,wEAAwE;AACxE,eAAO,IAAI,aAAa,EAAE,oBAAoB,GAAG,IAAW,CAAC;AAE7D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAErE"}
@@ -10,14 +10,47 @@
10
10
  * the active session's kind — the transport decides how to deliver.
11
11
  */
12
12
  import { log } from "./log.js";
13
+ import { activeItermSessionId } from "./state.js";
14
+ /**
15
+ * How long one enumeration is reused for.
16
+ *
17
+ * Short enough that no answer a person reads is meaningfully out of date;
18
+ * long enough that a client reconnect storm cannot turn a blocking terminal
19
+ * query into the daemon's whole capacity.
20
+ */
21
+ const SYNC_COALESCE_MS = 3_000;
13
22
  export class HybridSessionManager {
14
23
  apiBackend;
15
24
  sessions = [];
16
25
  _activeIndex = -1;
17
26
  nextNum = 1;
27
+ discover;
28
+ /** True when the last attempt to look could not complete, so the list is last-known. */
29
+ lastDiscoveryFailed = false;
30
+ /** When discovery last ran, so a burst of readers costs one enumeration. */
31
+ lastSyncAt = 0;
32
+ coalesceMs = SYNC_COALESCE_MS;
18
33
  constructor(apiBackend) {
19
34
  this.apiBackend = apiBackend;
20
35
  }
36
+ /**
37
+ * Where live sessions come from. Injected rather than imported so this stays
38
+ * a registry rather than growing a dependency on a particular terminal.
39
+ */
40
+ setDiscovery(fn) {
41
+ this.discover = fn;
42
+ }
43
+ /**
44
+ * Change how long one enumeration is reused for.
45
+ *
46
+ * Exists so tests can assert the two properties separately: that a burst
47
+ * costs one enumeration, and that a fresh look reflects what changed. With a
48
+ * fixed window the second is only observable by waiting, which makes the
49
+ * suite slow and the failure mode ambiguous.
50
+ */
51
+ setCoalesceWindow(ms) {
52
+ this.coalesceMs = ms;
53
+ }
21
54
  // ── Session creation ──
22
55
  /** Create a new headless (API) session. Delegates to APIBackend. */
23
56
  createApiSession(name, cwd) {
@@ -146,25 +179,136 @@ export class HybridSessionManager {
146
179
  s.name = newName;
147
180
  }
148
181
  }
149
- /** All sessions in creation order. */
182
+ /**
183
+ * All sessions in creation order, after checking what is actually running.
184
+ *
185
+ * For anything a person asked for. Discovery is an AppleScript round trip, so
186
+ * this is the wrong call on a path that runs per message — use
187
+ * `knownSessions()` there.
188
+ */
150
189
  listSessions() {
190
+ this.syncFromLive();
191
+ return [...this.sessions];
192
+ }
193
+ /**
194
+ * What the registry already knows, without going out to look.
195
+ *
196
+ * The read for hot paths: resolving a name for a push, checking that an id
197
+ * still exists on the way through. Those run per message, and an enumeration
198
+ * per message would put a terminal round trip in the delivery loop. Callers
199
+ * that need certainty rather than speed should fall back to `listSessions()`
200
+ * when this misses — cheap in the common case, correct in the rare one.
201
+ */
202
+ knownSessions() {
151
203
  return [...this.sessions];
152
204
  }
205
+ /**
206
+ * Bring the registry in line with what is actually running.
207
+ *
208
+ * Both read paths call this, which is the point: a caller cannot forget to
209
+ * populate, because populating is not the caller's job. Registration by the
210
+ * gateway and by the command that spawns a tab still works and is still
211
+ * useful — it names a session at the moment it is created, before discovery
212
+ * would have anything to go on — this only guarantees the floor.
213
+ *
214
+ * TWO FAILURES THAT ARE NOT THE SAME FACT. Discovery throwing means we could
215
+ * not look; discovery returning nothing means we looked and there is nothing.
216
+ * Folding them together would trade a false "none" for a false "current" —
217
+ * a list that reads as freshly enumerated while being last-known, which is
218
+ * the same lie as a Funnel reporting itself on while refusing connections.
219
+ *
220
+ * So: a throw keeps the known list AND is surfaced to the reader. An honest
221
+ * empty prunes, because a registry that keeps dead rows after looking is
222
+ * showing sessions that do not exist.
223
+ */
224
+ syncFromLive() {
225
+ if (!this.discover)
226
+ return;
227
+ // COALESCE. Discovery is a blocking AppleScript round trip — measured at
228
+ // 1.26 s on this machine — and Node has one thread. A mobile client that
229
+ // reconnects every two seconds asks for the list on every connect, so each
230
+ // reconnect stalled the whole daemon for seconds: heartbeats from other
231
+ // adapters timed out, their re-registrations queued behind the same lock,
232
+ // and the phone's own connection dropped because nothing could service it,
233
+ // which made it reconnect again. The hub spent fifteen seconds at a time
234
+ // unable to answer anything.
235
+ //
236
+ // A short reuse window, not a cache with a lifetime: it exists to make a
237
+ // BURST cost one enumeration, and it is deliberately shorter than a human
238
+ // can act, so no user-visible answer is stale by more than a moment.
239
+ const now = Date.now();
240
+ if (now - this.lastSyncAt < this.coalesceMs)
241
+ return;
242
+ this.lastSyncAt = now;
243
+ let live;
244
+ try {
245
+ live = this.discover();
246
+ this.lastDiscoveryFailed = false;
247
+ }
248
+ catch (e) {
249
+ this.lastDiscoveryFailed = true;
250
+ log(`HybridManager: discovery failed, keeping the known list — ${e instanceof Error ? e.message : String(e)}`);
251
+ return;
252
+ }
253
+ const liveIds = new Set(live.map((s) => s.id));
254
+ this.pruneDeadVisualSessions(liveIds);
255
+ const known = new Set(this.sessions.map((s) => s.backendSessionId));
256
+ const seen = new Set();
257
+ const activeBefore = this.activeSession;
258
+ for (const snap of live) {
259
+ const displayName = snap.paiName ?? snap.tabTitle ?? snap.name;
260
+ if (seen.has(displayName))
261
+ continue;
262
+ seen.add(displayName);
263
+ if (!known.has(snap.id))
264
+ this.registerVisualSession(displayName, "", snap.id);
265
+ }
266
+ // registerVisualSession moves the selection to whatever it just added.
267
+ // Discovery is not a selection, so put it back where the user left it —
268
+ // and on the FIRST population there is nothing to put back, which would
269
+ // otherwise leave "active" pointing at whichever tab happened to be
270
+ // enumerated last. Fall back to the session the hub actually considers
271
+ // active, so this list and every other reader mark the same one.
272
+ const restoreTo = activeBefore?.backendSessionId ?? activeItermSessionId;
273
+ if (restoreTo) {
274
+ const i = this.sessions.findIndex((s) => s.backendSessionId === restoreTo);
275
+ if (i >= 0)
276
+ this._activeIndex = i;
277
+ }
278
+ }
153
279
  /** Get session by 1-based display index. */
154
280
  getByIndex(index) {
155
281
  return this.sessions[index - 1];
156
282
  }
157
283
  // ── Display ──
158
- /** Format the unified session list for display. */
284
+ /**
285
+ * Format the unified session list for display.
286
+ *
287
+ * Discovers first, so "No sessions." can only ever mean there are none —
288
+ * not that nobody had populated the registry yet. Before this, the answer
289
+ * depended on whether a PAILot client had happened to connect since the last
290
+ * daemon restart: ask over a channel before that and you were told the
291
+ * machine was empty, in the same words it would use if it were.
292
+ */
159
293
  formatSessionList() {
160
- if (this.sessions.length === 0)
161
- return "No sessions.";
162
- return this.sessions.map((s, i) => {
294
+ this.syncFromLive();
295
+ // Say which of the two it is. A reader cannot otherwise tell a machine with
296
+ // nothing running from one we could not ask.
297
+ if (this.sessions.length === 0) {
298
+ return this.lastDiscoveryFailed
299
+ ? "Could not enumerate sessions, and none were known."
300
+ : "No sessions.";
301
+ }
302
+ const rows = this.sessions.map((s, i) => {
163
303
  const isActive = i === this._activeIndex;
164
304
  const tag = s.kind === "api" ? "[api]" : "[visual]";
165
305
  const marker = isActive ? "*" : " ";
166
306
  return `${marker}${i + 1}. ${s.name} ${tag}${s.cwd ? ` (${s.cwd})` : ""}`;
167
- }).join("\n");
307
+ });
308
+ if (this.lastDiscoveryFailed) {
309
+ rows.push("(could not enumerate sessions — showing last known)");
310
+ }
311
+ return rows.join("\n");
168
312
  }
169
313
  /**
170
314
  * Get a status string for the active session.
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid.js","sourceRoot":"","sources":["../../src/core/hybrid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hybrid.js","sourceRoot":"","sources":["../../src/core/hybrid.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAM5C"}
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED,wBAAgB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAa5C"}
package/dist/core/log.js CHANGED
@@ -7,7 +7,13 @@ export function setLogPrefix(prefix) {
7
7
  _prefix = prefix;
8
8
  }
9
9
  export function log(...args) {
10
- const timestamp = new Date().toISOString().slice(11, 23);
10
+ // LOCAL time, not UTC. Every other timestamp a person sees here — the audit
11
+ // trail, the tracker, the messages themselves — is local, and this log is
12
+ // read by lining it up against those. An offset that has to be remembered
13
+ // gets forgotten, and the reader concludes the events are unrelated.
14
+ const now = new Date();
15
+ const p = (n, w = 2) => String(n).padStart(w, "0");
16
+ const timestamp = `${p(now.getHours())}:${p(now.getMinutes())}:${p(now.getSeconds())}.${p(now.getMilliseconds(), 3)}`;
11
17
  const parts = args.map((a) => typeof a === "string" ? a : JSON.stringify(a));
12
18
  process.stderr.write(`[${_prefix} ${timestamp}] ${parts.join(" ")}\n`);
13
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,IAAI,OAAO,GAAG,UAAU,CAAC;AAEzB,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,GAAG,IAAe;IACpC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC"}
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,IAAI,OAAO,GAAG,UAAU,CAAC;AAEzB,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,GAAG,MAAM,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,GAAG,IAAe;IACpC,4EAA4E;IAC5E,0EAA0E;IAC1E,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC3D,MAAM,SAAS,GACb,GAAG,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;IACtG,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAC3B,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAC9C,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * core/session-discovery.ts — one answer to "which sessions are there".
3
+ *
4
+ * There were two, and they disagreed. The MCP tool enumerated live iTerm tabs
5
+ * directly; the channel commands read `HybridSessionManager`, an in-memory
6
+ * registry that only the PAILot gateway ever populated. So `aibroker_sessions`
7
+ * reported eight sessions while `/s` over WhatsApp answered "No sessions" —
8
+ * and the daemon's own handler carried the comment
9
+ *
10
+ * manager.listSessions() is always empty (nothing populates the registry)
11
+ *
12
+ * which is the defect written down and worked around rather than fixed.
13
+ *
14
+ * WHY THIS IS WORSE THAN A WRONG NUMBER. "No sessions" is what an empty machine
15
+ * says, so an unpopulated registry is indistinguishable from a true answer. The
16
+ * same shape has bitten this codebase before and been closed deliberately each
17
+ * time: an unreadable audit log that read as an empty one, a Funnel reporting
18
+ * itself on while refusing every connection. A reader cannot tell "none" from
19
+ * "did not look" unless the code refuses to say "none" without looking.
20
+ *
21
+ * So discovery lives here, both readers call it, and nobody has to remember to
22
+ * populate anything first.
23
+ */
24
+ import { snapshotAllSessions } from "../adapters/iterm/core.js";
25
+ export type LiveSession = ReturnType<typeof snapshotAllSessions>[0];
26
+ /**
27
+ * Live sessions, with their PAI names filled in.
28
+ *
29
+ * `snapshotAllSessions()` has returned `paiName: null` since 0.7.10 — the
30
+ * authoritative source is the persistent store — so a caller that skips this
31
+ * step gets tab titles where it expects names.
32
+ */
33
+ export declare function discoverLiveSessions(): LiveSession[];
34
+ /**
35
+ * Is this tab something a person would call a session?
36
+ *
37
+ * Deliberately generous: a named tab, anything that says Claude, or anything
38
+ * not sitting at a shell prompt. Being wrong in the inclusive direction shows
39
+ * a row too many, which a human corrects at a glance; being wrong the other way
40
+ * hides a session that exists, which reads as it not existing at all.
41
+ */
42
+ export declare function isClaudeRelated(snap: LiveSession): boolean;
43
+ //# sourceMappingURL=session-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-discovery.d.ts","sourceRoot":"","sources":["../../src/core/session-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAGhE,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEpE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI,WAAW,EAAE,CAOpD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAM1D"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * core/session-discovery.ts — one answer to "which sessions are there".
3
+ *
4
+ * There were two, and they disagreed. The MCP tool enumerated live iTerm tabs
5
+ * directly; the channel commands read `HybridSessionManager`, an in-memory
6
+ * registry that only the PAILot gateway ever populated. So `aibroker_sessions`
7
+ * reported eight sessions while `/s` over WhatsApp answered "No sessions" —
8
+ * and the daemon's own handler carried the comment
9
+ *
10
+ * manager.listSessions() is always empty (nothing populates the registry)
11
+ *
12
+ * which is the defect written down and worked around rather than fixed.
13
+ *
14
+ * WHY THIS IS WORSE THAN A WRONG NUMBER. "No sessions" is what an empty machine
15
+ * says, so an unpopulated registry is indistinguishable from a true answer. The
16
+ * same shape has bitten this codebase before and been closed deliberately each
17
+ * time: an unreadable audit log that read as an empty one, a Funnel reporting
18
+ * itself on while refusing every connection. A reader cannot tell "none" from
19
+ * "did not look" unless the code refuses to say "none" without looking.
20
+ *
21
+ * So discovery lives here, both readers call it, and nobody has to remember to
22
+ * populate anything first.
23
+ */
24
+ import { snapshotAllSessions } from "../adapters/iterm/core.js";
25
+ import { getAllPersistentSessionNames, lookupPersistentName } from "./persistence.js";
26
+ /**
27
+ * Live sessions, with their PAI names filled in.
28
+ *
29
+ * `snapshotAllSessions()` has returned `paiName: null` since 0.7.10 — the
30
+ * authoritative source is the persistent store — so a caller that skips this
31
+ * step gets tab titles where it expects names.
32
+ */
33
+ export function discoverLiveSessions() {
34
+ const snaps = snapshotAllSessions();
35
+ const persistentNames = getAllPersistentSessionNames();
36
+ for (const snap of snaps) {
37
+ snap.paiName = lookupPersistentName(persistentNames, snap.id, snap.aibrokerId);
38
+ }
39
+ return snaps;
40
+ }
41
+ /**
42
+ * Is this tab something a person would call a session?
43
+ *
44
+ * Deliberately generous: a named tab, anything that says Claude, or anything
45
+ * not sitting at a shell prompt. Being wrong in the inclusive direction shows
46
+ * a row too many, which a human corrects at a glance; being wrong the other way
47
+ * hides a session that exists, which reads as it not existing at all.
48
+ */
49
+ export function isClaudeRelated(snap) {
50
+ if (snap.paiName)
51
+ return true;
52
+ const name = (snap.tabTitle ?? snap.name).toLowerCase();
53
+ if (name.includes("claude"))
54
+ return true;
55
+ if (!snap.atPrompt)
56
+ return true;
57
+ return false;
58
+ }
59
+ //# sourceMappingURL=session-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-discovery.js","sourceRoot":"","sources":["../../src/core/session-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,4BAA4B,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAItF;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,mBAAmB,EAAE,CAAC;IACpC,MAAM,eAAe,GAAG,4BAA4B,EAAE,CAAC;IACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,oBAAoB,CAAC,eAAe,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB;IAC/C,IAAI,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACxD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/daemon/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAsDH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA6B3D;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,IAAI,CACzC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,cAAc,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA+6BxB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/daemon/commands.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAwDH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA6B3D;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,IAAI,CACzC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,cAAc,KAChB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA88BxB"}