@agent-relay/wrapper 0.1.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.
Files changed (115) hide show
  1. package/dist/__fixtures__/claude-outputs.d.ts +49 -0
  2. package/dist/__fixtures__/claude-outputs.d.ts.map +1 -0
  3. package/dist/__fixtures__/claude-outputs.js +443 -0
  4. package/dist/__fixtures__/claude-outputs.js.map +1 -0
  5. package/dist/__fixtures__/codex-outputs.d.ts +9 -0
  6. package/dist/__fixtures__/codex-outputs.d.ts.map +1 -0
  7. package/dist/__fixtures__/codex-outputs.js +94 -0
  8. package/dist/__fixtures__/codex-outputs.js.map +1 -0
  9. package/dist/__fixtures__/gemini-outputs.d.ts +19 -0
  10. package/dist/__fixtures__/gemini-outputs.d.ts.map +1 -0
  11. package/dist/__fixtures__/gemini-outputs.js +144 -0
  12. package/dist/__fixtures__/gemini-outputs.js.map +1 -0
  13. package/dist/__fixtures__/index.d.ts +68 -0
  14. package/dist/__fixtures__/index.d.ts.map +1 -0
  15. package/dist/__fixtures__/index.js +44 -0
  16. package/dist/__fixtures__/index.js.map +1 -0
  17. package/dist/auth-detection.d.ts +49 -0
  18. package/dist/auth-detection.d.ts.map +1 -0
  19. package/dist/auth-detection.js +199 -0
  20. package/dist/auth-detection.js.map +1 -0
  21. package/dist/base-wrapper.d.ts +225 -0
  22. package/dist/base-wrapper.d.ts.map +1 -0
  23. package/dist/base-wrapper.js +572 -0
  24. package/dist/base-wrapper.js.map +1 -0
  25. package/dist/client.d.ts +254 -0
  26. package/dist/client.d.ts.map +1 -0
  27. package/dist/client.js +801 -0
  28. package/dist/client.js.map +1 -0
  29. package/dist/id-generator.d.ts +35 -0
  30. package/dist/id-generator.d.ts.map +1 -0
  31. package/dist/id-generator.js +60 -0
  32. package/dist/id-generator.js.map +1 -0
  33. package/dist/idle-detector.d.ts +110 -0
  34. package/dist/idle-detector.d.ts.map +1 -0
  35. package/dist/idle-detector.js +304 -0
  36. package/dist/idle-detector.js.map +1 -0
  37. package/dist/inbox.d.ts +37 -0
  38. package/dist/inbox.d.ts.map +1 -0
  39. package/dist/inbox.js +73 -0
  40. package/dist/inbox.js.map +1 -0
  41. package/dist/index.d.ts +37 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +47 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/parser.d.ts +236 -0
  46. package/dist/parser.d.ts.map +1 -0
  47. package/dist/parser.js +1238 -0
  48. package/dist/parser.js.map +1 -0
  49. package/dist/prompt-composer.d.ts +67 -0
  50. package/dist/prompt-composer.d.ts.map +1 -0
  51. package/dist/prompt-composer.js +168 -0
  52. package/dist/prompt-composer.js.map +1 -0
  53. package/dist/relay-pty-orchestrator.d.ts +407 -0
  54. package/dist/relay-pty-orchestrator.d.ts.map +1 -0
  55. package/dist/relay-pty-orchestrator.js +1885 -0
  56. package/dist/relay-pty-orchestrator.js.map +1 -0
  57. package/dist/shared.d.ts +201 -0
  58. package/dist/shared.d.ts.map +1 -0
  59. package/dist/shared.js +341 -0
  60. package/dist/shared.js.map +1 -0
  61. package/dist/stuck-detector.d.ts +161 -0
  62. package/dist/stuck-detector.d.ts.map +1 -0
  63. package/dist/stuck-detector.js +402 -0
  64. package/dist/stuck-detector.js.map +1 -0
  65. package/dist/tmux-resolver.d.ts +55 -0
  66. package/dist/tmux-resolver.d.ts.map +1 -0
  67. package/dist/tmux-resolver.js +175 -0
  68. package/dist/tmux-resolver.js.map +1 -0
  69. package/dist/tmux-wrapper.d.ts +345 -0
  70. package/dist/tmux-wrapper.d.ts.map +1 -0
  71. package/dist/tmux-wrapper.js +1747 -0
  72. package/dist/tmux-wrapper.js.map +1 -0
  73. package/dist/trajectory-integration.d.ts +292 -0
  74. package/dist/trajectory-integration.d.ts.map +1 -0
  75. package/dist/trajectory-integration.js +979 -0
  76. package/dist/trajectory-integration.js.map +1 -0
  77. package/dist/wrapper-types.d.ts +41 -0
  78. package/dist/wrapper-types.d.ts.map +1 -0
  79. package/dist/wrapper-types.js +7 -0
  80. package/dist/wrapper-types.js.map +1 -0
  81. package/package.json +63 -0
  82. package/src/__fixtures__/claude-outputs.ts +471 -0
  83. package/src/__fixtures__/codex-outputs.ts +99 -0
  84. package/src/__fixtures__/gemini-outputs.ts +151 -0
  85. package/src/__fixtures__/index.ts +47 -0
  86. package/src/auth-detection.ts +244 -0
  87. package/src/base-wrapper.test.ts +540 -0
  88. package/src/base-wrapper.ts +741 -0
  89. package/src/client.test.ts +262 -0
  90. package/src/client.ts +984 -0
  91. package/src/id-generator.test.ts +71 -0
  92. package/src/id-generator.ts +69 -0
  93. package/src/idle-detector.test.ts +390 -0
  94. package/src/idle-detector.ts +370 -0
  95. package/src/inbox.test.ts +233 -0
  96. package/src/inbox.ts +89 -0
  97. package/src/index.ts +170 -0
  98. package/src/parser.regression.test.ts +251 -0
  99. package/src/parser.test.ts +1359 -0
  100. package/src/parser.ts +1477 -0
  101. package/src/prompt-composer.test.ts +219 -0
  102. package/src/prompt-composer.ts +231 -0
  103. package/src/relay-pty-orchestrator.test.ts +1027 -0
  104. package/src/relay-pty-orchestrator.ts +2270 -0
  105. package/src/shared.test.ts +221 -0
  106. package/src/shared.ts +454 -0
  107. package/src/stuck-detector.test.ts +303 -0
  108. package/src/stuck-detector.ts +511 -0
  109. package/src/tmux-resolver.test.ts +104 -0
  110. package/src/tmux-resolver.ts +207 -0
  111. package/src/tmux-wrapper.test.ts +316 -0
  112. package/src/tmux-wrapper.ts +2010 -0
  113. package/src/trajectory-detection.test.ts +151 -0
  114. package/src/trajectory-integration.ts +1261 -0
  115. package/src/wrapper-types.ts +45 -0
