@threadbase-sh/streamer 1.24.2 → 1.24.4

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/dist/index.d.cts CHANGED
@@ -202,6 +202,7 @@ type WSMessage = {
202
202
  type: "permission";
203
203
  sessionId: string;
204
204
  prompt?: string;
205
+ detail?: string;
205
206
  options: PermissionOption[];
206
207
  cursor?: number;
207
208
  } | {
@@ -326,6 +327,7 @@ interface PTYManagerOptions {
326
327
  onReady?: (session: ManagedSession) => void;
327
328
  onPermissionChange?: (sessionId: string, gate: {
328
329
  prompt?: string;
330
+ detail?: string;
329
331
  options: PermissionOption[];
330
332
  cursor?: number;
331
333
  } | null) => void;
@@ -985,6 +987,15 @@ declare class ConversationWatcher {
985
987
  constructor(events?: ConversationWatcherEvents);
986
988
  watch(filePath: string): void;
987
989
  unwatch(filePath: string): void;
990
+ /**
991
+ * Re-drive the tail read for a file that's already being tailed. A per-file
992
+ * chokidar handle can die silently (fs.watch stops firing after inode churn)
993
+ * while the coarser directory watcher keeps reporting changes — calling this
994
+ * from the directory-event path makes the tail self-healing. Reads are
995
+ * offset-based and coalesced, so a redundant poke after a normal change
996
+ * event is a cheap stat + no-op. Returns false for untailed paths.
997
+ */
998
+ poke(filePath: string): boolean;
988
999
  /**
989
1000
  * Watch a directory of conversation JSONL files. Fires
990
1001
  * onConversationChanged for any add/change/unlink event so the caller
package/dist/index.d.ts CHANGED
@@ -202,6 +202,7 @@ type WSMessage = {
202
202
  type: "permission";
203
203
  sessionId: string;
204
204
  prompt?: string;
205
+ detail?: string;
205
206
  options: PermissionOption[];
206
207
  cursor?: number;
207
208
  } | {
@@ -326,6 +327,7 @@ interface PTYManagerOptions {
326
327
  onReady?: (session: ManagedSession) => void;
327
328
  onPermissionChange?: (sessionId: string, gate: {
328
329
  prompt?: string;
330
+ detail?: string;
329
331
  options: PermissionOption[];
330
332
  cursor?: number;
331
333
  } | null) => void;
@@ -985,6 +987,15 @@ declare class ConversationWatcher {
985
987
  constructor(events?: ConversationWatcherEvents);
986
988
  watch(filePath: string): void;
987
989
  unwatch(filePath: string): void;
990
+ /**
991
+ * Re-drive the tail read for a file that's already being tailed. A per-file
992
+ * chokidar handle can die silently (fs.watch stops firing after inode churn)
993
+ * while the coarser directory watcher keeps reporting changes — calling this
994
+ * from the directory-event path makes the tail self-healing. Reads are
995
+ * offset-based and coalesced, so a redundant poke after a normal change
996
+ * event is a cheap stat + no-op. Returns false for untailed paths.
997
+ */
998
+ poke(filePath: string): boolean;
988
999
  /**
989
1000
  * Watch a directory of conversation JSONL files. Fires
990
1001
  * onConversationChanged for any add/change/unlink event so the caller
package/dist/index.js CHANGED
@@ -1145,14 +1145,41 @@ function scrapePermissionGate(lines) {
1145
1145
  }
1146
1146
  if (options.length === 0) return null;
1147
1147
  let prompt;
1148
+ let promptLine = -1;
1148
1149
  for (let i = firstOptionLine - 1; i >= 0; i--) {
1149
1150
  const t = stripGutter(lines[i]).trim();
1150
1151
  if (t.length === 0) continue;
1151
1152
  if (BOX_ONLY_RE.test(lines[i].trim()) || FOOTER_RE.test(t) || PROMPT_ARROW_RE.test(t)) continue;
1152
1153
  prompt = t || void 0;
1154
+ promptLine = i;
1153
1155
  break;
1154
1156
  }
1155
- return { ...prompt ? { prompt } : {}, options, ...cursor !== void 0 ? { cursor } : {} };
1157
+ const detail = promptLine > 0 ? scrapeDetail(lines, promptLine) : void 0;
1158
+ return {
1159
+ ...prompt ? { prompt } : {},
1160
+ ...detail ? { detail } : {},
1161
+ options,
1162
+ ...cursor !== void 0 ? { cursor } : {}
1163
+ };
1164
+ }
1165
+ var MAX_DETAIL_LINES = 6;
1166
+ function scrapeDetail(lines, promptLine) {
1167
+ const collected = [];
1168
+ let blankRun = 0;
1169
+ for (let i = promptLine - 1; i >= 0; i--) {
1170
+ const t = stripGutter(lines[i]).trim();
1171
+ if (BOX_ONLY_RE.test(t)) break;
1172
+ if (t.length === 0) {
1173
+ blankRun++;
1174
+ if (blankRun >= 2) break;
1175
+ continue;
1176
+ }
1177
+ blankRun = 0;
1178
+ if (FOOTER_RE.test(t) || PROMPT_ARROW_RE.test(t)) continue;
1179
+ collected.push(t);
1180
+ if (collected.length >= MAX_DETAIL_LINES) break;
1181
+ }
1182
+ return collected.length > 0 ? collected.reverse().join("\n") : void 0;
1156
1183
  }
1157
1184
 
1158
1185
  // src/services/questions/detectQuestionFromScreen.ts
@@ -4100,6 +4127,19 @@ var ConversationWatcher = class {
4100
4127
  void entry.watcher.close();
4101
4128
  this.files.delete(filePath);
4102
4129
  }
4130
+ /**
4131
+ * Re-drive the tail read for a file that's already being tailed. A per-file
4132
+ * chokidar handle can die silently (fs.watch stops firing after inode churn)
4133
+ * while the coarser directory watcher keeps reporting changes — calling this
4134
+ * from the directory-event path makes the tail self-healing. Reads are
4135
+ * offset-based and coalesced, so a redundant poke after a normal change
4136
+ * event is a cheap stat + no-op. Returns false for untailed paths.
4137
+ */
4138
+ poke(filePath) {
4139
+ if (!this.files.has(filePath)) return false;
4140
+ void this.readNewLines(filePath);
4141
+ return true;
4142
+ }
4103
4143
  /**
4104
4144
  * Watch a directory of conversation JSONL files. Fires
4105
4145
  * onConversationChanged for any add/change/unlink event so the caller
@@ -4936,6 +4976,7 @@ var StreamerServer = class {
4936
4976
  }
4937
4977
  },
4938
4978
  onConversationChanged: (filePath) => {
4979
+ this.fileWatcher.poke(filePath);
4939
4980
  this.cache?.invalidateByFilePath(filePath, { skipIfTailed: true });
4940
4981
  this.markScannerStaleDebounced();
4941
4982
  this.log.debug?.(`Scanner invalidated by directory event: ${filePath}`, {
@@ -6319,6 +6360,7 @@ var StreamerServer = class {
6319
6360
  type: "permission",
6320
6361
  sessionId,
6321
6362
  ...gate.prompt ? { prompt: gate.prompt } : {},
6363
+ ...gate.detail ? { detail: gate.detail } : {},
6322
6364
  options: gate.options,
6323
6365
  ...gate.cursor !== void 0 ? { cursor: gate.cursor } : {}
6324
6366
  });