@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.cjs CHANGED
@@ -1449,9 +1449,13 @@ var import_fs6 = require("fs");
1449
1449
  var import_path6 = require("path");
1450
1450
 
1451
1451
  // src/services/questions/detectPermissionGate.ts
1452
- var OSC_777_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*/;
1452
+ var OSC_777_PERMISSION_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*needs your permission/;
1453
+ var OSC_777_WAITING_RE = /\x1b\]777;notify;Claude Code;[^\x07\x1b]*waiting for your input/;
1453
1454
  function hasPermissionOsc(rawData) {
1454
- return OSC_777_RE.test(rawData);
1455
+ return OSC_777_PERMISSION_RE.test(rawData);
1456
+ }
1457
+ function hasWaitingForInputOsc(rawData) {
1458
+ return OSC_777_WAITING_RE.test(rawData);
1455
1459
  }
1456
1460
  var OPTION_RE = /^\s*(❯)?\s*(\d+)\.\s+(.+?)\s*$/;
1457
1461
  var FOOTER_RE = /Enter to select|Esc to cancel|↑|↓|to navigate|to cancel/i;
@@ -1602,22 +1606,29 @@ function detectShellPrompt(lines) {
1602
1606
  };
1603
1607
  }
1604
1608
  const lastNumberedIdx = (() => {
1605
- for (let i = last.idx; i >= 0; i--) {
1606
- if (NUMBERED_RE.test(lines[i])) return i;
1609
+ let i = last.idx;
1610
+ if (!NUMBERED_RE.test(lines[i])) {
1611
+ if (i > 0 && (PRESS_ENTER_RE.test(lines[i].trim()) || CONTINUE_RE.test(lines[i].trim()))) {
1612
+ i--;
1613
+ } else {
1614
+ return -1;
1615
+ }
1607
1616
  }
1608
- return -1;
1617
+ while (i >= 0 && !NUMBERED_RE.test(lines[i]) && lines[i].trim().length === 0) i--;
1618
+ return i >= 0 && NUMBERED_RE.test(lines[i]) ? i : -1;
1609
1619
  })();
1610
1620
  if (lastNumberedIdx >= 0) {
1611
1621
  const options = [];
1612
- for (let i = 0; i <= lastNumberedIdx; i++) {
1622
+ let firstRow = lastNumberedIdx;
1623
+ for (let i = lastNumberedIdx; i >= 0; i--) {
1613
1624
  const m = NUMBERED_RE.exec(lines[i]);
1614
- if (!m) continue;
1625
+ if (!m) break;
1615
1626
  const num = Number.parseInt(m[1], 10);
1616
- if (!Number.isFinite(num)) continue;
1617
- options.push({ index: num, label: m[2].trim(), answerKeys: `${num}${ENTER}` });
1627
+ if (!Number.isFinite(num)) break;
1628
+ options.unshift({ index: num, label: m[2].trim(), answerKeys: `${num}${ENTER}` });
1629
+ firstRow = i;
1618
1630
  }
1619
1631
  if (options.length >= 2) {
1620
- const firstRow = lines.findIndex((l) => NUMBERED_RE.test(l));
1621
1632
  let prompt = "";
1622
1633
  for (let i = firstRow - 1; i >= 0; i--) {
1623
1634
  const t = lines[i].trim();
@@ -2186,12 +2197,13 @@ var PTYManager = class {
2186
2197
  const session = this.sessions.get(sessionId);
2187
2198
  if (!session) return;
2188
2199
  const oscPermission = hasPermissionOsc(rawData);
2200
+ const oscWaitingForInput = hasWaitingForInputOsc(rawData);
2189
2201
  const hasAskFooter = /Enter to select/i.test(stripped);
2190
2202
  const hasPromptMarker = CLAUDE_PROMPT_MARKERS.some((m) => stripped.includes(m));
2191
2203
  const hasShellPromptHint = /[[(]\s*y\s*\/\s*n\s*[\])]|press\s+(enter|return|any key)|\bcontinue\b\s*\?|^\s*(?:❯|>)?\s*\d+[.)]\s+\S/im.test(
2192
2204
  stripped
2193
2205
  );
2194
- if (!oscPermission && !hasAskFooter && !hasShellPromptHint && !this.permissionOpen.has(sessionId) && !this.shellPromptOpen.has(sessionId) && !this.lastScreenQuestionKey.has(sessionId)) {
2206
+ if (!oscPermission && !oscWaitingForInput && !hasAskFooter && !hasShellPromptHint && !this.permissionOpen.has(sessionId) && !this.shellPromptOpen.has(sessionId) && !this.lastScreenQuestionKey.has(sessionId)) {
2195
2207
  return;
2196
2208
  }
2197
2209
  const lines = await this.getOutputLines(sessionId, 60);
@@ -2214,11 +2226,11 @@ var PTYManager = class {
2214
2226
  this.onPermissionChange?.(sessionId, gate ?? { options: [] });
2215
2227
  } else if (this.permissionOpen.has(sessionId) && !askFooterOnScreen) {
2216
2228
  const gate = scrapePermissionGate(lines);
2217
- if (gate) {
2218
- this.onPermissionChange?.(sessionId, gate);
2219
- } else if (hasPromptMarker) {
2229
+ if (oscWaitingForInput || !gate && hasPromptMarker) {
2220
2230
  this.permissionOpen.delete(sessionId);
2221
2231
  this.onPermissionChange?.(sessionId, null);
2232
+ } else if (gate) {
2233
+ this.onPermissionChange?.(sessionId, gate);
2222
2234
  }
2223
2235
  }
2224
2236
  if (askFooterOnScreen) {
@@ -3630,8 +3642,8 @@ var createSessionRoutes = (deps) => {
3630
3642
  await deps.handleStopSession(c.req.param("id"), c.env.outgoing);
3631
3643
  return alreadyHandled6();
3632
3644
  });
3633
- app.get("/:id", (c) => {
3634
- deps.handleGetSession(c.req.param("id"), c.env.outgoing);
3645
+ app.get("/:id", async (c) => {
3646
+ await deps.handleGetSession(c.req.param("id"), c.env.outgoing);
3635
3647
  return alreadyHandled6();
3636
3648
  });
3637
3649
  return app;
@@ -5995,6 +6007,32 @@ function deriveProjectChatTitle(input) {
5995
6007
  return `Untitled \xB7 ${input.id.slice(0, 8)}`;
5996
6008
  }
5997
6009
 
6010
+ // src/services/questions/parseStatusLine.ts
6011
+ var MODEL_RE = /(Opus|Sonnet|Haiku|Fable)\s+[\d.]+(?:\s*\([^)]*\))?/;
6012
+ var EFFORT_RE = /●\s*([A-Za-z]+)\s*·\s*\/effort/;
6013
+ var PERMISSION_MODE_RE = /⏵⏵\s*([^(·\n]+?)\s*(?:\(|·|$)/;
6014
+ function parseStatusLine(lines) {
6015
+ const info = {};
6016
+ for (let i = lines.length - 1; i >= 0; i--) {
6017
+ const line = lines[i];
6018
+ if (!line) continue;
6019
+ if (info.effort === void 0) {
6020
+ const m = EFFORT_RE.exec(line);
6021
+ if (m) info.effort = m[1];
6022
+ }
6023
+ if (info.permissionMode === void 0) {
6024
+ const m = PERMISSION_MODE_RE.exec(line);
6025
+ if (m) info.permissionMode = m[1].trim();
6026
+ }
6027
+ if (info.model === void 0) {
6028
+ const m = MODEL_RE.exec(line);
6029
+ if (m) info.model = m[0].replace(/\s+/g, " ").trim();
6030
+ }
6031
+ if (info.model && info.effort && info.permissionMode) break;
6032
+ }
6033
+ return info;
6034
+ }
6035
+
5998
6036
  // src/services/questions/detectAskUserQuestion.ts
5999
6037
  function normalizeContent2(raw) {
6000
6038
  if (Array.isArray(raw)) return raw;
@@ -7151,7 +7189,7 @@ var StreamerServer = class {
7151
7189
  }
7152
7190
  }
7153
7191
  if (msg.type === "hold_session" && typeof msg.sessionId === "string") {
7154
- this.startGraceTimer(msg.sessionId, 0);
7192
+ this.startGraceTimer(msg.sessionId, this.ptyGracePeriodMs);
7155
7193
  }
7156
7194
  } catch {
7157
7195
  }
@@ -8666,13 +8704,23 @@ var StreamerServer = class {
8666
8704
  throw err;
8667
8705
  }
8668
8706
  }
8669
- handleGetSession(sessionId, res) {
8707
+ async handleGetSession(sessionId, res) {
8670
8708
  if (this.rejectIfWarmingUp(res)) return;
8671
8709
  const session = this.sessionStore.get(sessionId, this.ptyAttachedIds());
8672
8710
  if (session) {
8673
8711
  if (!(0, import_fs17.existsSync)(session.projectPath)) {
8674
8712
  session.failureReason = `Project directory not found: ${session.projectPath}`;
8675
8713
  }
8714
+ if (this.ptyManager.hasSession(sessionId)) {
8715
+ try {
8716
+ const lines = await this.ptyManager.getOutputLines(sessionId, 10);
8717
+ const status = parseStatusLine(lines);
8718
+ if (session.model == null && status.model) session.model = status.model;
8719
+ if (status.effort) session.effort = status.effort;
8720
+ if (status.permissionMode) session.permissionMode = status.permissionMode;
8721
+ } catch {
8722
+ }
8723
+ }
8676
8724
  json(res, 200, session);
8677
8725
  return;
8678
8726
  }