@agentmeshhq/agent 0.4.18 → 0.4.20

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 (122) hide show
  1. package/dist/__tests__/attach.test.d.ts +1 -0
  2. package/dist/__tests__/attach.test.js +200 -0
  3. package/dist/__tests__/attach.test.js.map +1 -0
  4. package/dist/__tests__/auth-guard.integration.test.js +1 -1
  5. package/dist/__tests__/auth-guard.integration.test.js.map +1 -1
  6. package/dist/__tests__/auth-guard.test.js +3 -3
  7. package/dist/__tests__/auth-guard.test.js.map +1 -1
  8. package/dist/__tests__/bootstrap.test.js +23 -0
  9. package/dist/__tests__/bootstrap.test.js.map +1 -1
  10. package/dist/__tests__/daemon-hub-resilience.test.js +2 -2
  11. package/dist/__tests__/daemon-hub-resilience.test.js.map +1 -1
  12. package/dist/__tests__/evicted-cleanup.test.js.map +1 -1
  13. package/dist/__tests__/injector.test.js +47 -4
  14. package/dist/__tests__/injector.test.js.map +1 -1
  15. package/dist/__tests__/list.test.d.ts +1 -0
  16. package/dist/__tests__/list.test.js +62 -0
  17. package/dist/__tests__/list.test.js.map +1 -0
  18. package/dist/__tests__/opencode-serve.test.d.ts +1 -0
  19. package/dist/__tests__/opencode-serve.test.js +54 -0
  20. package/dist/__tests__/opencode-serve.test.js.map +1 -0
  21. package/dist/__tests__/opencode-session-policy.test.d.ts +1 -0
  22. package/dist/__tests__/opencode-session-policy.test.js +61 -0
  23. package/dist/__tests__/opencode-session-policy.test.js.map +1 -0
  24. package/dist/__tests__/opencode-session.test.d.ts +1 -0
  25. package/dist/__tests__/opencode-session.test.js +178 -0
  26. package/dist/__tests__/opencode-session.test.js.map +1 -0
  27. package/dist/__tests__/registry.register.test.js +16 -0
  28. package/dist/__tests__/registry.register.test.js.map +1 -1
  29. package/dist/__tests__/relay.test.js +121 -2
  30. package/dist/__tests__/relay.test.js.map +1 -1
  31. package/dist/__tests__/shared-resource-guards.test.js +1 -4
  32. package/dist/__tests__/shared-resource-guards.test.js.map +1 -1
  33. package/dist/__tests__/start-team-id.test.js +22 -0
  34. package/dist/__tests__/start-team-id.test.js.map +1 -1
  35. package/dist/__tests__/token-rejection-recovery.test.js +52 -0
  36. package/dist/__tests__/token-rejection-recovery.test.js.map +1 -1
  37. package/dist/__tests__/watcher-queue.test.js +7 -2
  38. package/dist/__tests__/watcher-queue.test.js.map +1 -1
  39. package/dist/cli/attach.d.ts +1 -1
  40. package/dist/cli/attach.js +125 -2
  41. package/dist/cli/attach.js.map +1 -1
  42. package/dist/cli/auth.js.map +1 -1
  43. package/dist/cli/index.js +9 -4
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/cli/list.js +26 -2
  46. package/dist/cli/list.js.map +1 -1
  47. package/dist/cli/relay.d.ts +3 -0
  48. package/dist/cli/relay.js +149 -1
  49. package/dist/cli/relay.js.map +1 -1
  50. package/dist/cli/start.d.ts +9 -1
  51. package/dist/cli/start.js +8 -0
  52. package/dist/cli/start.js.map +1 -1
  53. package/dist/cli/status.js +21 -8
  54. package/dist/cli/status.js.map +1 -1
  55. package/dist/cli/test.js +12 -1
  56. package/dist/cli/test.js.map +1 -1
  57. package/dist/config/schema.d.ts +16 -0
  58. package/dist/core/auth-guard.js +2 -2
  59. package/dist/core/auth-guard.js.map +1 -1
  60. package/dist/core/chat-output-parser.d.ts +3 -3
  61. package/dist/core/chat-output-parser.js +35 -19
  62. package/dist/core/chat-output-parser.js.map +1 -1
  63. package/dist/core/chat-output-parser.test.js +21 -0
  64. package/dist/core/chat-output-parser.test.js.map +1 -1
  65. package/dist/core/daemon/bootstrap.d.ts +8 -0
  66. package/dist/core/daemon/bootstrap.js +6 -1
  67. package/dist/core/daemon/bootstrap.js.map +1 -1
  68. package/dist/core/daemon/state.d.ts +8 -0
  69. package/dist/core/daemon/state.js +8 -0
  70. package/dist/core/daemon/state.js.map +1 -1
  71. package/dist/core/daemon/tmux-session.d.ts +4 -0
  72. package/dist/core/daemon/tmux-session.js +9 -1
  73. package/dist/core/daemon/tmux-session.js.map +1 -1
  74. package/dist/core/daemon/workspace.js +10 -2
  75. package/dist/core/daemon/workspace.js.map +1 -1
  76. package/dist/core/daemon.d.ts +10 -1
  77. package/dist/core/daemon.js +155 -18
  78. package/dist/core/daemon.js.map +1 -1
  79. package/dist/core/handoff-sla.js +1 -1
  80. package/dist/core/handoff-sla.js.map +1 -1
  81. package/dist/core/injector.d.ts +2 -0
  82. package/dist/core/injector.js +107 -49
  83. package/dist/core/injector.js.map +1 -1
  84. package/dist/core/opencode-serve.d.ts +26 -0
  85. package/dist/core/opencode-serve.js +97 -0
  86. package/dist/core/opencode-serve.js.map +1 -0
  87. package/dist/core/opencode-session-policy.d.ts +10 -0
  88. package/dist/core/opencode-session-policy.js +10 -0
  89. package/dist/core/opencode-session-policy.js.map +1 -0
  90. package/dist/core/opencode-session.d.ts +12 -0
  91. package/dist/core/opencode-session.js +165 -0
  92. package/dist/core/opencode-session.js.map +1 -0
  93. package/dist/core/registry.d.ts +2 -1
  94. package/dist/core/registry.js +3 -2
  95. package/dist/core/registry.js.map +1 -1
  96. package/dist/core/tmux-runtime.d.ts +1 -0
  97. package/dist/core/tmux-runtime.js +4 -1
  98. package/dist/core/tmux-runtime.js.map +1 -1
  99. package/dist/core/tmux.js +5 -0
  100. package/dist/core/tmux.js.map +1 -1
  101. package/dist/runtime/adapters/opencode.d.ts +63 -0
  102. package/dist/runtime/adapters/opencode.js +358 -0
  103. package/dist/runtime/adapters/opencode.js.map +1 -0
  104. package/dist/runtime/adapters/tmux-fallback.d.ts +23 -0
  105. package/dist/runtime/adapters/tmux-fallback.js +148 -0
  106. package/dist/runtime/adapters/tmux-fallback.js.map +1 -0
  107. package/dist/runtime/adapters/tmux-fallback.test.d.ts +4 -0
  108. package/dist/runtime/adapters/tmux-fallback.test.js +91 -0
  109. package/dist/runtime/adapters/tmux-fallback.test.js.map +1 -0
  110. package/dist/runtime/index.d.ts +146 -0
  111. package/dist/runtime/index.js +191 -0
  112. package/dist/runtime/index.js.map +1 -0
  113. package/dist/runtime/registry.d.ts +53 -0
  114. package/dist/runtime/registry.js +112 -0
  115. package/dist/runtime/registry.js.map +1 -0
  116. package/dist/runtime/registry.test.d.ts +4 -0
  117. package/dist/runtime/registry.test.js +69 -0
  118. package/dist/runtime/registry.test.js.map +1 -0
  119. package/dist/runtime/types.d.ts +158 -0
  120. package/dist/runtime/types.js +8 -0
  121. package/dist/runtime/types.js.map +1 -0
  122. package/package.json +1 -1
