@threadbase-sh/streamer 1.44.4 → 1.45.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.
- package/dist/cli.cjs +80 -15
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +78 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +78 -13
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1775,8 +1775,11 @@ declare class PTYManager implements SessionRunner {
|
|
|
1775
1775
|
private onLiveQuestionGone;
|
|
1776
1776
|
private onUserMessage;
|
|
1777
1777
|
private permissionOpen;
|
|
1778
|
+
private oscTail;
|
|
1779
|
+
private lastDetectAt;
|
|
1778
1780
|
private lastScreenQuestionKey;
|
|
1779
1781
|
private shellPromptOpen;
|
|
1782
|
+
private closedGateKey;
|
|
1780
1783
|
private pendingReady;
|
|
1781
1784
|
private queuedInputs;
|
|
1782
1785
|
private log;
|
package/dist/index.d.ts
CHANGED
|
@@ -1775,8 +1775,11 @@ declare class PTYManager implements SessionRunner {
|
|
|
1775
1775
|
private onLiveQuestionGone;
|
|
1776
1776
|
private onUserMessage;
|
|
1777
1777
|
private permissionOpen;
|
|
1778
|
+
private oscTail;
|
|
1779
|
+
private lastDetectAt;
|
|
1778
1780
|
private lastScreenQuestionKey;
|
|
1779
1781
|
private shellPromptOpen;
|
|
1782
|
+
private closedGateKey;
|
|
1780
1783
|
private pendingReady;
|
|
1781
1784
|
private queuedInputs;
|
|
1782
1785
|
private log;
|
package/dist/index.js
CHANGED
|
@@ -2120,14 +2120,19 @@ function scrapePermissionGate(lines) {
|
|
|
2120
2120
|
const options = [];
|
|
2121
2121
|
let cursor;
|
|
2122
2122
|
let firstOptionLine = -1;
|
|
2123
|
-
for (let i =
|
|
2124
|
-
const
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2123
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
2124
|
+
const stripped = stripGutter(lines[i]);
|
|
2125
|
+
const m = OPTION_RE.exec(stripped);
|
|
2126
|
+
if (m) {
|
|
2127
|
+
const index = Number.parseInt(m[2], 10);
|
|
2128
|
+
if (!Number.isFinite(index)) continue;
|
|
2129
|
+
firstOptionLine = i;
|
|
2130
|
+
if (m[1]) cursor = index;
|
|
2131
|
+
options.unshift({ index, label: m[3] });
|
|
2132
|
+
continue;
|
|
2133
|
+
}
|
|
2134
|
+
if (options.length === 0) continue;
|
|
2135
|
+
if (stripped.trim().length === 0 || BOX_ONLY_RE.test(lines[i].trim())) break;
|
|
2131
2136
|
}
|
|
2132
2137
|
if (options.length === 0) return null;
|
|
2133
2138
|
let prompt;
|
|
@@ -2167,6 +2172,17 @@ function scrapeDetail(lines, promptLine) {
|
|
|
2167
2172
|
}
|
|
2168
2173
|
return collected.length > 0 ? collected.reverse().join("\n") : void 0;
|
|
2169
2174
|
}
|
|
2175
|
+
var GATE_FOOTER_RE = /esc to cancel/i;
|
|
2176
|
+
var ASK_MENU_FOOTER_RE = /Enter to select/i;
|
|
2177
|
+
var YES_NO_LABEL_RE = /^(yes|no)\b/i;
|
|
2178
|
+
function detectGateScreen(lines) {
|
|
2179
|
+
if (lines.some((l) => ASK_MENU_FOOTER_RE.test(l))) return null;
|
|
2180
|
+
if (!lines.some((l) => GATE_FOOTER_RE.test(l))) return null;
|
|
2181
|
+
const gate = scrapePermissionGate(lines);
|
|
2182
|
+
if (!gate || gate.options.length < 2) return null;
|
|
2183
|
+
if (!gate.options.some((o) => YES_NO_LABEL_RE.test(o.label))) return null;
|
|
2184
|
+
return gate;
|
|
2185
|
+
}
|
|
2170
2186
|
|
|
2171
2187
|
// src/services/questions/detectQuestionFromScreen.ts
|
|
2172
2188
|
var ASK_FOOTER_RE = /Enter to select/i;
|
|
@@ -2314,6 +2330,8 @@ var PTY_ROWS2 = 40;
|
|
|
2314
2330
|
var SCREEN_SCROLLBACK2 = 1e3;
|
|
2315
2331
|
var CLAUDE_PROMPT_MARKERS = ["\u256D", "\u276F"];
|
|
2316
2332
|
var QUIET_DETECT_MS2 = 500;
|
|
2333
|
+
var OSC_TAIL_CHARS = 128;
|
|
2334
|
+
var SCRAPE_THROTTLE_MS = 300;
|
|
2317
2335
|
var CLAUDE_READY_FALLBACK_MS = 8e3;
|
|
2318
2336
|
function buildPasteBytes(input) {
|
|
2319
2337
|
return `\x1B[200~${input}\x1B[201~`;
|
|
@@ -2372,6 +2390,12 @@ var PTYManager = class {
|
|
|
2372
2390
|
// the next prompt-ready without a fresh 777 (gate closed). Prevents
|
|
2373
2391
|
// re-broadcasting open/close on every chunk.
|
|
2374
2392
|
permissionOpen = /* @__PURE__ */ new Set();
|
|
2393
|
+
// Last chunk's raw tail per session — prepended to the next chunk before
|
|
2394
|
+
// the OSC regex test so a split escape still matches. Consumed on match.
|
|
2395
|
+
oscTail = /* @__PURE__ */ new Map();
|
|
2396
|
+
// When the last full detection pass ran per session (any trigger) — the
|
|
2397
|
+
// clock the SCRAPE_THROTTLE_MS ceiling is measured against.
|
|
2398
|
+
lastDetectAt = /* @__PURE__ */ new Map();
|
|
2375
2399
|
// Content key of the last AskUserQuestion broadcast from the rendered screen,
|
|
2376
2400
|
// per session — de-dupes the same menu firing on consecutive repaints.
|
|
2377
2401
|
lastScreenQuestionKey = /* @__PURE__ */ new Map();
|
|
@@ -2380,6 +2404,13 @@ var PTYManager = class {
|
|
|
2380
2404
|
// on a prompt-ready/marker return and de-dupe consecutive repaints. Modelled
|
|
2381
2405
|
// on permissionOpen but keyed by content (a shell prompt has no OSC trigger).
|
|
2382
2406
|
shellPromptOpen = /* @__PURE__ */ new Map();
|
|
2407
|
+
// Content key (permissionContentKey, cursor excluded — see arm 3) of the
|
|
2408
|
+
// gate that was still painted on screen when arm 2 closed it. Suppresses
|
|
2409
|
+
// arm 3 re-claiming that same box from a later trigger-less/throttled pass
|
|
2410
|
+
// before Claude erases it — otherwise the paint-time claim reopens the
|
|
2411
|
+
// card it just closed. Cleared once detectGateScreen sees the box is gone,
|
|
2412
|
+
// so a genuinely new (even content-identical) gate is claimed normally.
|
|
2413
|
+
closedGateKey = /* @__PURE__ */ new Map();
|
|
2383
2414
|
// Tracks sessions (both fresh and resume) whose PTY has spawned but Claude
|
|
2384
2415
|
// hasn't yet reached an interactive prompt — i.e. onReady hasn't fired.
|
|
2385
2416
|
pendingReady = /* @__PURE__ */ new Set();
|
|
@@ -2733,8 +2764,11 @@ var PTYManager = class {
|
|
|
2733
2764
|
this.queuedInputs.delete(sessionId);
|
|
2734
2765
|
this.firstChunkAt.delete(sessionId);
|
|
2735
2766
|
this.permissionOpen.delete(sessionId);
|
|
2767
|
+
this.oscTail.delete(sessionId);
|
|
2768
|
+
this.lastDetectAt.delete(sessionId);
|
|
2736
2769
|
this.lastScreenQuestionKey.delete(sessionId);
|
|
2737
2770
|
this.shellPromptOpen.delete(sessionId);
|
|
2771
|
+
this.closedGateKey.delete(sessionId);
|
|
2738
2772
|
this.quietCheckers.get(sessionId)?.cancel();
|
|
2739
2773
|
this.quietCheckers.delete(sessionId);
|
|
2740
2774
|
this.clearReadyFallback(sessionId);
|
|
@@ -2829,8 +2863,11 @@ var PTYManager = class {
|
|
|
2829
2863
|
for (const timer of this.readyFallbackTimers.values()) clearTimeout(timer);
|
|
2830
2864
|
this.readyFallbackTimers.clear();
|
|
2831
2865
|
this.permissionOpen.clear();
|
|
2866
|
+
this.oscTail.clear();
|
|
2867
|
+
this.lastDetectAt.clear();
|
|
2832
2868
|
this.lastScreenQuestionKey.clear();
|
|
2833
2869
|
this.shellPromptOpen.clear();
|
|
2870
|
+
this.closedGateKey.clear();
|
|
2834
2871
|
}
|
|
2835
2872
|
handleOutput(sessionId, data) {
|
|
2836
2873
|
const session = this.sessions.get(sessionId);
|
|
@@ -2894,16 +2931,24 @@ var PTYManager = class {
|
|
|
2894
2931
|
async detectLivePrompts(sessionId, rawData, stripped) {
|
|
2895
2932
|
const session = this.sessions.get(sessionId);
|
|
2896
2933
|
if (!session) return;
|
|
2897
|
-
const
|
|
2898
|
-
const
|
|
2934
|
+
const oscWindow = (this.oscTail.get(sessionId) ?? "") + rawData;
|
|
2935
|
+
const oscPermission = hasPermissionOsc(oscWindow);
|
|
2936
|
+
const oscWaitingForInput = hasWaitingForInputOsc(oscWindow);
|
|
2937
|
+
if (rawData !== "") {
|
|
2938
|
+
if (oscPermission || oscWaitingForInput) this.oscTail.delete(sessionId);
|
|
2939
|
+
else this.oscTail.set(sessionId, oscWindow.slice(-OSC_TAIL_CHARS));
|
|
2940
|
+
}
|
|
2899
2941
|
const hasAskFooter = /Enter to select/i.test(stripped);
|
|
2900
2942
|
const hasPromptMarker = CLAUDE_PROMPT_MARKERS.some((m) => stripped.includes(m));
|
|
2901
2943
|
const hasShellPromptHint = /[[(]\s*y\s*\/\s*n\s*[\])]|press\s+(enter|return|any key)|\bcontinue\b\s*\?|^\s*(?:❯|>)?\s*\d+[.)]\s+\S/im.test(
|
|
2902
2944
|
stripped
|
|
2903
2945
|
);
|
|
2904
|
-
|
|
2946
|
+
const nowMs = Date.now();
|
|
2947
|
+
const scrapeDue = nowMs - (this.lastDetectAt.get(sessionId) ?? 0) >= SCRAPE_THROTTLE_MS;
|
|
2948
|
+
if (!oscPermission && !oscWaitingForInput && !hasAskFooter && !hasShellPromptHint && !scrapeDue && !this.permissionOpen.has(sessionId) && !this.shellPromptOpen.has(sessionId) && !this.lastScreenQuestionKey.has(sessionId)) {
|
|
2905
2949
|
return;
|
|
2906
2950
|
}
|
|
2951
|
+
this.lastDetectAt.set(sessionId, nowMs);
|
|
2907
2952
|
const lines = await this.getOutputLines(sessionId, 60);
|
|
2908
2953
|
const askFooterOnScreen = lines.some((l) => /Enter to select/i.test(l));
|
|
2909
2954
|
if (oscPermission || hasAskFooter || askFooterOnScreen) {
|
|
@@ -2923,13 +2968,30 @@ var PTYManager = class {
|
|
|
2923
2968
|
this.permissionOpen.add(sessionId);
|
|
2924
2969
|
this.onPermissionChange?.(sessionId, gate ?? { options: [] });
|
|
2925
2970
|
} else if (this.permissionOpen.has(sessionId) && !askFooterOnScreen) {
|
|
2926
|
-
const gate =
|
|
2927
|
-
|
|
2971
|
+
const gate = detectGateScreen(lines);
|
|
2972
|
+
const stillPainted = gate !== null || scrapePermissionGate(lines) !== null;
|
|
2973
|
+
if (oscWaitingForInput || !stillPainted && hasPromptMarker) {
|
|
2928
2974
|
this.permissionOpen.delete(sessionId);
|
|
2929
2975
|
this.onPermissionChange?.(sessionId, null);
|
|
2976
|
+
if (gate) {
|
|
2977
|
+
this.closedGateKey.set(sessionId, permissionContentKey({ ...gate, cursor: void 0 }));
|
|
2978
|
+
} else {
|
|
2979
|
+
this.closedGateKey.delete(sessionId);
|
|
2980
|
+
}
|
|
2930
2981
|
} else if (gate) {
|
|
2931
2982
|
this.onPermissionChange?.(sessionId, gate);
|
|
2932
2983
|
}
|
|
2984
|
+
} else if (!askFooterOnScreen && !oscWaitingForInput) {
|
|
2985
|
+
const gate = detectGateScreen(lines);
|
|
2986
|
+
if (gate) {
|
|
2987
|
+
const key = permissionContentKey({ ...gate, cursor: void 0 });
|
|
2988
|
+
if (this.closedGateKey.get(sessionId) !== key) {
|
|
2989
|
+
this.permissionOpen.add(sessionId);
|
|
2990
|
+
this.onPermissionChange?.(sessionId, gate);
|
|
2991
|
+
}
|
|
2992
|
+
} else {
|
|
2993
|
+
this.closedGateKey.delete(sessionId);
|
|
2994
|
+
}
|
|
2933
2995
|
}
|
|
2934
2996
|
if (askFooterOnScreen) {
|
|
2935
2997
|
const detected = detectQuestionFromScreen(lines);
|
|
@@ -3072,8 +3134,11 @@ var PTYManager = class {
|
|
|
3072
3134
|
this.queuedInputs.delete(sessionId);
|
|
3073
3135
|
this.firstChunkAt.delete(sessionId);
|
|
3074
3136
|
this.permissionOpen.delete(sessionId);
|
|
3137
|
+
this.oscTail.delete(sessionId);
|
|
3138
|
+
this.lastDetectAt.delete(sessionId);
|
|
3075
3139
|
this.lastScreenQuestionKey.delete(sessionId);
|
|
3076
3140
|
this.shellPromptOpen.delete(sessionId);
|
|
3141
|
+
this.closedGateKey.delete(sessionId);
|
|
3077
3142
|
this.quietCheckers.get(sessionId)?.cancel();
|
|
3078
3143
|
this.quietCheckers.delete(sessionId);
|
|
3079
3144
|
this.clearReadyFallback(sessionId);
|