package/dist/shared.js ADDED
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Shared types and utilities for TmuxWrapper and PtyWrapper
3
+ *
4
+ * This module contains common code to prevent drift between the two
5
+ * wrapper implementations and reduce duplication.
6
+ */
7
+ /**
8
+ * Injection timing constants
9
+ *
10
+ * Performance tuning (2024-01):
11
+ * - QUEUE_PROCESS_DELAY_MS: 500ms → 100ms (5x faster message throughput)
12
+ * - STABILITY_POLL_MS: 200ms → 100ms (faster idle detection)
13
+ * - ENTER_DELAY_MS: 100ms → 50ms (faster message completion)
14
+ * - RETRY_BACKOFF_MS: 300ms → 200ms (faster recovery)
15
+ *
16
+ * Use AdaptiveThrottle class for dynamic backpressure handling.
17
+ */
18
+ export const INJECTION_CONSTANTS = {
19
+ /** Maximum retry attempts for injection */
20
+ MAX_RETRIES: 3,
21
+ /** Timeout for output stability check (ms) */
22
+ STABILITY_TIMEOUT_MS: 3000,
23
+ /** Polling interval for stability check (ms) - reduced from 200ms */
24
+ STABILITY_POLL_MS: 100,
25
+ /** Required consecutive stable polls before injection */
26
+ REQUIRED_STABLE_POLLS: 2,
27
+ /** Timeout for injection verification (ms) */
28
+ VERIFICATION_TIMEOUT_MS: 2000,
29
+ /** Delay between message and Enter key (ms) - reduced from 100ms */
30
+ ENTER_DELAY_MS: 50,
31
+ /** Backoff multiplier for retries (ms per attempt) - reduced from 300ms */
32
+ RETRY_BACKOFF_MS: 200,
33
+ /** Base delay between processing queued messages (ms) - reduced from 500ms */
34
+ QUEUE_PROCESS_DELAY_MS: 100,
35
+ /** Maximum delay when under backpressure (ms) */
36
+ QUEUE_PROCESS_DELAY_MAX_MS: 500,
37
+ /** Threshold for increasing delay (consecutive failures) */
38
+ BACKPRESSURE_THRESHOLD: 2,
39
+ };
40
+ /**
41
+ * Adaptive throttle for message queue processing.
42
+ * Increases delay when failures occur, decreases on success.
43
+ *
44
+ * This allows fast messaging under normal conditions (~100ms between messages)
45
+ * while automatically backing off when the system is under stress.
46
+ */
47
+ export class AdaptiveThrottle {
48
+ consecutiveFailures = 0;
49
+ currentDelay = INJECTION_CONSTANTS.QUEUE_PROCESS_DELAY_MS;
50
+ /** Get current delay in milliseconds */
51
+ getDelay() {
52
+ return this.currentDelay;
53
+ }
54
+ /** Record a successful injection - decrease delay */
55
+ recordSuccess() {
56
+ this.consecutiveFailures = 0;
57
+ // Gradually decrease delay on success (exponential decay toward minimum)
58
+ this.currentDelay = Math.max(INJECTION_CONSTANTS.QUEUE_PROCESS_DELAY_MS, Math.floor(this.currentDelay * 0.7));
59
+ }
60
+ /** Record a failed injection - increase delay if threshold exceeded */
61
+ recordFailure() {
62
+ this.consecutiveFailures++;
63
+ if (this.consecutiveFailures >= INJECTION_CONSTANTS.BACKPRESSURE_THRESHOLD) {
64
+ // Increase delay when under backpressure (exponential backoff)
65
+ this.currentDelay = Math.min(INJECTION_CONSTANTS.QUEUE_PROCESS_DELAY_MAX_MS, Math.floor(this.currentDelay * 1.5));
66
+ }
67
+ }
68
+ /** Reset to default state */
69
+ reset() {
70
+ this.consecutiveFailures = 0;
71
+ this.currentDelay = INJECTION_CONSTANTS.QUEUE_PROCESS_DELAY_MS;
72
+ }
73
+ }
74
+ /**
75
+ * Strip ANSI escape codes from a string.
76
+ * Converts cursor movements to spaces to preserve visual layout.
77
+ */
78
+ export function stripAnsi(str) {
79
+ // Convert cursor forward movements to spaces (CSI n C)
80
+ // eslint-disable-next-line no-control-regex
81
+ let result = str.replace(/\x1B\[(\d+)C/g, (_m, n) => ' '.repeat(parseInt(n, 10) || 1));
82
+ // Convert single cursor right (CSI C) to space
83
+ // eslint-disable-next-line no-control-regex
84
+ result = result.replace(/\x1B\[C/g, ' ');
85
+ // Remove carriage returns (causes text overwriting issues)
86
+ result = result.replace(/\r(?!\n)/g, '');
87
+ // Strip ANSI escape sequences (with \x1B prefix)
88
+ // eslint-disable-next-line no-control-regex
89
+ result = result.replace(/\x1B(?:\[[0-9;?]*[A-Za-z]|\].*?(?:\x07|\x1B\\)|[@-Z\\-_])/g, '');
90
+ // Strip orphaned CSI sequences that lost their escape byte
91
+ // Requires at least one digit or question mark to avoid stripping legitimate text like [Agent
92
+ result = result.replace(/^\s*(\[(?:\?|\d)\d*[A-Za-z])+\s*/g, '');
93
+ return result;
94
+ }
95
+ /**
96
+ * Sleep for a given number of milliseconds
97
+ */
98
+ export function sleep(ms) {
99
+ return new Promise((resolve) => setTimeout(resolve, ms));
100
+ }
101
+ /**
102
+ * Build the injection string for a relay message.
103
+ * Format: Relay message from {from} [{shortId}]{hints}: {body}
104
+ *
105
+ * If the body is already formatted (starts with "Relay message from"),
106
+ * returns it as-is to prevent double-wrapping.
107
+ */
108
+ export function buildInjectionString(msg) {
109
+ // Check if body is already formatted (prevents double-wrapping)
110
+ // This can happen when:
111
+ // - Delivering queued/pending messages that were already formatted
112
+ // - Agent output includes quoted relay messages that get re-processed
113
+ // Strip ANSI first so escape codes don't interfere with detection
114
+ const sanitizedBody = stripAnsi(msg.body || '').replace(/[\r\n]+/g, ' ').trim();
115
+ if (sanitizedBody.startsWith('Relay message from ')) {
116
+ // Already formatted - return as-is
117
+ return sanitizedBody;
118
+ }
119
+ const shortId = msg.messageId.substring(0, 8);
120
+ // Use senderName from data if available (for dashboard messages sent via _DashboardUI)
121
+ // This allows showing the actual GitHub username instead of the system client name
122
+ const displayFrom = (msg.from === '_DashboardUI' && typeof msg.data?.senderName === 'string')
123
+ ? msg.data.senderName
124
+ : msg.from;
125
+ // Thread hint
126
+ const threadHint = msg.thread ? ` [thread:${msg.thread}]` : '';
127
+ // Importance indicator: [!!] for high (>75), [!] for medium (>50)
128
+ const importanceHint = msg.importance !== undefined && msg.importance > 75
129
+ ? ' [!!]'
130
+ : msg.importance !== undefined && msg.importance > 50
131
+ ? ' [!]'
132
+ : '';
133
+ // Channel indicator for channel messages and broadcasts
134
+ // originalTo will be '*' for broadcasts or the channel name (e.g., '#general') for channel messages
135
+ // Make it clear that replies should go to the channel, not the sender
136
+ const channelHint = msg.originalTo === '*'
137
+ ? ' [#general] (reply to #general, not sender)'
138
+ : msg.originalTo?.startsWith('#')
139
+ ? ` [${msg.originalTo}] (reply to ${msg.originalTo}, not sender)`
140
+ : '';
141
+ // Extract attachment file paths if present
142
+ let attachmentHint = '';
143
+ if (msg.data?.attachments && Array.isArray(msg.data.attachments)) {
144
+ const filePaths = msg.data.attachments
145
+ .map((att) => att.filePath)
146
+ .filter((p) => typeof p === 'string');
147
+ if (filePaths.length > 0) {
148
+ attachmentHint = ` [Attachments: ${filePaths.join(', ')}]`;
149
+ }
150
+ }
151
+ return `Relay message from ${displayFrom} [${shortId}]${threadHint}${importanceHint}${channelHint}${attachmentHint}: ${sanitizedBody}`;
152
+ }
153
+ /**
154
+ * Calculate injection success rate from metrics
155
+ */
156
+ export function calculateSuccessRate(metrics) {
157
+ if (metrics.total === 0)
158
+ return 100;
159
+ const successful = metrics.successFirstTry + metrics.successWithRetry;
160
+ return Math.round((successful / metrics.total) * 10000) / 100;
161
+ }
162
+ /**
163
+ * Create a fresh injection metrics object
164
+ */
165
+ export function createInjectionMetrics() {
166
+ return {
167
+ total: 0,
168
+ successFirstTry: 0,
169
+ successWithRetry: 0,
170
+ failed: 0,
171
+ };
172
+ }
173
+ /**
174
+ * Detect CLI type from command string
175
+ */
176
+ export function detectCliType(command) {
177
+ const cmdLower = command.toLowerCase();
178
+ if (cmdLower.includes('gemini'))
179
+ return 'gemini';
180
+ if (cmdLower.includes('codex'))
181
+ return 'codex';
182
+ if (cmdLower.includes('claude'))
183
+ return 'claude';
184
+ if (cmdLower.includes('droid'))
185
+ return 'droid';
186
+ if (cmdLower.includes('opencode'))
187
+ return 'opencode';
188
+ if (cmdLower.includes('cursor'))
189
+ return 'cursor';
190
+ return 'other';
191
+ }
192
+ /**
193
+ * Get the default relay prefix (unified for all agent types)
194
+ */
195
+ export function getDefaultRelayPrefix() {
196
+ return '->relay:';
197
+ }
198
+ /**
199
+ * CLI-specific quirks and handling
200
+ */
201
+ export const CLI_QUIRKS = {
202
+ /**
203
+ * CLIs that support bracketed paste mode.
204
+ * Others may interpret the escape sequences literally.
205
+ */
206
+ supportsBracketedPaste: (cli) => {
207
+ return cli === 'claude' || cli === 'codex' || cli === 'gemini' || cli === 'opencode' || cli === 'cursor';
208
+ },
209
+ /**
210
+ * Gemini interprets certain keywords (While, For, If, etc.) as shell commands.
211
+ * Wrap message in backticks to prevent shell keyword interpretation.
212
+ */
213
+ wrapForGemini: (body) => {
214
+ return `\`${body.replace(/`/g, "'")}\``;
215
+ },
216
+ /**
217
+ * Get prompt pattern regex for a CLI type.
218
+ * Used to detect when input line is clear.
219
+ */
220
+ getPromptPattern: (cli) => {
221
+ const patterns = {
222
+ claude: /^[>›»]\s*$/,
223
+ gemini: /^[>›»]\s*$/,
224
+ codex: /^[>›»]\s*$/,
225
+ droid: /^[>›»]\s*$/,
226
+ opencode: /^[>›»]\s*$/,
227
+ cursor: /^[>›»]\s*$/,
228
+ spawned: /^[>›»]\s*$/,
229
+ other: /^[>$%#➜›»]\s*$/,
230
+ };
231
+ return patterns[cli] || patterns.other;
232
+ },
233
+ /**
234
+ * Check if a line looks like a shell prompt (for Gemini safety check).
235
+ * Gemini can drop into shell mode - we skip injection to avoid executing commands.
236
+ */
237
+ isShellPrompt: (line) => {
238
+ const clean = stripAnsi(line).trim();
239
+ return /^\$\s*$/.test(clean) || /^\s*\$\s*$/.test(clean);
240
+ },
241
+ };
242
+ /**
243
+ * Verify that an injected message appeared in the output.
244
+ * Uses a callback to get output content, allowing different backends
245
+ * (tmux capture-pane, PTY buffer) to be used.
246
+ *
247
+ * @param shortId - First 8 chars of message ID
248
+ * @param from - Sender name
249
+ * @param getOutput - Callback to retrieve current output
250
+ * @returns true if message pattern found in output
251
+ */
252
+ export async function verifyInjection(shortId, from, getOutput) {
253
+ const expectedPattern = `Relay message from ${from} [${shortId}]`;
254
+ const startTime = Date.now();
255
+ while (Date.now() - startTime < INJECTION_CONSTANTS.VERIFICATION_TIMEOUT_MS) {
256
+ try {
257
+ const output = await getOutput();
258
+ if (output.includes(expectedPattern)) {
259
+ return true;
260
+ }
261
+ }
262
+ catch {
263
+ // Output retrieval failed, verification fails
264
+ return false;
265
+ }
266
+ await sleep(100);
267
+ }
268
+ return false;
269
+ }
270
+ /**
271
+ * Inject a message with retry logic and verification.
272
+ * Includes dedup check to prevent double-injection race condition.
273
+ *
274
+ * This consolidates the retry/verification logic that was duplicated
275
+ * in TmuxWrapper and PtyWrapper.
276
+ *
277
+ * @param injection - The formatted injection string
278
+ * @param shortId - First 8 chars of message ID for verification
279
+ * @param from - Sender name for verification pattern
280
+ * @param callbacks - Wrapper-specific callbacks for injection operations
281
+ * @returns Result indicating success/failure and attempt count
282
+ */
283
+ export async function injectWithRetry(injection, shortId, from, callbacks) {
284
+ const metrics = callbacks.getMetrics();
285
+ metrics.total++;
286
+ // Skip verification mode: trust that write() succeeds without checking output
287
+ // Used for PTY-based injection where CLIs don't echo input back
288
+ if (callbacks.skipVerification) {
289
+ try {
290
+ await callbacks.performInjection(injection);
291
+ metrics.successFirstTry++;
292
+ return { success: true, attempts: 1 };
293
+ }
294
+ catch (err) {
295
+ callbacks.logError(`Injection error: ${err?.message || err}`);
296
+ metrics.failed++;
297
+ return { success: false, attempts: 1 };
298
+ }
299
+ }
300
+ for (let attempt = 0; attempt < INJECTION_CONSTANTS.MAX_RETRIES; attempt++) {
301
+ try {
302
+ // On retry attempts, first check if message already exists (race condition fix)
303
+ // Previous injection may have succeeded but verification timed out
304
+ if (attempt > 0) {
305
+ const alreadyExists = await verifyInjection(shortId, from, callbacks.getOutput);
306
+ if (alreadyExists) {
307
+ metrics.successWithRetry++;
308
+ callbacks.log(`Message already present (late verification), skipping re-injection`);
309
+ return { success: true, attempts: attempt + 1 };
310
+ }
311
+ }
312
+ // Perform the injection
313
+ await callbacks.performInjection(injection);
314
+ // Verify it appeared in output
315
+ const verified = await verifyInjection(shortId, from, callbacks.getOutput);
316
+ if (verified) {
317
+ if (attempt === 0) {
318
+ metrics.successFirstTry++;
319
+ }
320
+ else {
321
+ metrics.successWithRetry++;
322
+ callbacks.log(`Injection succeeded on attempt ${attempt + 1}`);
323
+ }
324
+ return { success: true, attempts: attempt + 1 };
325
+ }
326
+ // Not verified - log and retry
327
+ callbacks.log(`Injection not verified, attempt ${attempt + 1}/${INJECTION_CONSTANTS.MAX_RETRIES}`);
328
+ // Backoff before retry
329
+ if (attempt < INJECTION_CONSTANTS.MAX_RETRIES - 1) {
330
+ await sleep(INJECTION_CONSTANTS.RETRY_BACKOFF_MS * (attempt + 1));
331
+ }
332
+ }
333
+ catch (err) {
334
+ callbacks.logError(`Injection error on attempt ${attempt + 1}: ${err?.message || err}`);
335
+ }
336
+ }
337
+ // All retries failed
338
+ metrics.failed++;
339
+ return { success: false, attempts: INJECTION_CONSTANTS.MAX_RETRIES };
340
+ }
341
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * StuckDetector - Detect when an agent is stuck
3
+ *
4
+ * Implements agent-relay-501: Stuck detection heuristics
5
+ *
6
+ * Detects five stuck conditions:
7
+ * 1. Extended idle (no output for 10+ minutes)
8
+ * 2. Error loop (same error message repeated 3+ times)
9
+ * 3. Output loop (same output pattern repeated 3+ times)
10
+ * 4. Tool loop (same file operated on 10+ times in 5 minutes)
11
+ * 5. Output flood (abnormally high output rate suggesting infinite loop)
12
+ *
13
+ * NOTE: Message intent detection (agent says "I'll send" but doesn't) was removed
14
+ * because pattern-based NLP detection is unreliable. A protocol-level approach
15
+ * (detecting stale outbox files) should be implemented in relay-pty instead.
16
+ *
17
+ * Emits 'stuck' event when detected, with reason and details.
18
+ */
19
+ import { EventEmitter } from 'node:events';
20
+ export type StuckReason = 'extended_idle' | 'error_loop' | 'output_loop' | 'tool_loop' | 'output_flood';
21
+ /**
22
+ * Tracked tool invocation for loop detection
23
+ */
24
+ interface ToolInvocation {
25
+ tool: string;
26
+ target: string;
27
+ timestamp: number;
28
+ }
29
+ export interface StuckEvent {
30
+ reason: StuckReason;
31
+ details: string;
32
+ timestamp: number;
33
+ /** Time since last output in ms (for extended_idle) */
34
+ idleDurationMs?: number;
35
+ /** Repeated content (for loops) */
36
+ repeatedContent?: string;
37
+ /** Number of repetitions (for loops) */
38
+ repetitions?: number;
39
+ /** Target file/command (for tool_loop) */
40
+ targetFile?: string;
41
+ /** Tool name (for tool_loop) */
42
+ toolName?: string;
43
+ /** Output rate in lines per minute (for output_flood) */
44
+ linesPerMinute?: number;
45
+ }
46
+ export interface StuckDetectorConfig {
47
+ /** Duration of inactivity before considered stuck (ms, default: 10 minutes) */
48
+ extendedIdleMs?: number;
49
+ /** Number of repeated outputs before considered stuck (default: 3) */
50
+ loopThreshold?: number;
51
+ /** Check interval (ms, default: 30 seconds) */
52
+ checkIntervalMs?: number;
53
+ /** Minimum output length to consider for loop detection */
54
+ minLoopLength?: number;
55
+ /** Error patterns to detect (regexes) */
56
+ errorPatterns?: RegExp[];
57
+ /** Threshold for same file operations before considered stuck (default: 10) */
58
+ toolLoopThreshold?: number;
59
+ /** Time window for tool loop detection (ms, default: 5 minutes) */
60
+ toolLoopWindowMs?: number;
61
+ /** Output lines per minute threshold for flood detection (default: 5000) */
62
+ outputFloodLinesPerMinute?: number;
63
+ /** Minimum duration before flood detection activates (ms, default: 2 minutes) */
64
+ outputFloodMinDurationMs?: number;
65
+ }
66
+ export declare class StuckDetector extends EventEmitter {
67
+ private config;
68
+ private lastOutputTime;
69
+ private recentOutputs;
70
+ private checkInterval;
71
+ private isStuck;
72
+ private stuckReason;
73
+ private toolInvocations;
74
+ private outputLineCount;
75
+ private outputStartTime;
76
+ constructor(config?: StuckDetectorConfig);
77
+ /**
78
+ * Start monitoring for stuck conditions.
79
+ * Call this after the agent process starts.
80
+ */
81
+ start(): void;
82
+ /**
83
+ * Stop monitoring.
84
+ */
85
+ stop(): void;
86
+ /**
87
+ * Feed output to the detector.
88
+ * Call this for every output chunk from the agent.
89
+ */
90
+ onOutput(chunk: string): void;
91
+ /**
92
+ * Extract tool invocations from output and track them.
93
+ */
94
+ private extractToolInvocations;
95
+ /**
96
+ * Normalize output for comparison (strip ANSI, trim, lowercase).
97
+ */
98
+ private normalizeOutput;
99
+ /**
100
+ * Check for stuck conditions.
101
+ */
102
+ private checkStuck;
103
+ /**
104
+ * Detect repeated error messages.
105
+ */
106
+ private detectErrorLoop;
107
+ /**
108
+ * Detect repeated output patterns (not necessarily errors).
109
+ */
110
+ private detectOutputLoop;
111
+ /**
112
+ * Detect when the same file is being operated on repeatedly.
113
+ * This catches cases like an agent repeatedly reading/writing the same file
114
+ * in a loop, even if the output content differs each time.
115
+ */
116
+ private detectToolLoop;
117
+ /**
118
+ * Detect abnormally high output rates that suggest an infinite loop.
119
+ * Only triggers after minimum duration to avoid false positives during
120
+ * normal high-output operations (like builds or tests).
121
+ */
122
+ private detectOutputFlood;
123
+ /**
124
+ * Emit stuck event.
125
+ */
126
+ private emitStuck;
127
+ /**
128
+ * Check if currently detected as stuck.
129
+ */
130
+ getIsStuck(): boolean;
131
+ /**
132
+ * Get the reason for being stuck (if stuck).
133
+ */
134
+ getStuckReason(): StuckReason | null;
135
+ /**
136
+ * Get time since last output in milliseconds.
137
+ */
138
+ getIdleDuration(): number;
139
+ /**
140
+ * Reset state.
141
+ */
142
+ reset(): void;
143
+ /**
144
+ * Get current output statistics (useful for debugging).
145
+ */
146
+ getOutputStats(): {
147
+ lineCount: number;
148
+ durationMs: number;
149
+ linesPerMinute: number;
150
+ };
151
+ /**
152
+ * Get recent tool invocations (useful for debugging).
153
+ */
154
+ getToolInvocations(): ToolInvocation[];
155
+ }
156
+ /**
157
+ * Create a stuck detector with default configuration.
158
+ */
159
+ export declare function createStuckDetector(config?: StuckDetectorConfig): StuckDetector;
160
+ export {};
161
+ //# sourceMappingURL=stuck-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stuck-detector.d.ts","sourceRoot":"","sources":["../src/stuck-detector.ts"],"names":[],"mappings":"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"}