@@ -0,0 +1,358 @@
1
+ /**
2
+ * OpenCode Runtime Adapter
3
+ *
4
+ * PRIMARY: OpenCode serve mode (HTTP API)
5
+ * FALLBACK: Tmux capture with delivery_path=tmux-fallback metadata
6
+ *
7
+ * This adapter implements the runtime I/O contract with OpenCode serve mode
8
+ * as the primary path for clean, structured output.
9
+ */
10
+ import { extractLLMReply } from "../../core/chat-output-parser.js";
11
+ import { captureSessionOutput, sendKeys, sessionExists } from "../../core/tmux.js";
12
+ const DEFAULT_WAIT_OPTIONS = {
13
+ pollMs: 1000,
14
+ stableMs: 3000,
15
+ timeoutMs: 60000,
16
+ maxLines: 120,
17
+ };
18
+ /** OpenCode serve mode default port range */
19
+ const OPENCODE_PORT_RANGE = { min: 3000, max: 3010 };
20
+ /**
21
+ * OpenCode adapter - serve mode primary, tmux fallback
22
+ */
23
+ export class OpenCodeAdapter {
24
+ id = "opencode";
25
+ displayName = "OpenCode";
26
+ supportedRunners = ["opencode"];
27
+ supportsStructuredEvents = true;
28
+ /** Cache for serve port by session */
29
+ servePort = new Map();
30
+ canHandle(sessionName) {
31
+ if (!sessionExists(sessionName))
32
+ return false;
33
+ try {
34
+ const { execSync } = require("node:child_process");
35
+ const output = execSync(`tmux list-panes -t "${sessionName}" -F "#{pane_current_command}"`, {
36
+ encoding: "utf-8",
37
+ });
38
+ return output.toLowerCase().includes("opencode");
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Detect OpenCode serve mode port for session
46
+ * Returns port number or null if not in serve mode
47
+ */
48
+ async detectServePort(sessionName) {
49
+ const cached = this.servePort.get(sessionName);
50
+ if (cached !== undefined)
51
+ return cached;
52
+ try {
53
+ const { execSync } = require("node:child_process");
54
+ // Check for AGENTMESH_OPENCODE_PORT env var in tmux session
55
+ const envOutput = execSync(`tmux show-environment -t "${sessionName}" | grep AGENTMESH_OPENCODE_PORT || true`, { encoding: "utf-8" });
56
+ const portMatch = envOutput.match(/AGENTMESH_OPENCODE_PORT=(\d+)/);
57
+ if (portMatch) {
58
+ const port = parseInt(portMatch[1], 10);
59
+ this.servePort.set(sessionName, port);
60
+ return port;
61
+ }
62
+ // Probe common OpenCode serve ports
63
+ for (let port = OPENCODE_PORT_RANGE.min; port <= OPENCODE_PORT_RANGE.max; port++) {
64
+ try {
65
+ const response = await fetch(`http://localhost:${port}/health`, {
66
+ method: "GET",
67
+ signal: AbortSignal.timeout(500),
68
+ });
69
+ if (response.ok) {
70
+ this.servePort.set(sessionName, port);
71
+ return port;
72
+ }
73
+ }
74
+ catch {
75
+ // Port not available, continue probing
76
+ }
77
+ }
78
+ this.servePort.set(sessionName, null);
79
+ return null;
80
+ }
81
+ catch {
82
+ this.servePort.set(sessionName, null);
83
+ return null;
84
+ }
85
+ }
86
+ /**
87
+ * PRIMARY: Inject via OpenCode serve mode HTTP API
88
+ * FALLBACK: Tmux send-keys
89
+ */
90
+ async injectInput(sessionName, request) {
91
+ // Try serve mode first (PRIMARY path)
92
+ const servePort = await this.detectServePort(sessionName);
93
+ if (servePort !== null) {
94
+ try {
95
+ const response = await fetch(`http://localhost:${servePort}/api/v1/chat`, {
96
+ method: "POST",
97
+ headers: { "Content-Type": "application/json" },
98
+ body: JSON.stringify({
99
+ message: request.content,
100
+ correlation_id: request.messageId,
101
+ }),
102
+ signal: AbortSignal.timeout(5000),
103
+ });
104
+ if (response.ok) {
105
+ console.log(`[OpenCodeAdapter] Injected via serve mode (port ${servePort})`);
106
+ return true;
107
+ }
108
+ }
109
+ catch (error) {
110
+ console.log(`[OpenCodeAdapter] Serve mode failed, falling back to tmux: ${error}`);
111
+ }
112
+ }
113
+ // FALLBACK: Tmux
114
+ console.log(`[OpenCodeAdapter] Using tmux fallback`);
115
+ return sendKeys(sessionName, request.content);
116
+ }
117
+ /**
118
+ * PRIMARY: Capture from OpenCode serve mode events
119
+ * FALLBACK: Tmux capture with delivery_path=tmux-fallback
120
+ */
121
+ async captureOutput(sessionName, request) {
122
+ const servePort = await this.detectServePort(sessionName);
123
+ // PRIMARY: Try serve mode
124
+ if (servePort !== null) {
125
+ try {
126
+ const response = await fetch(`http://localhost:${servePort}/api/v1/chat/${request.messageId}/response`, {
127
+ method: "GET",
128
+ signal: AbortSignal.timeout(5000),
129
+ });
130
+ if (response.ok) {
131
+ const data = await response.json();
132
+ return this.formatServeModeResponse(data, request, servePort);
133
+ }
134
+ }
135
+ catch (error) {
136
+ console.log(`[OpenCodeAdapter] Serve mode capture failed: ${error}`);
137
+ }
138
+ }
139
+ // FALLBACK: Tmux capture with metadata
140
+ return this.captureTmuxFallback(sessionName, request);
141
+ }
142
+ /**
143
+ * Wait for output with serve mode primary, tmux fallback
144
+ */
145
+ async waitForOutput(sessionName, request, options) {
146
+ const opts = { ...DEFAULT_WAIT_OPTIONS, ...options };
147
+ const servePort = await this.detectServePort(sessionName);
148
+ // PRIMARY: Use serve mode if available
149
+ if (servePort !== null) {
150
+ return this.waitForServeModeOutput(sessionName, request, servePort, opts);
151
+ }
152
+ // FALLBACK: Tmux-based capture
153
+ return this.waitForTmuxFallback(sessionName, request, opts);
154
+ }
155
+ /**
156
+ * PRIMARY path: Wait for output via serve mode
157
+ */
158
+ async waitForServeModeOutput(sessionName, request, port, opts) {
159
+ const startTime = Date.now();
160
+ while (Date.now() - startTime < opts.timeoutMs) {
161
+ try {
162
+ const response = await fetch(`http://localhost:${port}/api/v1/chat/${request.messageId}/response`, {
163
+ method: "GET",
164
+ signal: AbortSignal.timeout(1000),
165
+ });
166
+ if (response.ok) {
167
+ const data = await response.json();
168
+ if (data.complete) {
169
+ return this.formatServeModeResponse(data, request, port, Date.now() - startTime);
170
+ }
171
+ }
172
+ }
173
+ catch {
174
+ // Not ready yet, continue polling
175
+ }
176
+ await new Promise((r) => setTimeout(r, opts.pollMs));
177
+ }
178
+ // Timeout - return what we have
179
+ console.log(`[OpenCodeAdapter] Serve mode timeout, falling back to tmux`);
180
+ return this.waitForTmuxFallback(sessionName, request, opts);
181
+ }
182
+ /**
183
+ * FALLBACK path: Wait for output via tmux capture
184
+ */
185
+ async waitForTmuxFallback(sessionName, request, opts) {
186
+ const startTime = Date.now();
187
+ let lastSnapshot = captureSessionOutput(sessionName, opts.maxLines) || "";
188
+ let lastChangeAt = Date.now();
189
+ let stabilizedAt = null;
190
+ const baselineParsed = extractLLMReply(lastSnapshot).trim();
191
+ let lastParsed = baselineParsed;
192
+ let parsedChangedAt = null;
193
+ return new Promise((resolve) => {
194
+ const check = () => {
195
+ const elapsed = Date.now() - startTime;
196
+ const current = captureSessionOutput(sessionName, opts.maxLines) || "";
197
+ const parsed = extractLLMReply(current).trim();
198
+ if (current !== lastSnapshot) {
199
+ lastSnapshot = current;
200
+ lastChangeAt = Date.now();
201
+ stabilizedAt = null;
202
+ }
203
+ else if (!stabilizedAt) {
204
+ stabilizedAt = Date.now();
205
+ }
206
+ if (parsed !== lastParsed) {
207
+ lastParsed = parsed;
208
+ parsedChangedAt = Date.now();
209
+ }
210
+ else if (parsedChangedAt === null && parsed !== baselineParsed) {
211
+ parsedChangedAt = Date.now();
212
+ }
213
+ const stable = stabilizedAt && Date.now() - stabilizedAt >= opts.stableMs;
214
+ const timedOut = elapsed >= opts.timeoutMs;
215
+ const hasNewParsedOutput = parsed.length > 0 && parsed !== baselineParsed;
216
+ const parsedStable = parsedChangedAt !== null &&
217
+ Date.now() - parsedChangedAt >= Math.min(1200, Math.max(400, opts.stableMs / 2));
218
+ if (stable || timedOut) {
219
+ // For clean/structured capture, do not resolve on a merely stable pane
220
+ // unless we actually parsed assistant output. This prevents false
221
+ // "(no assistant output captured)" when only the user input echo is visible.
222
+ if (!timedOut && request.outputMode !== "raw" && !hasNewParsedOutput) {
223
+ stabilizedAt = null;
224
+ setTimeout(check, opts.pollMs);
225
+ return;
226
+ }
227
+ const stabilizationMs = stabilizedAt ? stabilizedAt - lastChangeAt : 0;
228
+ resolve(this.formatTmuxFallbackResponse(current, request, stabilizationMs, timedOut));
229
+ return;
230
+ }
231
+ // Fast-path for clean/structured: return as soon as parsed assistant
232
+ // output is new for this turn and stable, even if raw pane keeps changing
233
+ // due to token counters / terminal chrome updates.
234
+ if (!timedOut && request.outputMode !== "raw" && hasNewParsedOutput && parsedStable) {
235
+ const stabilizationMs = Date.now() - (parsedChangedAt ?? startTime);
236
+ resolve(this.formatTmuxFallbackResponse(current, request, stabilizationMs, false));
237
+ return;
238
+ }
239
+ setTimeout(check, opts.pollMs);
240
+ };
241
+ check();
242
+ });
243
+ }
244
+ /**
245
+ * FALLBACK: Capture from tmux with metadata
246
+ */
247
+ captureTmuxFallback(sessionName, request) {
248
+ const rawOutput = captureSessionOutput(sessionName, 120) || "";
249
+ const linesCaptured = rawOutput.split("\n").length;
250
+ const cleaned = extractLLMReply(rawOutput);
251
+ switch (request.outputMode) {
252
+ case "raw":
253
+ return {
254
+ mode: "raw",
255
+ content: rawOutput,
256
+ metadata: { delivery_path: "tmux-fallback" },
257
+ };
258
+ case "structured": {
259
+ const structured = {
260
+ content: cleaned,
261
+ rawOutput,
262
+ metadata: {
263
+ capturedAt: new Date().toISOString(),
264
+ linesCaptured,
265
+ stabilizationMs: 0,
266
+ truncated: linesCaptured >= 120,
267
+ delivery_path: "tmux-fallback",
268
+ },
269
+ parsing: {
270
+ success: cleaned.length > 0,
271
+ parser: "tmux-regex",
272
+ error: cleaned.length === 0 ? "No LLM reply extracted" : undefined,
273
+ },
274
+ };
275
+ return { mode: "structured", data: structured };
276
+ }
277
+ default:
278
+ return {
279
+ mode: "clean",
280
+ content: cleaned,
281
+ metadata: { delivery_path: "tmux-fallback" },
282
+ };
283
+ }
284
+ }
285
+ /**
286
+ * Format serve mode response
287
+ */
288
+ formatServeModeResponse(data, request, port, elapsedMs = 0) {
289
+ const content = String(data.content || data.message || "");
290
+ switch (request.outputMode) {
291
+ case "raw":
292
+ return { mode: "raw", content };
293
+ case "structured": {
294
+ const structured = {
295
+ content,
296
+ rawOutput: content,
297
+ metadata: {
298
+ capturedAt: new Date().toISOString(),
299
+ linesCaptured: content.split("\n").length,
300
+ stabilizationMs: elapsedMs,
301
+ truncated: false,
302
+ delivery_path: `opencode-serve:${port}`,
303
+ },
304
+ parsing: {
305
+ success: true,
306
+ parser: "opencode-serve-api",
307
+ },
308
+ };
309
+ return { mode: "structured", data: structured };
310
+ }
311
+ default:
312
+ return { mode: "clean", content };
313
+ }
314
+ }
315
+ /**
316
+ * Format tmux fallback response
317
+ */
318
+ formatTmuxFallbackResponse(rawOutput, request, stabilizationMs, timedOut) {
319
+ const linesCaptured = rawOutput.split("\n").length;
320
+ const cleaned = extractLLMReply(rawOutput);
321
+ switch (request.outputMode) {
322
+ case "raw":
323
+ return {
324
+ mode: "raw",
325
+ content: rawOutput,
326
+ metadata: { delivery_path: "tmux-fallback" },
327
+ };
328
+ case "structured": {
329
+ const structured = {
330
+ content: cleaned,
331
+ rawOutput,
332
+ metadata: {
333
+ capturedAt: new Date().toISOString(),
334
+ linesCaptured,
335
+ stabilizationMs,
336
+ truncated: linesCaptured >= 120,
337
+ delivery_path: "tmux-fallback",
338
+ },
339
+ parsing: {
340
+ success: cleaned.length > 0 && !timedOut,
341
+ parser: "tmux-regex",
342
+ error: cleaned.length === 0 ? "No LLM reply extracted" : timedOut ? "Timed out" : undefined,
343
+ },
344
+ };
345
+ return { mode: "structured", data: structured };
346
+ }
347
+ default:
348
+ return {
349
+ mode: "clean",
350
+ content: cleaned,
351
+ metadata: { delivery_path: "tmux-fallback" },
352
+ };
353
+ }
354
+ }
355
+ }
356
+ /** Singleton instance */
357
+ export const opencodeAdapter = new OpenCodeAdapter();
358
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../../src/runtime/adapters/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Tmux Fallback Adapter
3
+ *
4
+ * Generic tmux-based adapter that works with any runner.
5
+ * Uses tmux capture-pane and regex parsing for output extraction.
6
+ */
7
+ import type { ChatInputRequest, ChatOutputResponse, RuntimeAdapter, WaitForOutputOptions } from "../types.js";
8
+ /**
9
+ * Tmux fallback adapter - works with any runner via tmux capture
10
+ */
11
+ export declare class TmuxFallbackAdapter implements RuntimeAdapter {
12
+ readonly id = "tmux-fallback";
13
+ readonly displayName = "Tmux Fallback";
14
+ readonly supportedRunners: string[];
15
+ readonly supportsStructuredEvents = false;
16
+ canHandle(sessionName: string): boolean;
17
+ injectInput(sessionName: string, request: ChatInputRequest): boolean;
18
+ captureOutput(sessionName: string, request: ChatInputRequest): ChatOutputResponse;
19
+ waitForOutput(sessionName: string, request: ChatInputRequest, options?: WaitForOutputOptions): Promise<ChatOutputResponse>;
20
+ private formatResponse;
21
+ }
22
+ /** Singleton instance */
23
+ export declare const tmuxFallbackAdapter: TmuxFallbackAdapter;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Tmux Fallback Adapter
3
+ *
4
+ * Generic tmux-based adapter that works with any runner.
5
+ * Uses tmux capture-pane and regex parsing for output extraction.
6
+ */
7
+ import { extractLLMReply } from "../../core/chat-output-parser.js";
8
+ import { captureSessionOutput, sendKeys, sessionExists } from "../../core/tmux.js";
9
+ const DEFAULT_WAIT_OPTIONS = {
10
+ pollMs: 2000,
11
+ stableMs: 5000,
12
+ timeoutMs: 60000,
13
+ maxLines: 120,
14
+ };
15
+ /**
16
+ * Tmux fallback adapter - works with any runner via tmux capture
17
+ */
18
+ export class TmuxFallbackAdapter {
19
+ id = "tmux-fallback";
20
+ displayName = "Tmux Fallback";
21
+ supportedRunners = ["*"]; // Universal fallback
22
+ supportsStructuredEvents = false;
23
+ canHandle(sessionName) {
24
+ return sessionExists(sessionName);
25
+ }
26
+ injectInput(sessionName, request) {
27
+ return sendKeys(sessionName, request.content);
28
+ }
29
+ captureOutput(sessionName, request) {
30
+ const rawOutput = captureSessionOutput(sessionName, 120) || "";
31
+ switch (request.outputMode) {
32
+ case "raw":
33
+ return { mode: "raw", content: rawOutput };
34
+ case "structured": {
35
+ const cleaned = extractLLMReply(rawOutput);
36
+ const structured = {
37
+ content: cleaned,
38
+ rawOutput,
39
+ metadata: {
40
+ capturedAt: new Date().toISOString(),
41
+ linesCaptured: rawOutput.split("\n").length,
42
+ stabilizationMs: 0,
43
+ truncated: rawOutput.split("\n").length >= 120,
44
+ },
45
+ parsing: {
46
+ success: cleaned.length > 0,
47
+ parser: "tmux-regex",
48
+ error: cleaned.length === 0 ? "No LLM reply extracted" : undefined,
49
+ },
50
+ };
51
+ return { mode: "structured", data: structured };
52
+ }
53
+ default: {
54
+ const cleaned = extractLLMReply(rawOutput);
55
+ return { mode: "clean", content: cleaned };
56
+ }
57
+ }
58
+ }
59
+ async waitForOutput(sessionName, request, options) {
60
+ const opts = { ...DEFAULT_WAIT_OPTIONS, ...options };
61
+ const startTime = Date.now();
62
+ let lastSnapshot = captureSessionOutput(sessionName, opts.maxLines) || "";
63
+ let lastChangeAt = Date.now();
64
+ let stabilizedAt = null;
65
+ const baselineParsed = extractLLMReply(lastSnapshot).trim();
66
+ let lastParsed = baselineParsed;
67
+ let parsedChangedAt = null;
68
+ return new Promise((resolve) => {
69
+ const check = () => {
70
+ const elapsed = Date.now() - startTime;
71
+ const current = captureSessionOutput(sessionName, opts.maxLines) || "";
72
+ const parsed = extractLLMReply(current).trim();
73
+ if (current !== lastSnapshot) {
74
+ lastSnapshot = current;
75
+ lastChangeAt = Date.now();
76
+ stabilizedAt = null;
77
+ }
78
+ else if (!stabilizedAt) {
79
+ stabilizedAt = Date.now();
80
+ }
81
+ if (parsed !== lastParsed) {
82
+ lastParsed = parsed;
83
+ parsedChangedAt = Date.now();
84
+ }
85
+ else if (parsedChangedAt === null && parsed !== baselineParsed) {
86
+ parsedChangedAt = Date.now();
87
+ }
88
+ const stable = stabilizedAt && Date.now() - stabilizedAt >= opts.stableMs;
89
+ const timedOut = elapsed >= opts.timeoutMs;
90
+ const hasNewParsedOutput = parsed.length > 0 && parsed !== baselineParsed;
91
+ const parsedStable = parsedChangedAt !== null &&
92
+ Date.now() - parsedChangedAt >= Math.min(1200, Math.max(400, opts.stableMs / 2));
93
+ if (stable || timedOut) {
94
+ // For clean/structured capture, wait for actual parsed assistant output.
95
+ // A stable pane can still mean "input echoed, assistant not responded yet".
96
+ if (!timedOut && request.outputMode !== "raw" && !hasNewParsedOutput) {
97
+ stabilizedAt = null;
98
+ setTimeout(check, opts.pollMs);
99
+ return;
100
+ }
101
+ const stabilizationMs = stabilizedAt ? stabilizedAt - lastChangeAt : 0;
102
+ resolve(this.formatResponse(current, request, stabilizationMs, timedOut));
103
+ return;
104
+ }
105
+ // Fast-path for clean/structured: return once parsed output is new for
106
+ // this turn and stable, even when raw pane keeps changing.
107
+ if (!timedOut && request.outputMode !== "raw" && hasNewParsedOutput && parsedStable) {
108
+ const stabilizationMs = Date.now() - (parsedChangedAt ?? startTime);
109
+ resolve(this.formatResponse(current, request, stabilizationMs, false));
110
+ return;
111
+ }
112
+ setTimeout(check, opts.pollMs);
113
+ };
114
+ check();
115
+ });
116
+ }
117
+ formatResponse(rawOutput, request, stabilizationMs, _timedOut) {
118
+ const linesCaptured = rawOutput.split("\n").length;
119
+ const cleaned = extractLLMReply(rawOutput);
120
+ switch (request.outputMode) {
121
+ case "raw":
122
+ return { mode: "raw", content: rawOutput };
123
+ case "structured": {
124
+ const structured = {
125
+ content: cleaned,
126
+ rawOutput,
127
+ metadata: {
128
+ capturedAt: new Date().toISOString(),
129
+ linesCaptured,
130
+ stabilizationMs,
131
+ truncated: linesCaptured >= 120,
132
+ },
133
+ parsing: {
134
+ success: cleaned.length > 0,
135
+ parser: "tmux-regex",
136
+ error: cleaned.length === 0 ? "No LLM reply extracted" : undefined,
137
+ },
138
+ };
139
+ return { mode: "structured", data: structured };
140
+ }
141
+ default:
142
+ return { mode: "clean", content: cleaned };
143
+ }
144
+ }
145
+ }
146
+ /** Singleton instance */
147
+ export const tmuxFallbackAdapter = new TmuxFallbackAdapter();
148
+ //# sourceMappingURL=tmux-fallback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tmux-fallback.js","sourceRoot":"","sources":["../../../src/runtime/adapters/tmux-fallback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Tmux Fallback Adapter Tests
3
+ */
4
+ export {};
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Tmux Fallback Adapter Tests
3
+ */
4
+ import { describe, expect, it, vi } from "vitest";
5
+ import { TmuxFallbackAdapter } from "./tmux-fallback.js";
6
+ // Mock the tmux module
7
+ vi.mock("../../core/tmux.js", () => ({
8
+ sessionExists: vi.fn(() => true),
9
+ sendKeys: vi.fn(() => true),
10
+ captureSessionOutput: vi.fn(() => "❯ Hello\n⏺ This is the LLM response\n❯ "),
11
+ getSessionName: vi.fn((name) => `agentmesh-${name}`),
12
+ }));
13
+ describe("TmuxFallbackAdapter", () => {
14
+ const adapter = new TmuxFallbackAdapter();
15
+ describe("basic properties", () => {
16
+ it("should have correct id and name", () => {
17
+ expect(adapter.id).toBe("tmux-fallback");
18
+ expect(adapter.displayName).toBe("Tmux Fallback");
19
+ });
20
+ it("should support all runners", () => {
21
+ expect(adapter.supportedRunners).toEqual(["*"]);
22
+ });
23
+ it("should not support structured events", () => {
24
+ expect(adapter.supportsStructuredEvents).toBe(false);
25
+ });
26
+ });
27
+ describe("canHandle", () => {
28
+ it("should return true for existing sessions", () => {
29
+ expect(adapter.canHandle("agentmesh-test")).toBe(true);
30
+ });
31
+ });
32
+ describe("captureOutput", () => {
33
+ const baseRequest = {
34
+ content: "Test message",
35
+ outputMode: "clean",
36
+ messageId: "msg_123",
37
+ workspace: "test-workspace",
38
+ agentId: "agent_456",
39
+ };
40
+ it("should return clean output by default", () => {
41
+ const response = adapter.captureOutput("agentmesh-test", baseRequest);
42
+ expect(response.mode).toBe("clean");
43
+ if (response.mode === "clean") {
44
+ expect(response.content).toBe("This is the LLM response");
45
+ }
46
+ });
47
+ it("should return raw output when requested", () => {
48
+ const request = { ...baseRequest, outputMode: "raw" };
49
+ const response = adapter.captureOutput("agentmesh-test", request);
50
+ expect(response.mode).toBe("raw");
51
+ if (response.mode === "raw") {
52
+ expect(response.content).toContain("❯ Hello");
53
+ expect(response.content).toContain("⏺ This is the LLM response");
54
+ }
55
+ });
56
+ it("should return structured output when requested", () => {
57
+ const request = { ...baseRequest, outputMode: "structured" };
58
+ const response = adapter.captureOutput("agentmesh-test", request);
59
+ expect(response.mode).toBe("structured");
60
+ if (response.mode === "structured") {
61
+ expect(response.data.content).toBe("This is the LLM response");
62
+ expect(response.data.rawOutput).toContain("❯ Hello");
63
+ expect(response.data.metadata.linesCaptured).toBeGreaterThan(0);
64
+ expect(response.data.parsing.parser).toBe("tmux-regex");
65
+ expect(response.data.parsing.success).toBe(true);
66
+ }
67
+ });
68
+ it("should handle empty output gracefully", () => {
69
+ const { captureSessionOutput } = require("../../core/tmux.js");
70
+ captureSessionOutput.mockReturnValueOnce("");
71
+ const response = adapter.captureOutput("agentmesh-test", baseRequest);
72
+ if (response.mode === "clean") {
73
+ expect(response.content).toBe("");
74
+ }
75
+ });
76
+ });
77
+ describe("injectInput", () => {
78
+ it("should send keys to session", () => {
79
+ const request = {
80
+ content: "Hello agent",
81
+ outputMode: "clean",
82
+ messageId: "msg_123",
83
+ workspace: "test-workspace",
84
+ agentId: "agent_456",
85
+ };
86
+ const result = adapter.injectInput("agentmesh-test", request);
87
+ expect(result).toBe(true);
88
+ });
89
+ });
90
+ });
91
+ //# sourceMappingURL=tmux-fallback.test.js.map