@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.
- package/dist/__tests__/attach.test.d.ts +1 -0
- package/dist/__tests__/attach.test.js +200 -0
- package/dist/__tests__/attach.test.js.map +1 -0
- package/dist/__tests__/auth-guard.integration.test.js +1 -1
- package/dist/__tests__/auth-guard.integration.test.js.map +1 -1
- package/dist/__tests__/auth-guard.test.js +3 -3
- package/dist/__tests__/auth-guard.test.js.map +1 -1
- package/dist/__tests__/bootstrap.test.js +23 -0
- package/dist/__tests__/bootstrap.test.js.map +1 -1
- package/dist/__tests__/daemon-hub-resilience.test.js +2 -2
- package/dist/__tests__/daemon-hub-resilience.test.js.map +1 -1
- package/dist/__tests__/evicted-cleanup.test.js.map +1 -1
- package/dist/__tests__/injector.test.js +47 -4
- package/dist/__tests__/injector.test.js.map +1 -1
- package/dist/__tests__/list.test.d.ts +1 -0
- package/dist/__tests__/list.test.js +62 -0
- package/dist/__tests__/list.test.js.map +1 -0
- package/dist/__tests__/opencode-serve.test.d.ts +1 -0
- package/dist/__tests__/opencode-serve.test.js +54 -0
- package/dist/__tests__/opencode-serve.test.js.map +1 -0
- package/dist/__tests__/opencode-session-policy.test.d.ts +1 -0
- package/dist/__tests__/opencode-session-policy.test.js +61 -0
- package/dist/__tests__/opencode-session-policy.test.js.map +1 -0
- package/dist/__tests__/opencode-session.test.d.ts +1 -0
- package/dist/__tests__/opencode-session.test.js +178 -0
- package/dist/__tests__/opencode-session.test.js.map +1 -0
- package/dist/__tests__/registry.register.test.js +16 -0
- package/dist/__tests__/registry.register.test.js.map +1 -1
- package/dist/__tests__/relay.test.js +121 -2
- package/dist/__tests__/relay.test.js.map +1 -1
- package/dist/__tests__/shared-resource-guards.test.js +1 -4
- package/dist/__tests__/shared-resource-guards.test.js.map +1 -1
- package/dist/__tests__/start-team-id.test.js +22 -0
- package/dist/__tests__/start-team-id.test.js.map +1 -1
- package/dist/__tests__/token-rejection-recovery.test.js +52 -0
- package/dist/__tests__/token-rejection-recovery.test.js.map +1 -1
- package/dist/__tests__/watcher-queue.test.js +7 -2
- package/dist/__tests__/watcher-queue.test.js.map +1 -1
- package/dist/cli/attach.d.ts +1 -1
- package/dist/cli/attach.js +125 -2
- package/dist/cli/attach.js.map +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli/index.js +9 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/list.js +26 -2
- package/dist/cli/list.js.map +1 -1
- package/dist/cli/relay.d.ts +3 -0
- package/dist/cli/relay.js +149 -1
- package/dist/cli/relay.js.map +1 -1
- package/dist/cli/start.d.ts +9 -1
- package/dist/cli/start.js +8 -0
- package/dist/cli/start.js.map +1 -1
- package/dist/cli/status.js +21 -8
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/test.js +12 -1
- package/dist/cli/test.js.map +1 -1
- package/dist/config/schema.d.ts +16 -0
- package/dist/core/auth-guard.js +2 -2
- package/dist/core/auth-guard.js.map +1 -1
- package/dist/core/chat-output-parser.d.ts +3 -3
- package/dist/core/chat-output-parser.js +35 -19
- package/dist/core/chat-output-parser.js.map +1 -1
- package/dist/core/chat-output-parser.test.js +21 -0
- package/dist/core/chat-output-parser.test.js.map +1 -1
- package/dist/core/daemon/bootstrap.d.ts +8 -0
- package/dist/core/daemon/bootstrap.js +6 -1
- package/dist/core/daemon/bootstrap.js.map +1 -1
- package/dist/core/daemon/state.d.ts +8 -0
- package/dist/core/daemon/state.js +8 -0
- package/dist/core/daemon/state.js.map +1 -1
- package/dist/core/daemon/tmux-session.d.ts +4 -0
- package/dist/core/daemon/tmux-session.js +9 -1
- package/dist/core/daemon/tmux-session.js.map +1 -1
- package/dist/core/daemon/workspace.js +10 -2
- package/dist/core/daemon/workspace.js.map +1 -1
- package/dist/core/daemon.d.ts +10 -1
- package/dist/core/daemon.js +155 -18
- package/dist/core/daemon.js.map +1 -1
- package/dist/core/handoff-sla.js +1 -1
- package/dist/core/handoff-sla.js.map +1 -1
- package/dist/core/injector.d.ts +2 -0
- package/dist/core/injector.js +107 -49
- package/dist/core/injector.js.map +1 -1
- package/dist/core/opencode-serve.d.ts +26 -0
- package/dist/core/opencode-serve.js +97 -0
- package/dist/core/opencode-serve.js.map +1 -0
- package/dist/core/opencode-session-policy.d.ts +10 -0
- package/dist/core/opencode-session-policy.js +10 -0
- package/dist/core/opencode-session-policy.js.map +1 -0
- package/dist/core/opencode-session.d.ts +12 -0
- package/dist/core/opencode-session.js +165 -0
- package/dist/core/opencode-session.js.map +1 -0
- package/dist/core/registry.d.ts +2 -1
- package/dist/core/registry.js +3 -2
- package/dist/core/registry.js.map +1 -1
- package/dist/core/tmux-runtime.d.ts +1 -0
- package/dist/core/tmux-runtime.js +4 -1
- package/dist/core/tmux-runtime.js.map +1 -1
- package/dist/core/tmux.js +5 -0
- package/dist/core/tmux.js.map +1 -1
- package/dist/runtime/adapters/opencode.d.ts +63 -0
- package/dist/runtime/adapters/opencode.js +358 -0
- package/dist/runtime/adapters/opencode.js.map +1 -0
- package/dist/runtime/adapters/tmux-fallback.d.ts +23 -0
- package/dist/runtime/adapters/tmux-fallback.js +148 -0
- package/dist/runtime/adapters/tmux-fallback.js.map +1 -0
- package/dist/runtime/adapters/tmux-fallback.test.d.ts +4 -0
- package/dist/runtime/adapters/tmux-fallback.test.js +91 -0
- package/dist/runtime/adapters/tmux-fallback.test.js.map +1 -0
- package/dist/runtime/index.d.ts +146 -0
- package/dist/runtime/index.js +191 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/registry.d.ts +53 -0
- package/dist/runtime/registry.js +112 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime/registry.test.d.ts +4 -0
- package/dist/runtime/registry.test.js +69 -0
- package/dist/runtime/registry.test.js.map +1 -0
- package/dist/runtime/types.d.ts +158 -0
- package/dist/runtime/types.js +8 -0
- package/dist/runtime/types.js.map +1 -0
- 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,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
|