pty-manager 1.8.0 → 1.9.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.mts CHANGED
@@ -52,6 +52,17 @@ interface SpawnConfig {
52
52
  * are emitted as autoResponded=false instead of being auto-responded.
53
53
  * Auto-response rules (ruleOverrides) are unaffected. */
54
54
  skipAdapterAutoResponse?: boolean;
55
+ /**
56
+ * Whether to inherit the parent process environment variables.
57
+ * When `true` (default), `process.env` is spread as the base of the spawned
58
+ * process environment. When `false`, only `adapter.getEnv()` output and
59
+ * `config.env` are used — the caller is responsible for providing any
60
+ * necessary system vars (PATH, HOME, etc.) via `config.env`.
61
+ *
62
+ * Set to `false` for security-sensitive contexts where the host process has
63
+ * secrets that spawned agents should not access.
64
+ */
65
+ inheritProcessEnv?: boolean;
55
66
  }
56
67
  /**
57
68
  * Handle to a running session
@@ -188,6 +199,17 @@ interface StallClassification {
188
199
  /** Suggested response to send (for waiting_for_input with auto-respond) */
189
200
  suggestedResponse?: string;
190
201
  }
202
+ /**
203
+ * Information about an external tool/process running within a session.
204
+ * Emitted when the adapter detects a tool is actively executing (e.g. browser,
205
+ * bash command, Node process). Suppresses stall detection while active.
206
+ */
207
+ interface ToolRunningInfo {
208
+ /** Name of the tool (e.g. "Chrome", "bash", "node", "python") */
209
+ toolName: string;
210
+ /** Optional description of what the tool is doing */
211
+ description?: string;
212
+ }
191
213
  /**
192
214
  * Logger interface (bring your own logger)
193
215
  */
@@ -387,6 +409,17 @@ interface CLIAdapter {
387
409
  * "Reading N files", "Waiting for LLM", etc.
388
410
  */
389
411
  detectLoading?(output: string): boolean;
412
+ /**
413
+ * Optional: Detect if an external tool/process is currently running within
414
+ * the session (e.g. browser, bash command, Node server, Python script).
415
+ *
416
+ * When a tool is detected, stall detection is suppressed (the agent is
417
+ * working, just through an external process) and a `tool_running` event
418
+ * is emitted so the UI can display the active tool.
419
+ *
420
+ * Return null when no tool is detected.
421
+ */
422
+ detectToolRunning?(output: string): ToolRunningInfo | null;
390
423
  /**
391
424
  * Optional: Get health check command
392
425
  */
@@ -453,6 +486,7 @@ interface PTYSessionEvents {
453
486
  stall_detected: (recentOutput: string, stallDurationMs: number) => void;
454
487
  status_changed: (status: SessionStatus) => void;
455
488
  task_complete: () => void;
489
+ tool_running: (info: ToolRunningInfo) => void;
456
490
  }
457
491
  /**
458
492
  * Special key mappings to escape sequences
@@ -490,6 +524,7 @@ declare class PTYSession extends EventEmitter {
490
524
  private static readonly TASK_COMPLETE_DEBOUNCE_MS;
491
525
  private _readySettleTimer;
492
526
  private _readySettlePending;
527
+ private _lastToolRunningName;
493
528
  private _processScheduled;
494
529
  private static readonly MAX_OUTPUT_BUFFER;
495
530
  readonly id: string;
@@ -669,6 +704,12 @@ declare class PTYSession extends EventEmitter {
669
704
  * @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
670
705
  */
671
706
  sendKeys(keys: string | string[]): void;
707
+ /**
708
+ * Build the environment object for spawning a PTY process.
709
+ * Merges base env (process.env unless opted out), adapter env, and config env,
710
+ * with TERM/COLORTERM always forced.
711
+ */
712
+ static buildSpawnEnv(config: SpawnConfig, adapterEnv: Record<string, string>): Record<string, string>;
672
713
  /**
673
714
  * Normalize a list of key names for SPECIAL_KEYS lookup.
674
715
  *
@@ -737,6 +778,7 @@ interface PTYManagerEvents {
737
778
  stall_detected: (session: SessionHandle, recentOutput: string, stallDurationMs: number) => void;
738
779
  session_status_changed: (session: SessionHandle) => void;
739
780
  task_complete: (session: SessionHandle) => void;
781
+ tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;
740
782
  }
741
783
  declare class PTYManager extends EventEmitter {
742
784
  private sessions;
@@ -1199,4 +1241,4 @@ declare function isBun(): boolean;
1199
1241
  */
1200
1242
  declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
1201
1243
 
1202
- 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 };
1244
+ 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
@@ -52,6 +52,17 @@ interface SpawnConfig {
52
52
  * are emitted as autoResponded=false instead of being auto-responded.
53
53
  * Auto-response rules (ruleOverrides) are unaffected. */
54
54
  skipAdapterAutoResponse?: boolean;
55
+ /**
56
+ * Whether to inherit the parent process environment variables.
57
+ * When `true` (default), `process.env` is spread as the base of the spawned
58
+ * process environment. When `false`, only `adapter.getEnv()` output and
59
+ * `config.env` are used — the caller is responsible for providing any
60
+ * necessary system vars (PATH, HOME, etc.) via `config.env`.
61
+ *
62
+ * Set to `false` for security-sensitive contexts where the host process has
63
+ * secrets that spawned agents should not access.
64
+ */
65
+ inheritProcessEnv?: boolean;
55
66
  }
