@threadbase-sh/streamer 1.36.0 → 1.36.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.
package/dist/index.d.cts CHANGED
@@ -301,6 +301,16 @@ interface SessionResponse {
301
301
  pid?: number;
302
302
  sessionName?: string;
303
303
  model?: string;
304
+ /**
305
+ * Reasoning-effort tier scraped from the live PTY status line (e.g. "high").
306
+ * Live sessions only — absent for historical/resumable conversations.
307
+ */
308
+ effort?: string;
309
+ /**
310
+ * Active permission mode from the live PTY status line (e.g. "accept edits on").
311
+ * Live sessions only.
312
+ */
313
+ permissionMode?: string;
304
314
  account?: string;
305
315
  messageCount?: number;
306
316
  preview?: string;
@@ -1032,7 +1042,7 @@ type ApiDeps = {
1032
1042
  handleSessionsCount: (res: ServerResponse) => void;
1033
1043
  handleGetRecentSessions: (url: URL, res: ServerResponse) => void;
1034
1044
  handleGetSessionNames: (res: ServerResponse) => void;
1035
- handleGetSession: (sessionId: string, res: ServerResponse) => void;
1045
+ handleGetSession: (sessionId: string, res: ServerResponse) => Promise<void>;
1036
1046
  handleGetOutput: (sessionId: string, res: ServerResponse) => void;
1037
1047
  handleSendInput: (sessionId: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
1038
1048
  handleSendAnswer: (sessionId: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
package/dist/index.d.ts CHANGED
@@ -301,6 +301,16 @@ interface SessionResponse {
301
301
  pid?: number;
302
302
  sessionName?: string;
303
303
  model?: string;
304
+ /**
305
+ * Reasoning-effort tier scraped from the live PTY status line (e.g. "high").
306
+ * Live sessions only — absent for historical/resumable conversations.
307
+ */
308
+ effort?: string;
309
+ /**
310
+ * Active permission mode from the live PTY status line (e.g. "accept edits on").
311
+ * Live sessions only.
312
+ */
313
+ permissionMode?: string;
304
314
  account?: string;
305
315
  messageCount?: number;
306
316
  preview?: string;
@@ -1032,7 +1042,7 @@ type ApiDeps = {
1032
1042
  handleSessionsCount: (res: ServerResponse) => void;
1033
1043
  handleGetRecentSessions: (url: URL, res: ServerResponse) => void;
1034
1044
  handleGetSessionNames: (res: ServerResponse) => void;
1035
- handleGetSession: (sessionId: string, res: ServerResponse) => void;
1045
+ handleGetSession: (sessionId: string, res: ServerResponse) => Promise<void>;
1036
1046
  handleGetOutput: (sessionId: string, res: ServerResponse) => void;
1037
1047
  handleSendInput: (sessionId: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
1038
1048
  handleSendAnswer: (sessionId: string, req: IncomingMessage, res: ServerResponse) => Promise<void>;
package/dist/index.js CHANGED
@@ -1397,9 +1397,13 @@ import { existsSync as existsSync3 } from "fs";
1397
1397
  import { basename as basename2 } from "path";
1398
1398
 
1399
1399
  // src/services/questions/detectPermissionGate.ts
1400
- var OSC_777_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*/;
1400
+ var OSC_777_PERMISSION_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*needs your permission/;
1401
+ var OSC_777_WAITING_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*waiting for your input/;
1401
1402
  function hasPermissionOsc(rawData) {
1402
- return OSC_777_RE.test(rawData);
1403
+ return OSC_777_PERMISSION_RE.test(rawData);
1404
+ }
1405
+ function hasWaitingForInputOsc(rawData) {
1406
+ return OSC_777_WAITING_RE.test(rawData);
1403
1407
  }
1404
1408
  var OPTION_RE = /^\s*(❯)?\s*(\d+)\.\s+(.+?)\s*$/;
1405
1409
  var FOOTER_RE = /Enter to select|Esc to cancel|↑|↓|to navigate|to cancel/i;
@@ -1550,22 +1554,29 @@ function detectShellPrompt(lines) {
1550
1554
  };
1551
1555
  }
1552
1556
  const lastNumberedIdx = (() => {
1553
- for (let i = last.idx; i >= 0; i--) {
1554
- if (NUMBERED_RE.test(lines[i])) return i;
1557
+ let i = last.idx;
1558
+ if (!NUMBERED_RE.test(lines[i])) {
1559
+ if (i > 0 && (PRESS_ENTER_RE.test(lines[i].trim()) || CONTINUE_RE.test(lines[i].trim()))) {
1560
+ i--;
1561
+ } else {
1562
+ return -1;
1563
+ }
1555
1564
  }
1556
- return -1;
1565
+ while (i >= 0 && !NUMBERED_RE.test(lines[i]) && lines[i].trim().length === 0) i--;
1566
+ return i >= 0 && NUMBERED_RE.test(lines[i]) ? i : -1;
1557
1567
  })();
1558
1568
  if (lastNumberedIdx >= 0) {
1559
1569
  const options = [];
1560
- for (let i = 0; i <= lastNumberedIdx; i++) {
1570
+ let firstRow = lastNumberedIdx;
1571
+ for (let i = lastNumberedIdx; i >= 0; i--) {
1561
1572
  const m = NUMBERED_RE.exec(lines[i]);
1562
- if (!m) continue;
1573
+ if (!m) break;
1563
1574
  const num = Number.parseInt(m[1], 10);
1564
- if (!Number.isFinite(num)) continue;
1565
- options.push({ index: num, label: m[2].trim(), answerKeys: `${num}${ENTER}` });
1575
+ if (!Number.isFinite(num)) break;
1576
+ options.unshift({ index: num, label: m[2].trim(), answerKeys: `${num}${ENTER}` });
1577
+ firstRow = i;
1566
1578
  }
1567
1579
  if (options.length >= 2) {
1568
- const firstRow = lines.findIndex((l) => NUMBERED_RE.test(l));
1569
1580
  let prompt = "";
1570
1581
  for (let i = firstRow - 1; i >= 0; i--) {
1571
1582
  const t = lines[i].trim();
@@ -2134,12 +2145,13 @@ var PTYManager = class {
2134
2145
  const session = this.sessions.get(sessionId);
2135
2146
  if (!session) return;
2136
2147
  const oscPermission = hasPermissionOsc(rawData);
2148
+ const oscWaitingForInput = hasWaitingForInputOsc(rawData);
2137
2149
  const hasAskFooter = /Enter to select/i.test(stripped);
2138
2150
  const hasPromptMarker = CLAUDE_PROMPT_MARKERS.some((m) => stripped.includes(m));
2139
2151
  const hasShellPromptHint = /[[(]\s*y\s*\/\s*n\s*[\])]|press\s+(enter|return|any key)|\bcontinue\b\s*\?|^\s*(?:❯|>)?\s*\d+[.)]\s+\S/im.test(
2140
2152
  stripped
2141
2153
  );
2142
- if (!oscPermission && !hasAskFooter && !hasShellPromptHint && !this.permissionOpen.has(sessionId) && !this.shellPromptOpen.has(sessionId) && !this.lastScreenQuestionKey.has(sessionId)) {
2154
+ if (!oscPermission && !oscWaitingForInput && !hasAskFooter && !hasShellPromptHint && !this.permissionOpen.has(sessionId) && !this.shellPromptOpen.has(sessionId) && !this.lastScreenQuestionKey.has(sessionId)) {
2143
2155
  return;
2144
2156
  }
2145
2157
  const lines = await this.getOutputLines(sessionId, 60);
@@ -2162,11 +2174,11 @@ var PTYManager = class {
2162
2174
  this.onPermissionChange?.(sessionId, gate ?? { options: [] });
2163
2175
  } else if (this.permissionOpen.has(sessionId) && !askFooterOnScreen) {
2164
2176
  const gate = scrapePermissionGate(lines);
2165
- if (gate) {
2166
- this.onPermissionChange?.(sessionId, gate);
2167
- } else if (hasPromptMarker) {
2177
+ if (oscWaitingForInput || !gate && hasPromptMarker) {
2168
2178
  this.permissionOpen.delete(sessionId);
2169
2179
  this.onPermissionChange?.(sessionId, null);
2180
+ } else if (gate) {
2181
+ this.onPermissionChange?.(sessionId, gate);
2170
2182
  }
2171
2183
  }
2172
2184
  if (askFooterOnScreen) {
@@ -3592,8 +3604,8 @@ var createSessionRoutes = (deps) => {
3592
3604
  await deps.handleStopSession(c.req.param("id"), c.env.outgoing);
3593
3605
  return alreadyHandled6();
3594
3606
  });
3595
- app.get("/:id", (c) => {
3596
- deps.handleGetSession(c.req.param("id"), c.env.outgoing);
3607
+ app.get("/:id", async (c) => {
3608
+ await deps.handleGetSession(c.req.param("id"), c.env.outgoing);
3597
3609
  return alreadyHandled6();
3598
3610
  });
3599
3611
  return app;
@@ -5959,6 +5971,32 @@ function deriveProjectChatTitle(input) {
5959
5971
  return `Untitled \xB7 ${input.id.slice(0, 8)}`;
5960
5972
  }
5961
5973
 
5974
+ // src/services/questions/parseStatusLine.ts
5975
+ var MODEL_RE = /(Opus|Sonnet|Haiku|Fable)\s+[\d.]+(?:\s*\([^)]*\))?/;
5976
+ var EFFORT_RE = /●\s*([A-Za-z]+)\s*·\s*\/effort/;
5977
+ var PERMISSION_MODE_RE = /⏵⏵\s*([^(·\n]+?)\s*(?:\(|·|$)/;
5978
+ function parseStatusLine(lines) {
5979
+ const info = {};
5980
+ for (let i = lines.length - 1; i >= 0; i--) {
5981
+ const line = lines[i];
5982
+ if (!line) continue;
5983
+ if (info.effort === void 0) {
5984
+ const m = EFFORT_RE.exec(line);
5985
+ if (m) info.effort = m[1];
5986
+ }
5987
+ if (info.permissionMode === void 0) {
5988
+ const m = PERMISSION_MODE_RE.exec(line);
5989
+ if (m) info.permissionMode = m[1].trim();
5990
+ }
5991
+ if (info.model === void 0) {
5992
+ const m = MODEL_RE.exec(line);
5993
+ if (m) info.model = m[0].replace(/\s+/g, " ").trim();
5994
+ }
5995
+ if (info.model && info.effort && info.permissionMode) break;
5996
+ }
5997
+ return info;
5998
+ }
5999
+
5962
6000
  // src/services/questions/detectAskUserQuestion.ts
5963
6001
  function normalizeContent2(raw) {
5964
6002
  if (Array.isArray(raw)) return raw;
@@ -7115,7 +7153,7 @@ var StreamerServer = class {
7115
7153
  }
7116
7154
  }
7117
7155
  if (msg.type === "hold_session" && typeof msg.sessionId === "string") {
7118
- this.startGraceTimer(msg.sessionId, 0);
7156
+ this.startGraceTimer(msg.sessionId, this.ptyGracePeriodMs);
7119
7157
  }
7120
7158
  } catch {
7121
7159
  }
@@ -8630,13 +8668,23 @@ var StreamerServer = class {
8630
8668
  throw err;
8631
8669
  }
8632
8670
  }
8633
- handleGetSession(sessionId, res) {
8671
+ async handleGetSession(sessionId, res) {
8634
8672
  if (this.rejectIfWarmingUp(res)) return;
8635
8673
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
8636
8674
  if (session) {
8637
8675
  if (!existsSync10(session.projectPath)) {
8638
8676
  session.failureReason = `Project directory not found: ${session.projectPath}`;
8639
8677
  }
8678
+ if (this.ptyManager.hasSession(sessionId)) {
8679
+ try {
8680
+ const lines = await this.ptyManager.getOutputLines(sessionId, 10);
8681
+ const status = parseStatusLine(lines);
8682
+ if (session.model == null && status.model) session.model = status.model;
8683
+ if (status.effort) session.effort = status.effort;
8684
+ if (status.permissionMode) session.permissionMode = status.permissionMode;
8685
+ } catch {
8686
+ }
8687
+ }
8640
8688
  json(res, 200, session);
8641
8689
  return;
8642
8690
  }