@agentmeshhq/agent 0.4.16 → 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/LICENSE +21 -0
- 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__/injection-verify.test.d.ts +1 -0
- package/dist/__tests__/injection-verify.test.js +93 -0
- package/dist/__tests__/injection-verify.test.js.map +1 -0
- package/dist/__tests__/injector.test.js +124 -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.d.ts +1 -0
- package/dist/__tests__/relay.test.js +136 -0
- package/dist/__tests__/relay.test.js.map +1 -0
- package/dist/__tests__/runner.test.js +17 -0
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/__tests__/session-recovery.test.js +214 -11
- package/dist/__tests__/session-recovery.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__/startup-diagnostics.test.d.ts +1 -0
- package/dist/__tests__/startup-diagnostics.test.js +250 -0
- package/dist/__tests__/startup-diagnostics.test.js.map +1 -0
- package/dist/__tests__/tmux-runtime.test.js +13 -0
- package/dist/__tests__/tmux-runtime.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.d.ts +1 -0
- package/dist/__tests__/watcher-queue.test.js +90 -0
- package/dist/__tests__/watcher-queue.test.js.map +1 -0
- package/dist/__tests__/watcher-state.test.d.ts +1 -0
- package/dist/__tests__/watcher-state.test.js +159 -0
- package/dist/__tests__/watcher-state.test.js.map +1 -0
- 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/commands.d.ts +32 -0
- package/dist/cli/commands.js +165 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/index.js +97 -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 +4 -0
- package/dist/cli/relay.js +165 -3
- 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 +17 -1
- 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 +24 -0
- package/dist/core/chat-output-parser.js +150 -0
- package/dist/core/chat-output-parser.js.map +1 -0
- package/dist/core/chat-output-parser.test.d.ts +7 -0
- package/dist/core/chat-output-parser.test.js +151 -0
- package/dist/core/chat-output-parser.test.js.map +1 -0
- 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/crash-log.js +5 -0
- package/dist/core/daemon/crash-log.js.map +1 -1
- package/dist/core/daemon/injection-verify.d.ts +25 -0
- package/dist/core/daemon/injection-verify.js +94 -0
- package/dist/core/daemon/injection-verify.js.map +1 -0
- package/dist/core/daemon/roles.d.ts +2 -2
- package/dist/core/daemon/roles.js +3 -0
- package/dist/core/daemon/roles.js.map +1 -1
- package/dist/core/daemon/session-recovery.d.ts +18 -1
- package/dist/core/daemon/session-recovery.js +89 -5
- package/dist/core/daemon/session-recovery.js.map +1 -1
- package/dist/core/daemon/startup-diagnostics.d.ts +76 -0
- package/dist/core/daemon/startup-diagnostics.js +277 -0
- package/dist/core/daemon/startup-diagnostics.js.map +1 -0
- 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/watcher-loop.d.ts +27 -0
- package/dist/core/daemon/watcher-loop.js +134 -0
- package/dist/core/daemon/watcher-loop.js.map +1 -0
- package/dist/core/daemon/watcher-queue.d.ts +33 -0
- package/dist/core/daemon/watcher-queue.js +71 -0
- package/dist/core/daemon/watcher-queue.js.map +1 -0
- package/dist/core/daemon/watcher-state.d.ts +66 -0
- package/dist/core/daemon/watcher-state.js +151 -0
- package/dist/core/daemon/watcher-state.js.map +1 -0
- package/dist/core/daemon/workspace.js +10 -2
- package/dist/core/daemon/workspace.js.map +1 -1
- package/dist/core/daemon.d.ts +22 -1
- package/dist/core/daemon.js +289 -20
- 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 +227 -32
- 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/runner/build.js +7 -31
- package/dist/core/runner/build.js.map +1 -1
- package/dist/core/runner/detect.js +2 -8
- package/dist/core/runner/detect.js.map +1 -1
- package/dist/core/runner/index.d.ts +3 -1
- package/dist/core/runner/index.js +2 -0
- package/dist/core/runner/index.js.map +1 -1
- package/dist/core/runner/kimi-models.d.ts +4 -0
- package/dist/core/runner/kimi-models.js +24 -0
- package/dist/core/runner/kimi-models.js.map +1 -0
- package/dist/core/runner/registry.d.ts +3 -0
- package/dist/core/runner/registry.js +75 -0
- package/dist/core/runner/registry.js.map +1 -0
- package/dist/core/runner/types.d.ts +17 -1
- package/dist/core/tmux-runtime.d.ts +2 -1
- package/dist/core/tmux-runtime.js +17 -1
- package/dist/core/tmux-runtime.js.map +1 -1
- package/dist/core/tmux.d.ts +4 -0
- package/dist/core/tmux.js +54 -11
- 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 +11 -12
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts clean LLM reply from raw tmux capture.
|
|
3
|
+
*
|
|
4
|
+
* Raw tmux output includes:
|
|
5
|
+
* - Welcome screen with logo
|
|
6
|
+
* - Prompt characters (❯ for input, ⏺ for output)
|
|
7
|
+
* - ANSI escape codes for colors/formatting
|
|
8
|
+
* - Box-drawing characters
|
|
9
|
+
*
|
|
10
|
+
* This parser identifies the LLM's response block and strips all chrome.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Remove ANSI escape codes (colors, formatting, etc.)
|
|
14
|
+
*/
|
|
15
|
+
function stripAnsiCodes(text) {
|
|
16
|
+
// Match ESC[ ... (letter|number) patterns
|
|
17
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: ESC is needed for ANSI parsing
|
|
18
|
+
return text.replace(/\u001b\[[0-9;]*[a-zA-Z]/g, "");
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Check if a line is tmux chrome (logo, box-drawing, etc.)
|
|
22
|
+
*/
|
|
23
|
+
function isTmuxChrome(line) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
// Empty lines are not chrome
|
|
26
|
+
if (trimmed.length === 0)
|
|
27
|
+
return false;
|
|
28
|
+
// Claude Code logo lines (▐▛███▜▌, ▝▜█████▛▘, etc.)
|
|
29
|
+
if (/^[▐▛███▜▌▝█]*\s*Claude Code/.test(trimmed))
|
|
30
|
+
return true;
|
|
31
|
+
if (/^[▛███▜▌▝█]*\s*Haiku|Sonnet|Opus|Claude/.test(trimmed))
|
|
32
|
+
return true;
|
|
33
|
+
if (/^[▘▝]*\s*$/.test(trimmed))
|
|
34
|
+
return true;
|
|
35
|
+
// Pure box drawing / special characters
|
|
36
|
+
if (/^[╔╗╚╝═║├┤┬┴┼▐▛███▜▌▝█\s]*$/.test(trimmed))
|
|
37
|
+
return true;
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a line starts with a prompt character.
|
|
42
|
+
* Input prompts:
|
|
43
|
+
* - ❯ (Claude)
|
|
44
|
+
* - › (Codex/OpenCode)
|
|
45
|
+
* Output prompts:
|
|
46
|
+
* - ⏺ (Claude)
|
|
47
|
+
* - • (Codex/OpenCode)
|
|
48
|
+
*/
|
|
49
|
+
function getPromptType(line) {
|
|
50
|
+
const trimmed = line.trim();
|
|
51
|
+
if (trimmed.startsWith("❯") || trimmed.startsWith("›"))
|
|
52
|
+
return "input";
|
|
53
|
+
if (trimmed.startsWith("⏺") || trimmed.startsWith("•"))
|
|
54
|
+
return "output";
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extract the message content after a prompt character.
|
|
59
|
+
* Removes the prompt character and leading/trailing whitespace.
|
|
60
|
+
*/
|
|
61
|
+
function extractMessageAfterPrompt(line) {
|
|
62
|
+
const trimmed = line.trim();
|
|
63
|
+
// Remove ❯/›/⏺/• and following space(s)
|
|
64
|
+
return trimmed.replace(/^[❯›⏺•]\s+/, "").trim();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Main parser: extract clean LLM reply from raw tmux capture.
|
|
68
|
+
*
|
|
69
|
+
* Strategy:
|
|
70
|
+
* 1. Split into lines
|
|
71
|
+
* 2. Remove ANSI codes
|
|
72
|
+
* 3. Find the last input prompt (most recent user turn)
|
|
73
|
+
* 4. Extract all output lines after that input prompt
|
|
74
|
+
* 5. Stop at the next input prompt (if any)
|
|
75
|
+
*
|
|
76
|
+
* Returns the clean reply text, or empty string if no reply found.
|
|
77
|
+
*/
|
|
78
|
+
export function extractLLMReply(rawOutput) {
|
|
79
|
+
if (!rawOutput || rawOutput.trim().length === 0) {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
const lines = rawOutput.split("\n");
|
|
83
|
+
// Step 1: Remove ANSI codes and filter out tmux chrome
|
|
84
|
+
const cleaned = [];
|
|
85
|
+
for (const line of lines) {
|
|
86
|
+
const noAnsi = stripAnsiCodes(line);
|
|
87
|
+
if (isTmuxChrome(noAnsi)) {
|
|
88
|
+
// Skip pure chrome lines, but keep track of them in the array
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const promptType = getPromptType(noAnsi);
|
|
92
|
+
cleaned.push({
|
|
93
|
+
original: line,
|
|
94
|
+
text: noAnsi,
|
|
95
|
+
promptType,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Step 2: Anchor extraction after the most recent input prompt.
|
|
99
|
+
// This preserves multi-line Codex/OpenCode replies where each line starts with "•".
|
|
100
|
+
let startSearchIdx = 0;
|
|
101
|
+
for (let i = cleaned.length - 1; i >= 0; i--) {
|
|
102
|
+
if (cleaned[i].promptType === "input") {
|
|
103
|
+
startSearchIdx = i + 1;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Step 3: Find the first output prompt after the latest input turn.
|
|
108
|
+
let firstOutputIdx = -1;
|
|
109
|
+
for (let i = startSearchIdx; i < cleaned.length; i++) {
|
|
110
|
+
if (cleaned[i].promptType === "output") {
|
|
111
|
+
firstOutputIdx = i;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (firstOutputIdx === -1) {
|
|
116
|
+
// No output prompt found — maybe the response hasn't started yet
|
|
117
|
+
return "";
|
|
118
|
+
}
|
|
119
|
+
// Step 4: Extract content starting from the first output prompt.
|
|
120
|
+
const replyLines = [];
|
|
121
|
+
// Add the message from the output prompt line
|
|
122
|
+
const firstMsg = extractMessageAfterPrompt(cleaned[firstOutputIdx].text);
|
|
123
|
+
if (firstMsg) {
|
|
124
|
+
replyLines.push(firstMsg);
|
|
125
|
+
}
|
|
126
|
+
// Step 5: Continue collecting lines until the next input prompt or end of buffer.
|
|
127
|
+
for (let i = firstOutputIdx + 1; i < cleaned.length; i++) {
|
|
128
|
+
if (cleaned[i].promptType === "input") {
|
|
129
|
+
// Stop at the next input prompt
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
// If this line has a prompt marker but it's not an input, skip the marker
|
|
133
|
+
if (cleaned[i].promptType === "output") {
|
|
134
|
+
const msg = extractMessageAfterPrompt(cleaned[i].text);
|
|
135
|
+
if (msg) {
|
|
136
|
+
replyLines.push(msg);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// Regular continuation line
|
|
141
|
+
const continuation = cleaned[i].text.trim();
|
|
142
|
+
if (continuation.length > 0) {
|
|
143
|
+
replyLines.push(continuation);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Step 6: Join and return
|
|
148
|
+
return replyLines.join("\n").trim();
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=chat-output-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-output-parser.js","sourceRoot":"","sources":["../../src/core/chat-output-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for chat-output-parser (GH-891 Phase 1)
|
|
3
|
+
*
|
|
4
|
+
* Tests extraction of clean LLM replies from raw tmux capture,
|
|
5
|
+
* including removal of ANSI codes, prompt characters, and tmux chrome.
|
|
6
|
+
*/
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import test from "node:test";
|
|
9
|
+
import { extractLLMReply } from "./chat-output-parser.js";
|
|
10
|
+
test("extractLLMReply - basic reply extraction", () => {
|
|
11
|
+
const raw = `▐▛███▜▌ Claude Code v2.1.88
|
|
12
|
+
▝▜█████▛▘ Haiku 4.5 with high effort · Claude Max
|
|
13
|
+
▘▘ ▝▝ ~/Dev/agentmesh-mesh-dev-2
|
|
14
|
+
|
|
15
|
+
❯ [AgentMesh] Connected and ready...
|
|
16
|
+
⏺ Ready and connected. I understand the system...
|
|
17
|
+
❯ ping - test chat
|
|
18
|
+
⏺ Pong. Chat is live and connected. Ready to assist.
|
|
19
|
+
❯ `;
|
|
20
|
+
const result = extractLLMReply(raw);
|
|
21
|
+
assert.strictEqual(result, "Pong. Chat is live and connected. Ready to assist.");
|
|
22
|
+
});
|
|
23
|
+
test("extractLLMReply - multi-line response", () => {
|
|
24
|
+
const raw = `❯ tell me a story
|
|
25
|
+
⏺ Once upon a time,
|
|
26
|
+
there was a kingdom.
|
|
27
|
+
❯ `;
|
|
28
|
+
const result = extractLLMReply(raw);
|
|
29
|
+
assert.strictEqual(result, "Once upon a time,\nthere was a kingdom.");
|
|
30
|
+
});
|
|
31
|
+
test("extractLLMReply - strips ANSI codes", () => {
|
|
32
|
+
const raw = `❯ hello
|
|
33
|
+
⏺ \x1b[32mGreen\x1b[0m text
|
|
34
|
+
❯ `;
|
|
35
|
+
const result = extractLLMReply(raw);
|
|
36
|
+
assert.strictEqual(result, "Green text");
|
|
37
|
+
});
|
|
38
|
+
test("extractLLMReply - handles empty input", () => {
|
|
39
|
+
const result = extractLLMReply("");
|
|
40
|
+
assert.strictEqual(result, "");
|
|
41
|
+
});
|
|
42
|
+
test("extractLLMReply - handles whitespace-only input", () => {
|
|
43
|
+
const result = extractLLMReply(" \n \n ");
|
|
44
|
+
assert.strictEqual(result, "");
|
|
45
|
+
});
|
|
46
|
+
test("extractLLMReply - no output prompt found", () => {
|
|
47
|
+
const raw = `❯ hello
|
|
48
|
+
some random text`;
|
|
49
|
+
const result = extractLLMReply(raw);
|
|
50
|
+
assert.strictEqual(result, "");
|
|
51
|
+
});
|
|
52
|
+
test("extractLLMReply - strips logo and chrome", () => {
|
|
53
|
+
const raw = `▐▛███▜▌ Claude Code v2.1.88
|
|
54
|
+
▝▜█████▛▘ Sonnet 4.6 · High Effort
|
|
55
|
+
▘▘ ▝▝ ~/project
|
|
56
|
+
|
|
57
|
+
❯ test
|
|
58
|
+
⏺ Clean output
|
|
59
|
+
❯ `;
|
|
60
|
+
const result = extractLLMReply(raw);
|
|
61
|
+
assert.strictEqual(result, "Clean output");
|
|
62
|
+
});
|
|
63
|
+
test("extractLLMReply - response with blank lines", () => {
|
|
64
|
+
const raw = `❯ query
|
|
65
|
+
⏺ First paragraph.
|
|
66
|
+
|
|
67
|
+
Second paragraph.
|
|
68
|
+
❯ `;
|
|
69
|
+
const result = extractLLMReply(raw);
|
|
70
|
+
// Empty lines between paragraphs should be preserved
|
|
71
|
+
assert.strictEqual(result, "First paragraph.\n\nSecond paragraph.");
|
|
72
|
+
});
|
|
73
|
+
test("extractLLMReply - last output prompt wins", () => {
|
|
74
|
+
const raw = `❯ first
|
|
75
|
+
⏺ First reply
|
|
76
|
+
❯ second
|
|
77
|
+
⏺ Second reply
|
|
78
|
+
❯ `;
|
|
79
|
+
const result = extractLLMReply(raw);
|
|
80
|
+
assert.strictEqual(result, "Second reply");
|
|
81
|
+
});
|
|
82
|
+
test("extractLLMReply - handles trailing empty lines", () => {
|
|
83
|
+
const raw = `❯ hello
|
|
84
|
+
⏺ Response
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
❯ `;
|
|
88
|
+
const result = extractLLMReply(raw);
|
|
89
|
+
assert.strictEqual(result, "Response");
|
|
90
|
+
});
|
|
91
|
+
test("extractLLMReply - only extracts until next input prompt", () => {
|
|
92
|
+
const raw = `❯ first query
|
|
93
|
+
⏺ Response to first
|
|
94
|
+
More response content
|
|
95
|
+
❯ second query`;
|
|
96
|
+
const result = extractLLMReply(raw);
|
|
97
|
+
assert.strictEqual(result, "Response to first\nMore response content");
|
|
98
|
+
});
|
|
99
|
+
test("extractLLMReply - complex real-world example", () => {
|
|
100
|
+
const raw = `▐▛███▜▌ Claude Code v2.1.88
|
|
101
|
+
▝▜█████▛▘ Haiku 4.5 · High Effort
|
|
102
|
+
▘▘ ▝▝ ~/Dev/project
|
|
103
|
+
|
|
104
|
+
❯ [Handoff] Task: implement feature X
|
|
105
|
+
⏺ I understand. Let me start by reading the requirements.
|
|
106
|
+
❯ [User] What's your plan?
|
|
107
|
+
⏺ Here's my plan:
|
|
108
|
+
|
|
109
|
+
1. Read the specification
|
|
110
|
+
2. Create tests
|
|
111
|
+
3. Implement the feature
|
|
112
|
+
|
|
113
|
+
I'll start now.
|
|
114
|
+
❯ `;
|
|
115
|
+
const result = extractLLMReply(raw);
|
|
116
|
+
const expected = "Here's my plan:\n\n1. Read the specification\n2. Create tests\n3. Implement the feature\n\nI'll start now.";
|
|
117
|
+
assert.strictEqual(result, expected);
|
|
118
|
+
});
|
|
119
|
+
test("extractLLMReply - handles colored box-drawing characters", () => {
|
|
120
|
+
const raw = `╔════════════════════════════╗
|
|
121
|
+
║ Claude Code v2 ║
|
|
122
|
+
╚════════════════════════════╝
|
|
123
|
+
|
|
124
|
+
❯ command
|
|
125
|
+
⏺ Result
|
|
126
|
+
❯ `;
|
|
127
|
+
const result = extractLLMReply(raw);
|
|
128
|
+
assert.strictEqual(result, "Result");
|
|
129
|
+
});
|
|
130
|
+
test("extractLLMReply - codex prompt markers (›/•)", () => {
|
|
131
|
+
const raw = `› Hello!
|
|
132
|
+
• Hi. What do you want to work on in this repo?
|
|
133
|
+
› Summarize recent commits
|
|
134
|
+
• Sure — here's a quick summary:
|
|
135
|
+
• - Added runtime chat ACK wiring
|
|
136
|
+
• - Fixed local workspace routing
|
|
137
|
+
› `;
|
|
138
|
+
const result = extractLLMReply(raw);
|
|
139
|
+
assert.strictEqual(result, "Sure — here's a quick summary:\n- Added runtime chat ACK wiring\n- Fixed local workspace routing");
|
|
140
|
+
});
|
|
141
|
+
test("extractLLMReply - codex multiline output continuation", () => {
|
|
142
|
+
const raw = `› Plan this work
|
|
143
|
+
• Here's a concrete plan:
|
|
144
|
+
1. Reproduce the issue.
|
|
145
|
+
2. Patch parser.
|
|
146
|
+
3. Validate E2E.
|
|
147
|
+
› `;
|
|
148
|
+
const result = extractLLMReply(raw);
|
|
149
|
+
assert.strictEqual(result, "Here's a concrete plan:\n1. Reproduce the issue.\n2. Patch parser.\n3. Validate E2E.");
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=chat-output-parser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-output-parser.test.js","sourceRoot":"","sources":["../../src/core/chat-output-parser.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,10 @@ export interface BootstrapOptions {
|
|
|
10
10
|
autoSetup?: boolean;
|
|
11
11
|
serve?: boolean;
|
|
12
12
|
servePort?: number;
|
|
13
|
+
serveHostname?: string;
|
|
14
|
+
servePublicUrl?: string;
|
|
15
|
+
serveUsername?: string;
|
|
16
|
+
servePasswordEnv?: string;
|
|
13
17
|
sandbox?: boolean;
|
|
14
18
|
sandboxImage?: string;
|
|
15
19
|
sandboxCpu?: string;
|
|
@@ -27,6 +31,10 @@ export interface DaemonBootstrap {
|
|
|
27
31
|
autoSetup: boolean;
|
|
28
32
|
serveMode: boolean;
|
|
29
33
|
servePort: number;
|
|
34
|
+
serveHostname: string;
|
|
35
|
+
servePublicUrl?: string;
|
|
36
|
+
serveUsername?: string;
|
|
37
|
+
servePasswordEnv?: string;
|
|
30
38
|
sandboxMode: boolean;
|
|
31
39
|
sandboxImage: string;
|
|
32
40
|
sandboxCpu: string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadConfig } from "../../config/loader.js";
|
|
2
|
+
import { DEFAULT_OPENCODE_SERVE_HOSTNAME, DEFAULT_OPENCODE_SERVE_PORT } from "../opencode-serve.js";
|
|
2
3
|
import { buildRunnerConfig } from "../runner.js";
|
|
3
4
|
import { isKnownRole, ROLE_DAEMON_BEHAVIOUR } from "./roles.js";
|
|
4
5
|
/**
|
|
@@ -60,7 +61,11 @@ export function bootstrapDaemon(options) {
|
|
|
60
61
|
isWorkerAgent: workerMode,
|
|
61
62
|
autoSetup: options.autoSetup === true,
|
|
62
63
|
serveMode: options.serve === true,
|
|
63
|
-
servePort: options.servePort ||
|
|
64
|
+
servePort: options.servePort || DEFAULT_OPENCODE_SERVE_PORT,
|
|
65
|
+
serveHostname: options.serveHostname || DEFAULT_OPENCODE_SERVE_HOSTNAME,
|
|
66
|
+
servePublicUrl: options.servePublicUrl?.trim() || undefined,
|
|
67
|
+
serveUsername: options.serveUsername?.trim() || undefined,
|
|
68
|
+
servePasswordEnv: options.servePasswordEnv?.trim() || undefined,
|
|
64
69
|
sandboxMode: options.sandbox === true,
|
|
65
70
|
sandboxImage: options.sandboxImage || "agentmesh/agent-sandbox:latest",
|
|
66
71
|
sandboxCpu: options.sandboxCpu || "1",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../../src/core/daemon/bootstrap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpD,OAAO,EAAE,iBAAiB,EAAqB,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../../src/core/daemon/bootstrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { formatDiagnosticSummary } from "./startup-diagnostics.js";
|
|
1
2
|
/**
|
|
2
3
|
* Formats a structured crash entry for on-disk diagnostics.
|
|
3
4
|
*/
|
|
4
5
|
export function formatCrashLog(input) {
|
|
6
|
+
// Include startup diagnostics if available
|
|
7
|
+
const startupDiagnostics = formatDiagnosticSummary(input.agentName);
|
|
5
8
|
return `
|
|
6
9
|
================================================================================
|
|
7
10
|
AGENT CRASH DETECTED
|
|
@@ -14,6 +17,8 @@ Sandbox: ${input.sandboxLabel}
|
|
|
14
17
|
Workdir: ${input.workdir}
|
|
15
18
|
Model: ${input.model}
|
|
16
19
|
|
|
20
|
+
${startupDiagnostics}
|
|
21
|
+
|
|
17
22
|
--- Last Session Output ---
|
|
18
23
|
${input.lastOutput}
|
|
19
24
|
================================================================================
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crash-log.js","sourceRoot":"","sources":["../../../src/core/daemon/crash-log.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"crash-log.js","sourceRoot":"","sources":["../../../src/core/daemon/crash-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAanE;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAoB;IACjD,2CAA2C;IAC3C,MAAM,kBAAkB,GAAG,uBAAuB,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEpE,OAAO;;;;aAII,KAAK,CAAC,SAAS;SACnB,KAAK,CAAC,SAAS;YACZ,KAAK,CAAC,OAAO;UACf,KAAK,CAAC,MAAM;WACX,KAAK,CAAC,YAAY;WAClB,KAAK,CAAC,OAAO;SACf,KAAK,CAAC,KAAK;;EAElB,kBAAkB;;;EAGlB,KAAK,CAAC,UAAU;;;CAGjB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handoff injection verification — confirms the LLM actually started
|
|
3
|
+
* processing an injected handoff by monitoring tmux output changes.
|
|
4
|
+
*
|
|
5
|
+
* Also detects rate-limit patterns to pause auto-acceptance.
|
|
6
|
+
*
|
|
7
|
+
* Epic #887
|
|
8
|
+
*/
|
|
9
|
+
export interface InjectionResult {
|
|
10
|
+
verified: boolean;
|
|
11
|
+
rateLimited: boolean;
|
|
12
|
+
attempts: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* After injecting a handoff into tmux, poll output to verify the LLM
|
|
16
|
+
* acknowledged it. Re-injects up to maxRetries times if no activity.
|
|
17
|
+
*
|
|
18
|
+
* Returns whether the injection was verified, and whether a rate limit
|
|
19
|
+
* was detected.
|
|
20
|
+
*/
|
|
21
|
+
export declare function verifyInjection(agentName: string, handoffId: string, handoffScope: string, maxRetries?: number): Promise<InjectionResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Scan tmux output for rate-limit indicators.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isRateLimited(output: string): boolean;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handoff injection verification — confirms the LLM actually started
|
|
3
|
+
* processing an injected handoff by monitoring tmux output changes.
|
|
4
|
+
*
|
|
5
|
+
* Also detects rate-limit patterns to pause auto-acceptance.
|
|
6
|
+
*
|
|
7
|
+
* Epic #887
|
|
8
|
+
*/
|
|
9
|
+
import { captureSessionOutput, sendKeys } from "../tmux.js";
|
|
10
|
+
const RATE_LIMIT_PATTERNS = [
|
|
11
|
+
"hit your limit",
|
|
12
|
+
"rate limit",
|
|
13
|
+
"resets ",
|
|
14
|
+
"usage limit",
|
|
15
|
+
"too many requests",
|
|
16
|
+
"quota exceeded",
|
|
17
|
+
];
|
|
18
|
+
/**
|
|
19
|
+
* After injecting a handoff into tmux, poll output to verify the LLM
|
|
20
|
+
* acknowledged it. Re-injects up to maxRetries times if no activity.
|
|
21
|
+
*
|
|
22
|
+
* Returns whether the injection was verified, and whether a rate limit
|
|
23
|
+
* was detected.
|
|
24
|
+
*/
|
|
25
|
+
export async function verifyInjection(agentName, handoffId, handoffScope, maxRetries = 2) {
|
|
26
|
+
const result = { verified: false, rateLimited: false, attempts: 1 };
|
|
27
|
+
// Capture baseline output before checking
|
|
28
|
+
const baseline = captureSessionOutput(agentName, 30) || "";
|
|
29
|
+
// Check for rate limit in current output
|
|
30
|
+
if (isRateLimited(baseline)) {
|
|
31
|
+
console.log(`[INJECT-VERIFY] Rate limit detected for ${agentName}`);
|
|
32
|
+
result.rateLimited = true;
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
// Wait and check if output changed (LLM is processing)
|
|
36
|
+
const verified = await pollForActivity(agentName, baseline, 30_000);
|
|
37
|
+
if (verified) {
|
|
38
|
+
result.verified = true;
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
// No activity — retry injection
|
|
42
|
+
for (let retry = 0; retry < maxRetries; retry++) {
|
|
43
|
+
result.attempts += 1;
|
|
44
|
+
console.log(`[INJECT-VERIFY] Re-injecting handoff ${handoffId} (attempt ${result.attempts})`);
|
|
45
|
+
const reminderMsg = `[AgentMesh] Reminder: You accepted handoff ${handoffId}. Scope: ${handoffScope}. Please start working on it.`;
|
|
46
|
+
const sent = sendKeys(agentName, reminderMsg);
|
|
47
|
+
if (!sent) {
|
|
48
|
+
console.warn(`[INJECT-VERIFY] Failed to re-inject into ${agentName}`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// Wait a bit then check output
|
|
52
|
+
await sleep(5000);
|
|
53
|
+
const current = captureSessionOutput(agentName, 30) || "";
|
|
54
|
+
// Check rate limit after re-injection
|
|
55
|
+
if (isRateLimited(current)) {
|
|
56
|
+
console.log(`[INJECT-VERIFY] Rate limit detected after retry for ${agentName}`);
|
|
57
|
+
result.rateLimited = true;
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
const retryVerified = await pollForActivity(agentName, current, 20_000);
|
|
61
|
+
if (retryVerified) {
|
|
62
|
+
result.verified = true;
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
console.warn(`[INJECT-VERIFY] Handoff ${handoffId} not verified after ${result.attempts} attempts`);
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Scan tmux output for rate-limit indicators.
|
|
71
|
+
*/
|
|
72
|
+
export function isRateLimited(output) {
|
|
73
|
+
const lower = output.toLowerCase();
|
|
74
|
+
return RATE_LIMIT_PATTERNS.some((pattern) => lower.includes(pattern));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Poll tmux output for changes over a duration. Returns true if output changes.
|
|
78
|
+
*/
|
|
79
|
+
async function pollForActivity(agentName, baseline, durationMs) {
|
|
80
|
+
const pollInterval = 5000;
|
|
81
|
+
const polls = Math.ceil(durationMs / pollInterval);
|
|
82
|
+
for (let i = 0; i < polls; i++) {
|
|
83
|
+
await sleep(pollInterval);
|
|
84
|
+
const current = captureSessionOutput(agentName, 30) || "";
|
|
85
|
+
if (current !== baseline) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function sleep(ms) {
|
|
92
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=injection-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection-verify.js","sourceRoot":"","sources":["../../../src/core/daemon/injection-verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/** Canonical set of predefined roles. Free-form strings are still accepted for
|
|
8
8
|
* hub auto-assignment but will not activate role-specific daemon behaviour. */
|
|
9
|
-
export type AgentRole = "coordinator" | "developer" | "reviewer" | "lead" | "observer";
|
|
9
|
+
export type AgentRole = "coordinator" | "developer" | "reviewer" | "lead" | "observer" | "watcher";
|
|
10
10
|
export declare const VALID_ROLES: readonly AgentRole[];
|
|
11
11
|
export declare function isKnownRole(role: string): role is AgentRole;
|
|
12
12
|
/**
|
|
@@ -22,4 +22,4 @@ export declare const ROLE_SYSTEM_PROMPTS: Record<AgentRole, string>;
|
|
|
22
22
|
*
|
|
23
23
|
* Replaces inferAttendedFromRole() in bootstrap.ts for known roles.
|
|
24
24
|
*/
|
|
25
|
-
export declare const ROLE_DAEMON_BEHAVIOUR: Record<AgentRole, "lead-loop" | "worker" | "observer">;
|
|
25
|
+
export declare const ROLE_DAEMON_BEHAVIOUR: Record<AgentRole, "lead-loop" | "worker" | "observer" | "watcher-loop">;
|
|
@@ -10,6 +10,7 @@ export const VALID_ROLES = [
|
|
|
10
10
|
"reviewer",
|
|
11
11
|
"lead",
|
|
12
12
|
"observer",
|
|
13
|
+
"watcher",
|
|
13
14
|
];
|
|
14
15
|
export function isKnownRole(role) {
|
|
15
16
|
return VALID_ROLES.includes(role);
|
|
@@ -24,6 +25,7 @@ export const ROLE_SYSTEM_PROMPTS = {
|
|
|
24
25
|
reviewer: "You are a reviewer agent. Your job is to review pull requests and handoff proposals for correctness, quality, and consistency. Approve, request changes, or reject with clear reasoning.",
|
|
25
26
|
lead: "You are a lead agent. You coordinate the team, route work to the right agents, monitor SLAs, and escalate blockers. You also review high-level architecture decisions.",
|
|
26
27
|
observer: "You are an observer agent. You monitor team activity and provide strategic input when asked. You do not accept handoffs automatically and do not modify code directly.",
|
|
28
|
+
watcher: "You are a watcher agent. Every ~2 minutes you receive a project state snapshot showing handoffs, agent health, blockers, and claims. Analyze the state and take corrective actions using agentmesh CLI commands: nudge stuck agents, escalate breached SLAs, reassign stalled handoffs, create blockers, release stale claims. Process one tick at a time — after analysis and action, wait for the next tick. Do not take actions unprompted between ticks.",
|
|
27
29
|
};
|
|
28
30
|
/**
|
|
29
31
|
* Maps each predefined role to a daemon behaviour mode:
|
|
@@ -39,5 +41,6 @@ export const ROLE_DAEMON_BEHAVIOUR = {
|
|
|
39
41
|
reviewer: "worker",
|
|
40
42
|
lead: "lead-loop",
|
|
41
43
|
observer: "observer",
|
|
44
|
+
watcher: "watcher-loop",
|
|
42
45
|
};
|
|
43
46
|
//# sourceMappingURL=roles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../../../src/core/daemon/roles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,aAAa;IACb,WAAW;IACX,UAAU;IACV,MAAM;IACN,UAAU;
|
|
1
|
+
{"version":3,"file":"roles.js","sourceRoot":"","sources":["../../../src/core/daemon/roles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,CAAC,MAAM,WAAW,GAAyB;IAC/C,aAAa;IACb,WAAW;IACX,UAAU;IACV,MAAM;IACN,UAAU;IACV,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAQ,WAAiC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA8B;IAC5D,WAAW,EACT,8LAA8L;IAChM,SAAS,EACP,mJAAmJ;IACrJ,QAAQ,EACN,0LAA0L;IAC5L,IAAI,EAAE,wKAAwK;IAC9K,QAAQ,EACN,wKAAwK;IAC1K,OAAO,EACL,8bAA8b;CACjc,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAG9B;IACF,WAAW,EAAE,WAAW;IACxB,SAAS,EAAE,QAAQ;IACnB,QAAQ,EAAE,QAAQ;IAClB,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,UAAU;IACpB,OAAO,EAAE,cAAc;CACxB,CAAC"}
|
|
@@ -1 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { type ProcessExitEvent } from "./startup-diagnostics.js";
|
|
2
|
+
/**
|
|
3
|
+
* Gets the most recent process exit event from diagnostics
|
|
4
|
+
*/
|
|
5
|
+
export declare function getLastProcessExit(agentName: string): ProcessExitEvent | null;
|
|
6
|
+
/**
|
|
7
|
+
* Determines if a session failure is recoverable based on the reason
|
|
8
|
+
* and startup diagnostics.
|
|
9
|
+
*
|
|
10
|
+
* A failure is considered recoverable if:
|
|
11
|
+
* 1. The reason matches known recoverable patterns
|
|
12
|
+
* 2. The process exited during startup (within 15s) AND the exit event is fresh
|
|
13
|
+
* (within 60s) - this suggests a transient issue that may resolve on retry
|
|
14
|
+
*
|
|
15
|
+
* The freshness guard prevents old exit events from misclassifying unrelated
|
|
16
|
+
* future failures as recoverable.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isRecoverableSessionFailure(reason: string, agentName?: string): boolean;
|