56
67
  /**
57
68
  * Handle to a running session
@@ -188,6 +199,17 @@ interface StallClassification {
188
199
  /** Suggested response to send (for waiting_for_input with auto-respond) */
189
200
  suggestedResponse?: string;
190
201
  }
202
+ /**
203
+ * Information about an external tool/process running within a session.
204
+ * Emitted when the adapter detects a tool is actively executing (e.g. browser,
205
+ * bash command, Node process). Suppresses stall detection while active.
206
+ */
207
+ interface ToolRunningInfo {
208
+ /** Name of the tool (e.g. "Chrome", "bash", "node", "python") */
209
+ toolName: string;
210
+ /** Optional description of what the tool is doing */
211
+ description?: string;
212
+ }
191
213
  /**
192
214
  * Logger interface (bring your own logger)
193
215
  */
@@ -387,6 +409,17 @@ interface CLIAdapter {
387
409
  * "Reading N files", "Waiting for LLM", etc.
388
410
  */
389
411
  detectLoading?(output: string): boolean;
412
+ /**
413
+ * Optional: Detect if an external tool/process is currently running within
414
+ * the session (e.g. browser, bash command, Node server, Python script).
415
+ *
416
+ * When a tool is detected, stall detection is suppressed (the agent is
417
+ * working, just through an external process) and a `tool_running` event
418
+ * is emitted so the UI can display the active tool.
419
+ *
420
+ * Return null when no tool is detected.
421
+ */
422
+ detectToolRunning?(output: string): ToolRunningInfo | null;
390
423
  /**
391
424
  * Optional: Get health check command
392
425
  */
@@ -453,6 +486,7 @@ interface PTYSessionEvents {
453
486
  stall_detected: (recentOutput: string, stallDurationMs: number) => void;
454
487
  status_changed: (status: SessionStatus) => void;
455
488
  task_complete: () => void;
489
+ tool_running: (info: ToolRunningInfo) => void;
456
490
  }
457
491
  /**
458
492
  * Special key mappings to escape sequences
@@ -490,6 +524,7 @@ declare class PTYSession extends EventEmitter {
490
524
  private static readonly TASK_COMPLETE_DEBOUNCE_MS;
491
525
  private _readySettleTimer;
492
526
  private _readySettlePending;
527
+ private _lastToolRunningName;
493
528
  private _processScheduled;
494
529
  private static readonly MAX_OUTPUT_BUFFER;
495
530
  readonly id: string;
@@ -669,6 +704,12 @@ declare class PTYSession extends EventEmitter {
669
704
  * @param keys - Key name(s) to send, e.g. "ctrl+c" or ["up", "up", "enter"]
670
705
  */
671
706
  sendKeys(keys: string | string[]): void;
707
+ /**
708
+ * Build the environment object for spawning a PTY process.
709
+ * Merges base env (process.env unless opted out), adapter env, and config env,
710
+ * with TERM/COLORTERM always forced.
711
+ */
712
+ static buildSpawnEnv(config: SpawnConfig, adapterEnv: Record<string, string>): Record<string, string>;
672
713
  /**
673
714
  * Normalize a list of key names for SPECIAL_KEYS lookup.
674
715
  *
@@ -737,6 +778,7 @@ interface PTYManagerEvents {
737
778
  stall_detected: (session: SessionHandle, recentOutput: string, stallDurationMs: number) => void;
738
779
  session_status_changed: (session: SessionHandle) => void;
739
780
  task_complete: (session: SessionHandle) => void;
781
+ tool_running: (session: SessionHandle, info: ToolRunningInfo) => void;
740
782
  }
741
783
  declare class PTYManager extends EventEmitter {
742
784
  private sessions;
@@ -1199,4 +1241,4 @@ declare function isBun(): boolean;
1199
1241
  */
1200
1242
  declare function createPTYManager(options?: BunPTYManagerOptions): BunCompatiblePTYManager;
1201
1243
 
1202
- 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 };
1244
+ 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) {
@@ -882,14 +900,7 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
882
900
  const command = this.adapter.getCommand();
883
901
  const args = this.adapter.getArgs(this.config);
884
902
  const adapterEnv = this.adapter.getEnv(this.config);
885
- const env = {
886
- ...process.env,
887
- ...adapterEnv,
888
- ...this.config.env,
889
- // Force terminal settings
890
- TERM: "xterm-256color",
891
- COLORTERM: "truecolor"
892
- };
903
+ const env = _PTYSession.buildSpawnEnv(this.config, adapterEnv);
893
904
  this.logger.info(
894
905
  { sessionId: this.id, command, args: args.join(" ") },
895
906
  "Starting PTY session"
@@ -967,6 +978,17 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
967
978
  this.scheduleReadySettle();
968
979
  return;
969
980
  }
981
+ if (this._status === "busy") {
982
+ const toolInfo = this.adapter.detectToolRunning?.(this.outputBuffer);
983
+ if (toolInfo) {
984
+ if (toolInfo.toolName !== this._lastToolRunningName) {
985
+ this._lastToolRunningName = toolInfo.toolName;
986
+ this.emit("tool_running", toolInfo);
987
+ }
988
+ } else if (this._lastToolRunningName) {
989
+ this._lastToolRunningName = null;
990
+ }
991
+ }
970
992
  if (this._status === "busy") {
971
993
  const signal = this.isTaskCompleteSignal(this.outputBuffer);
972
994
  if (this._taskCompletePending || signal) {
@@ -1260,6 +1282,21 @@ var PTYSession = class _PTYSession extends import_events.EventEmitter {
1260
1282
  }
1261
1283
  }
1262
1284
  }
1285
+ /**
1286
+ * Build the environment object for spawning a PTY process.
1287
+ * Merges base env (process.env unless opted out), adapter env, and config env,
1288
+ * with TERM/COLORTERM always forced.
1289
+ */
1290
+ static buildSpawnEnv(config, adapterEnv) {
1291
+ const baseEnv = config.inheritProcessEnv !== false ? process.env : {};
1292
+ return {
1293
+ ...baseEnv,
1294
+ ...adapterEnv,
1295
+ ...config.env,
1296
+ TERM: "xterm-256color",
1297
+ COLORTERM: "truecolor"
1298
+ };
1299
+ }
1263
1300
  /**
1264
1301
  * Normalize a list of key names for SPECIAL_KEYS lookup.
1265
1302
  *
@@ -1498,6 +1535,9 @@ var PTYManager = class extends import_events2.EventEmitter {
1498
1535
  session.on("task_complete", () => {
1499
1536
  this.emit("task_complete", session.toHandle());
1500
1537
  });
1538
+ session.on("tool_running", (info) => {
1539
+ this.emit("tool_running", session.toHandle(), info);
1540
+ });
1501
1541
  session.on("stall_detected", (recentOutput, stallDurationMs) => {
1502
1542
  const handle = session.toHandle();
1503
1543
  this.emit("stall_detected", handle, recentOutput, stallDurationMs);
@@ -2576,6 +2616,13 @@ var BunCompatiblePTYManager = class extends import_events3.EventEmitter {
2576
2616
  }
2577
2617
  break;
2578
2618
  }
2619
+ case "tool_running": {
2620
+ const session = this.sessions.get(id);
2621
+ if (session) {
2622
+ this.emit("tool_running", session, event.info);
2623
+ }
2624
+ break;
2625
+ }
2579
2626
  case "stall_detected": {
2580
2627
  const session = this.sessions.get(id);
2581
2628
  if (session) {