pty-manager 1.7.3 → 1.9.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/index.d.mts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +121 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +121 -13
- package/dist/index.mjs.map +1 -1
- package/dist/pty-worker.js +104 -7
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -188,6 +188,17 @@ interface StallClassification {
|
|
|
188
188
|
/** Suggested response to send (for waiting_for_input with auto-respond) */
|
|
189
189
|
suggestedResponse?: string;
|
|
190
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Information about an external tool/process running within a session.
|
|
193
|
+
* Emitted when the adapter detects a tool is actively executing (e.g. browser,
|
|
194
|
+
* bash command, Node process). Suppresses stall detection while active.
|
|
195
|
+
*/
|
|
196
|
+
interface ToolRunningInfo {
|
|
197
|
+
/** Name of the tool (e.g. "Chrome", "bash", "node", "python") */
|
|
198
|
+
toolName: string;
|
|
199
|
+
/** Optional description of what the tool is doing */
|
|
200
|
+
description?: string;
|
|
201
|
+
}
|
|
191
202
|
/**
|
|
192
203
|
* Logger interface (bring your own logger)
|
|
193
204
|
*/
|
|
@@ -387,6 +398,17 @@ interface CLIAdapter {
|
|
|
387
398
|
* "Reading N files", "Waiting for LLM", etc.
|
|
388
399
|
*/
|
|
389
400
|
detectLoading?(output: string): boolean;
|
|
401
|
+
/**
|
|
402
|
+
* Optional: Detect if an external tool/process is currently running within
|
|
403
|
+
* the session (e.g. browser, bash command, Node server, Python script).
|
|
404
|
+
*
|
|
405
|
+
* When a tool is detected, stall detection is suppressed (the agent is
|
|
406
|
+
* working, just through an external process) and a `tool_running` event
|
|
407
|
+
* is emitted so the UI can display the active tool.
|
|
408
|
+
*
|
|
409
|
+
* Return null when no tool is detected.
|
|
410
|
+
*/
|
|
411
|
+
detectToolRunning?(output: string): ToolRunningInfo | null;
|
|
390
412
|
/**
|
|
391
413
|
* Optional: Get health check command
|
|
392
414
|
*/
|
|
@@ -453,6 +475,7 @@ interface PTYSessionEvents {
|
|
|
453
475
|
stall_detected: (recentOutput: string, stallDurationMs: number) => void;
|
|
454
476
|
status_changed: (status: SessionStatus) => void;
|
|
455
477
|
task_complete: () => void;
|
|
478
|
+
tool_running: (info: ToolRunningInfo) => void;
|
|
456
479
|
}
|
|
457
480
|
/**
|
|
458
481
|
* Special key mappings to escape sequences
|
|
@@ -490,6 +513,7 @@ declare class PTYSession extends EventEmitter {
|
|
|
490
513
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
491
514
|
private _readySettleTimer;
|
|
492
515
|
private _readySettlePending;
|
|
516
|
+
private _lastToolRunningName;
|
|
493
517
|
private _processScheduled;
|
|
494
518
|
private static readonly MAX_OUTPUT_BUFFER;
|
|
495
519
|
readonly id: string;
|
|
@@ -669,6 +693,15 @@ declare class PTYSession extends EventEmitter {
|
|
|
669
693
|
* @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
|
|
670
694
|
*/
|
|
671
695
|
sendKeys(keys: string | string[]): void;
|
|
696
|
+
/**
|
|
697
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
698
|
+
*
|
|
699
|
+
* Handles two problems:
|
|
700
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
701
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
702
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
703
|
+
*/
|
|
704
|
+
static normalizeKeyList(keys: string[]): string[];
|
|
672
705
|
/**
|
|
673
706
|
* Select a TUI menu option by index (0-based).
|
|
674
707
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -728,6 +761,7 @@ interface PTYManagerEvents {
|
|
|
728
761
|
stall_detected: (session: SessionHandle, recentOutput: string, stallDurationMs: number) => void;
|
|
729
762
|
session_status_changed: (session: SessionHandle) => void;
|
|
730
763
|
task_complete: (session: SessionHandle) => void;
|
|
764
|
+
tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;
|
|
731
765
|
}
|
|
732
766
|
declare class PTYManager extends EventEmitter {
|
|
733
767
|
private sessions;
|
|
@@ -1002,6 +1036,11 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
1002
1036
|
detectLogin(_output: string): LoginDetection;
|
|
1003
1037
|
detectBlockingPrompt(_output: string): BlockingPromptDetection;
|
|
1004
1038
|
detectReady(output: string): boolean;
|
|
1039
|
+
/**
|
|
1040
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
1041
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
1042
|
+
*/
|
|
1043
|
+
private isContinuationPrompt;
|
|
1005
1044
|
detectExit(output: string): {
|
|
1006
1045
|
exited: boolean;
|
|
1007
1046
|
code?: number;
|
|
@@ -1185,4 +1224,4 @@ declare function isBun(): boolean;
|
|
|
1185
1224
|
*/
|
|
1186
1225
|
declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
|
|
1187
1226
|
|
|
1188
|
-
export { type AdapterFactoryConfig, AdapterRegistry, type AuthRequiredInfo, type AuthRequiredMethod, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, type BuildTimelineOptions, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StallClassification, type StopOptions, type TaskCompletionTimelineResult, type TaskCompletionTimelineStep, type TaskCompletionTraceRecord, type TaskCompletionTurnTimeline, type TerminalAttachment, type WorkerSessionHandle, buildTaskCompletionTimeline, createAdapter, createPTYManager, extractTaskCompletionTraceRecords, isBun };
|
|
1227
|
+
export { type AdapterFactoryConfig, AdapterRegistry, type AuthRequiredInfo, type AuthRequiredMethod, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, type BuildTimelineOptions, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StallClassification, type StopOptions, type TaskCompletionTimelineResult, type TaskCompletionTimelineStep, type TaskCompletionTraceRecord, type TaskCompletionTurnTimeline, type TerminalAttachment, type ToolRunningInfo, type WorkerSessionHandle, buildTaskCompletionTimeline, createAdapter, createPTYManager, extractTaskCompletionTraceRecords, isBun };
|
package/dist/index.d.ts
CHANGED
|
@@ -188,6 +188,17 @@ interface StallClassification {
|
|
|
188
188
|
/** Suggested response to send (for waiting_for_input with auto-respond) */
|
|
189
189
|
suggestedResponse?: string;
|
|
190
190
|
}
|
|
191
|
+
/**
|
|
192
|
+
* Information about an external tool/process running within a session.
|
|
193
|
+
* Emitted when the adapter detects a tool is actively executing (e.g. browser,
|
|
194
|
+
* bash command, Node process). Suppresses stall detection while active.
|
|
195
|
+
*/
|
|
196
|
+
interface ToolRunningInfo {
|
|
197
|
+
/** Name of the tool (e.g. "Chrome", "bash", "node", "python") */
|
|
198
|
+
toolName: string;
|
|
199
|
+
/** Optional description of what the tool is doing */
|
|
200
|
+
description?: string;
|
|
201
|
+
}
|
|
191
202
|
/**
|
|
192
203
|
* Logger interface (bring your own logger)
|
|
193
204
|
*/
|
|
@@ -387,6 +398,17 @@ interface CLIAdapter {
|
|
|
387
398
|
* "Reading N files", "Waiting for LLM", etc.
|
|
388
399
|
*/
|
|
389
400
|
detectLoading?(output: string): boolean;
|
|
401
|
+
/**
|
|
402
|
+
* Optional: Detect if an external tool/process is currently running within
|
|
403
|
+
* the session (e.g. browser, bash command, Node server, Python script).
|
|
404
|
+
*
|
|
405
|
+
* When a tool is detected, stall detection is suppressed (the agent is
|
|
406
|
+
* working, just through an external process) and a `tool_running` event
|
|
407
|
+
* is emitted so the UI can display the active tool.
|
|
408
|
+
*
|
|
409
|
+
* Return null when no tool is detected.
|
|
410
|
+
*/
|
|
411
|
+
detectToolRunning?(output: string): ToolRunningInfo | null;
|
|
390
412
|
/**
|
|
391
413
|
* Optional: Get health check command
|
|
392
414
|
*/
|
|
@@ -453,6 +475,7 @@ interface PTYSessionEvents {
|
|
|
453
475
|
stall_detected: (recentOutput: string, stallDurationMs: number) => void;
|
|
454
476
|
status_changed: (status: SessionStatus) => void;
|
|
455
477
|
task_complete: () => void;
|
|
478
|
+
tool_running: (info: ToolRunningInfo) => void;
|
|
456
479
|
}
|
|
457
480
|
/**
|
|
458
481
|
* Special key mappings to escape sequences
|
|
@@ -490,6 +513,7 @@ declare class PTYSession extends EventEmitter {
|
|
|
490
513
|
private static readonly TASK_COMPLETE_DEBOUNCE_MS;
|
|
491
514
|
private _readySettleTimer;
|
|
492
515
|
private _readySettlePending;
|
|
516
|
+
private _lastToolRunningName;
|
|
493
517
|
private _processScheduled;
|
|
494
518
|
private static readonly MAX_OUTPUT_BUFFER;
|
|
495
519
|
readonly id: string;
|
|
@@ -669,6 +693,15 @@ declare class PTYSession extends EventEmitter {
|
|
|
669
693
|
* @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
|
|
670
694
|
*/
|
|
671
695
|
sendKeys(keys: string | string[]): void;
|
|
696
|
+
/**
|
|
697
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
698
|
+
*
|
|
699
|
+
* Handles two problems:
|
|
700
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
701
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
702
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
703
|
+
*/
|
|
704
|
+
static normalizeKeyList(keys: string[]): string[];
|
|
672
705
|
/**
|
|
673
706
|
* Select a TUI menu option by index (0-based).
|
|
674
707
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -728,6 +761,7 @@ interface PTYManagerEvents {
|
|
|
728
761
|
stall_detected: (session: SessionHandle, recentOutput: string, stallDurationMs: number) => void;
|
|
729
762
|
session_status_changed: (session: SessionHandle) => void;
|
|
730
763
|
task_complete: (session: SessionHandle) => void;
|
|
764
|
+
tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;
|
|
731
765
|
}
|
|
732
766
|
declare class PTYManager extends EventEmitter {
|
|
733
767
|
private sessions;
|
|
@@ -1002,6 +1036,11 @@ declare class ShellAdapter implements CLIAdapter {
|
|
|
1002
1036
|
detectLogin(_output: string): LoginDetection;
|
|
1003
1037
|
detectBlockingPrompt(_output: string): BlockingPromptDetection;
|
|
1004
1038
|
detectReady(output: string): boolean;
|
|
1039
|
+
/**
|
|
1040
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
1041
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
1042
|
+
*/
|
|
1043
|
+
private isContinuationPrompt;
|
|
1005
1044
|
detectExit(output: string): {
|
|
1006
1045
|
exited: boolean;
|
|
1007
1046
|
code?: number;
|
|
@@ -1185,4 +1224,4 @@ declare function isBun(): boolean;
|
|
|
1185
1224
|
*/
|
|
1186
1225
|
declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
|
|
1187
1226
|
|
|
1188
|
-
export { type AdapterFactoryConfig, AdapterRegistry, type AuthRequiredInfo, type AuthRequiredMethod, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, type BuildTimelineOptions, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StallClassification, type StopOptions, type TaskCompletionTimelineResult, type TaskCompletionTimelineStep, type TaskCompletionTraceRecord, type TaskCompletionTurnTimeline, type TerminalAttachment, type WorkerSessionHandle, buildTaskCompletionTimeline, createAdapter, createPTYManager, extractTaskCompletionTraceRecords, isBun };
|
|
1227
|
+
export { type AdapterFactoryConfig, AdapterRegistry, type AuthRequiredInfo, type AuthRequiredMethod, type AutoResponseRule, BaseCLIAdapter, type BlockingPromptDetection, type BlockingPromptInfo, type BlockingPromptType, type BuildTimelineOptions, BunCompatiblePTYManager, type BunPTYManagerOptions, type CLIAdapter, type LogOptions, type Logger, type LoginDetection, type MessageType, PTYManager, type PTYManagerConfig, type PTYManagerEvents, PTYSession, type PTYSessionEvents, type ParsedOutput, SPECIAL_KEYS, type SessionFilter, type SessionHandle, type SessionMessage, type SessionStatus, ShellAdapter, type ShellAdapterOptions, type SpawnConfig, type StallClassification, type StopOptions, type TaskCompletionTimelineResult, type TaskCompletionTimelineStep, type TaskCompletionTraceRecord, type TaskCompletionTurnTimeline, type TerminalAttachment, type ToolRunningInfo, type WorkerSessionHandle, buildTaskCompletionTimeline, createAdapter, createPTYManager, extractTaskCompletionTraceRecords, isBun };
|
package/dist/index.js
CHANGED
|
@@ -364,6 +364,8 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
364
364
|
// Ready detection settle delay — defers session_ready until output goes quiet
|
|
365
365
|
_readySettleTimer = null;
|
|
366
366
|
_readySettlePending = false;
|
|
367
|
+
// Tool running deduplication — only emit when tool changes
|
|
368
|
+
_lastToolRunningName = null;
|
|
367
369
|
// Deferred output processing — prevents node-pty's synchronous data
|
|
368
370
|
// delivery from starving the event loop (timers, I/O callbacks, etc.)
|
|
369
371
|
_processScheduled = false;
|
|
@@ -529,6 +531,22 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
529
531
|
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
530
532
|
return;
|
|
531
533
|
}
|
|
534
|
+
const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);
|
|
535
|
+
if (toolInfo) {
|
|
536
|
+
if (toolInfo.toolName !== this._lastToolRunningName) {
|
|
537
|
+
this._lastToolRunningName = toolInfo.toolName;
|
|
538
|
+
this.emit("tool_running", toolInfo);
|
|
539
|
+
}
|
|
540
|
+
this.logger.debug(
|
|
541
|
+
{ sessionId: this.id, tool: toolInfo.toolName },
|
|
542
|
+
"Tool running \u2014 suppressing stall emission"
|
|
543
|
+
);
|
|
544
|
+
this._stallTimer = setTimeout(() => this.onStallTimerFired(), this._stallBackoffMs);
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
if (this._lastToolRunningName) {
|
|
548
|
+
this._lastToolRunningName = null;
|
|
549
|
+
}
|
|
532
550
|
const tail = this.outputBuffer.slice(-500);
|
|
533
551
|
const hash = this.simpleHash(tail);
|
|
534
552
|
if (hash === this._lastStallHash) {
|
|
@@ -967,6 +985,17 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
967
985
|
this.scheduleReadySettle();
|
|
968
986
|
return;
|
|
969
987
|
}
|
|
988
|
+
if (this._status === "busy") {
|
|
989
|
+
const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);
|
|
990
|
+
if (toolInfo) {
|
|
991
|
+
if (toolInfo.toolName !== this._lastToolRunningName) {
|
|
992
|
+
this._lastToolRunningName = toolInfo.toolName;
|
|
993
|
+
this.emit("tool_running", toolInfo);
|
|
994
|
+
}
|
|
995
|
+
} else if (this._lastToolRunningName) {
|
|
996
|
+
this._lastToolRunningName = null;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
970
999
|
if (this._status === "busy") {
|
|
971
1000
|
const signal = this.isTaskCompleteSignal(this.outputBuffer);
|
|
972
1001
|
if (this._taskCompletePending || signal) {
|
|
@@ -1242,24 +1271,71 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
|
|
|
1242
1271
|
throw new Error("Session not started");
|
|
1243
1272
|
}
|
|
1244
1273
|
const keyList = Array.isArray(keys) ? keys : [keys];
|
|
1274
|
+
const normalized = _PTYSession.normalizeKeyList(keyList);
|
|
1245
1275
|
this._stallEmissionCount = 0;
|
|
1246
1276
|
this.resetStallTimer();
|
|
1247
|
-
for (const key of
|
|
1248
|
-
const
|
|
1249
|
-
const sequence = SPECIAL_KEYS[normalizedKey];
|
|
1277
|
+
for (const key of normalized) {
|
|
1278
|
+
const sequence = SPECIAL_KEYS[key];
|
|
1250
1279
|
if (sequence) {
|
|
1251
1280
|
this._lastActivityAt = /* @__PURE__ */ new Date();
|
|
1252
1281
|
this.ptyProcess.write(sequence);
|
|
1253
|
-
this.logger.debug({ sessionId: this.id, key
|
|
1282
|
+
this.logger.debug({ sessionId: this.id, key }, "Sent special key");
|
|
1254
1283
|
} else {
|
|
1255
1284
|
this.logger.warn(
|
|
1256
|
-
{ sessionId: this.id, key
|
|
1285
|
+
{ sessionId: this.id, key },
|
|
1257
1286
|
"Unknown special key, sending as literal"
|
|
1258
1287
|
);
|
|
1259
1288
|
this.ptyProcess.write(key);
|
|
1260
1289
|
}
|
|
1261
1290
|
}
|
|
1262
1291
|
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Normalize a list of key names for SPECIAL_KEYS lookup.
|
|
1294
|
+
*
|
|
1295
|
+
* Handles two problems:
|
|
1296
|
+
* 1. Modifier aliases: "control" → "ctrl", "command" → "meta", "option" → "alt"
|
|
1297
|
+
* 2. Comma-separated compound keys from stall classifier: ["control", "c"] → ["ctrl+c"]
|
|
1298
|
+
* A bare modifier followed by a single char/key is joined with "+".
|
|
1299
|
+
*/
|
|
1300
|
+
static normalizeKeyList(keys) {
|
|
1301
|
+
const MODIFIER_MAP = {
|
|
1302
|
+
control: "ctrl",
|
|
1303
|
+
command: "meta",
|
|
1304
|
+
cmd: "meta",
|
|
1305
|
+
option: "alt",
|
|
1306
|
+
opt: "alt"
|
|
1307
|
+
};
|
|
1308
|
+
const MODIFIER_NAMES = /* @__PURE__ */ new Set([
|
|
1309
|
+
"ctrl",
|
|
1310
|
+
"alt",
|
|
1311
|
+
"shift",
|
|
1312
|
+
"meta",
|
|
1313
|
+
// Also match the aliases so we can detect them before remapping
|
|
1314
|
+
...Object.keys(MODIFIER_MAP)
|
|
1315
|
+
]);
|
|
1316
|
+
const result = [];
|
|
1317
|
+
let i = 0;
|
|
1318
|
+
while (i < keys.length) {
|
|
1319
|
+
let key = keys[i].toLowerCase().trim();
|
|
1320
|
+
if (MODIFIER_MAP[key]) {
|
|
1321
|
+
key = MODIFIER_MAP[key];
|
|
1322
|
+
}
|
|
1323
|
+
if (MODIFIER_NAMES.has(key) && i + 1 < keys.length) {
|
|
1324
|
+
let nextKey = keys[i + 1].toLowerCase().trim();
|
|
1325
|
+
if (MODIFIER_MAP[nextKey]) {
|
|
1326
|
+
nextKey = MODIFIER_MAP[nextKey];
|
|
1327
|
+
}
|
|
1328
|
+
if (!MODIFIER_NAMES.has(nextKey)) {
|
|
1329
|
+
result.push(`${key}+${nextKey}`);
|
|
1330
|
+
i += 2;
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
result.push(key);
|
|
1335
|
+
i++;
|
|
1336
|
+
}
|
|
1337
|
+
return result;
|
|
1338
|
+
}
|
|
1263
1339
|
/**
|
|
1264
1340
|
* Select a TUI menu option by index (0-based).
|
|
1265
1341
|
* Sends Down arrow `optionIndex` times, then Enter, with 50ms delays.
|
|
@@ -1451,6 +1527,9 @@ var PTYManager = class extends import_events2.EventEmitter {
|
|
|
1451
1527
|
session.on("task_complete", () => {
|
|
1452
1528
|
this.emit("task_complete", session.toHandle());
|
|
1453
1529
|
});
|
|
1530
|
+
session.on("tool_running", (info) => {
|
|
1531
|
+
this.emit("tool_running", session.toHandle(), info);
|
|
1532
|
+
});
|
|
1454
1533
|
session.on("stall_detected", (recentOutput, stallDurationMs) => {
|
|
1455
1534
|
const handle = session.toHandle();
|
|
1456
1535
|
this.emit("stall_detected", handle, recentOutput, stallDurationMs);
|
|
@@ -2261,7 +2340,18 @@ var ShellAdapter = class {
|
|
|
2261
2340
|
return { detected: false };
|
|
2262
2341
|
}
|
|
2263
2342
|
detectReady(output) {
|
|
2264
|
-
|
|
2343
|
+
if (this.isContinuationPrompt(output)) {
|
|
2344
|
+
return false;
|
|
2345
|
+
}
|
|
2346
|
+
return this.getPromptPattern().test(this.stripAnsi(output));
|
|
2347
|
+
}
|
|
2348
|
+
/**
|
|
2349
|
+
* Detect shell continuation prompts that indicate the shell is NOT ready
|
|
2350
|
+
* for a new command (e.g., unclosed quote, heredoc, backtick).
|
|
2351
|
+
*/
|
|
2352
|
+
isContinuationPrompt(output) {
|
|
2353
|
+
const stripped = this.stripAnsi(output);
|
|
2354
|
+
return /(?:quote|dquote|heredoc|bquote|cmdsubst|pipe|then|else|do|loop)>\s*$/.test(stripped) || /(?:quote|dquote|heredoc|bquote)>\s*$/m.test(stripped);
|
|
2265
2355
|
}
|
|
2266
2356
|
detectExit(output) {
|
|
2267
2357
|
if (output.includes("exit")) {
|
|
@@ -2284,7 +2374,7 @@ var ShellAdapter = class {
|
|
|
2284
2374
|
}
|
|
2285
2375
|
getPromptPattern() {
|
|
2286
2376
|
const escaped = this.promptStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2287
|
-
return new RegExp(`(?:${escaped}
|
|
2377
|
+
return new RegExp(`(?:${escaped}|\\$|#)\\s*$`, "m");
|
|
2288
2378
|
}
|
|
2289
2379
|
async validateInstallation() {
|
|
2290
2380
|
return { installed: true };
|
|
@@ -2380,9 +2470,6 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
|
2380
2470
|
const id = event.id;
|
|
2381
2471
|
switch (eventType) {
|
|
2382
2472
|
case "worker_ready":
|
|
2383
|
-
if (this.adapterModules.length > 0) {
|
|
2384
|
-
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2385
|
-
}
|
|
2386
2473
|
if (this._stallDetectionEnabled) {
|
|
2387
2474
|
this.sendCommand({
|
|
2388
2475
|
cmd: "configureStallDetection",
|
|
@@ -2390,9 +2477,23 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
|
2390
2477
|
timeoutMs: this._stallTimeoutMs
|
|
2391
2478
|
});
|
|
2392
2479
|
}
|
|
2393
|
-
this.
|
|
2394
|
-
|
|
2395
|
-
|
|
2480
|
+
if (this.adapterModules.length > 0) {
|
|
2481
|
+
this.sendCommand({ cmd: "registerAdapters", modules: this.adapterModules });
|
|
2482
|
+
this.createPending("registerAdapters").then(() => {
|
|
2483
|
+
this.ready = true;
|
|
2484
|
+
this.readyResolve();
|
|
2485
|
+
this.emit("ready");
|
|
2486
|
+
}).catch((err) => {
|
|
2487
|
+
this.emit("worker_error", `Failed to register adapters: ${err}`);
|
|
2488
|
+
this.ready = true;
|
|
2489
|
+
this.readyResolve();
|
|
2490
|
+
this.emit("ready");
|
|
2491
|
+
});
|
|
2492
|
+
} else {
|
|
2493
|
+
this.ready = true;
|
|
2494
|
+
this.readyResolve();
|
|
2495
|
+
this.emit("ready");
|
|
2496
|
+
}
|
|
2396
2497
|
break;
|
|
2397
2498
|
case "spawned": {
|
|
2398
2499
|
const session = {
|
|
@@ -2507,6 +2608,13 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
|
|
|
2507
2608
|
}
|
|
2508
2609
|
break;
|
|
2509
2610
|
}
|
|
2611
|
+
case "tool_running": {
|
|
2612
|
+
const session = this.sessions.get(id);
|
|
2613
|
+
if (session) {
|
|
2614
|
+
this.emit("tool_running", session, event.info);
|
|
2615
|
+
}
|
|
2616
|
+
break;
|
|
2617
|
+
}
|
|
2510
2618
|
case "stall_detected": {
|
|
2511
2619
|
const session = this.sessions.get(id);
|
|
2512
2620
|
if (session) {
|