mstro-app 0.5.1 → 0.5.5
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/PRIVACY.md +9 -9
- package/README.md +71 -28
- package/bin/commands/config.js +1 -1
- package/bin/mstro.js +55 -4
- package/dist/server/cli/eta-estimator.d.ts +55 -0
- package/dist/server/cli/eta-estimator.d.ts.map +1 -0
- package/dist/server/cli/eta-estimator.js +222 -0
- package/dist/server/cli/eta-estimator.js.map +1 -0
- package/dist/server/cli/headless/stall-assessor.d.ts +50 -0
- package/dist/server/cli/headless/stall-assessor.d.ts.map +1 -1
- package/dist/server/cli/headless/stall-assessor.js +64 -9
- package/dist/server/cli/headless/stall-assessor.js.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.d.ts +21 -0
- package/dist/server/cli/headless/tool-watchdog.d.ts.map +1 -1
- package/dist/server/cli/headless/tool-watchdog.js +19 -12
- package/dist/server/cli/headless/tool-watchdog.js.map +1 -1
- package/dist/server/cli/improvisation-history-store.d.ts.map +1 -1
- package/dist/server/cli/improvisation-history-store.js +5 -1
- package/dist/server/cli/improvisation-history-store.js.map +1 -1
- package/dist/server/cli/improvisation-output-queue.d.ts +5 -1
- package/dist/server/cli/improvisation-output-queue.d.ts.map +1 -1
- package/dist/server/cli/improvisation-output-queue.js +30 -7
- package/dist/server/cli/improvisation-output-queue.js.map +1 -1
- package/dist/server/cli/improvisation-session-manager.d.ts +29 -0
- package/dist/server/cli/improvisation-session-manager.d.ts.map +1 -1
- package/dist/server/cli/improvisation-session-manager.js +50 -1
- package/dist/server/cli/improvisation-session-manager.js.map +1 -1
- package/dist/server/cli/improvisation-types.d.ts +2 -0
- package/dist/server/cli/improvisation-types.d.ts.map +1 -1
- package/dist/server/cli/improvisation-types.js.map +1 -1
- package/dist/server/engines/EngineEvent.d.ts +126 -0
- package/dist/server/engines/EngineEvent.d.ts.map +1 -0
- package/dist/server/engines/EngineEvent.js +11 -0
- package/dist/server/engines/EngineEvent.js.map +1 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.d.ts +47 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.d.ts.map +1 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.js +338 -0
- package/dist/server/engines/claude/ClaudeCodeEngine.js.map +1 -0
- package/dist/server/engines/factory.d.ts +21 -0
- package/dist/server/engines/factory.d.ts.map +1 -0
- package/dist/server/engines/factory.js +152 -0
- package/dist/server/engines/factory.js.map +1 -0
- package/dist/server/engines/opencode/OpenCodeEngine.d.ts +148 -0
- package/dist/server/engines/opencode/OpenCodeEngine.d.ts.map +1 -0
- package/dist/server/engines/opencode/OpenCodeEngine.js +630 -0
- package/dist/server/engines/opencode/OpenCodeEngine.js.map +1 -0
- package/dist/server/engines/opencode/OpenCodeServerManager.d.ts +172 -0
- package/dist/server/engines/opencode/OpenCodeServerManager.d.ts.map +1 -0
- package/dist/server/engines/opencode/OpenCodeServerManager.js +390 -0
- package/dist/server/engines/opencode/OpenCodeServerManager.js.map +1 -0
- package/dist/server/engines/opencode/model-catalog.d.ts +94 -0
- package/dist/server/engines/opencode/model-catalog.d.ts.map +1 -0
- package/dist/server/engines/opencode/model-catalog.js +141 -0
- package/dist/server/engines/opencode/model-catalog.js.map +1 -0
- package/dist/server/engines/types.d.ts +146 -0
- package/dist/server/engines/types.d.ts.map +1 -0
- package/dist/server/engines/types.js +4 -0
- package/dist/server/engines/types.js.map +1 -0
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/mcp/bouncer-haiku.d.ts +17 -4
- package/dist/server/mcp/bouncer-haiku.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-haiku.js +8 -124
- package/dist/server/mcp/bouncer-haiku.js.map +1 -1
- package/dist/server/mcp/bouncer-integration.d.ts +45 -0
- package/dist/server/mcp/bouncer-integration.d.ts.map +1 -1
- package/dist/server/mcp/bouncer-integration.js +69 -5
- package/dist/server/mcp/bouncer-integration.js.map +1 -1
- package/dist/server/mcp/classifier/BouncerClassifier.d.ts +34 -0
- package/dist/server/mcp/classifier/BouncerClassifier.d.ts.map +1 -0
- package/dist/server/mcp/classifier/BouncerClassifier.js +4 -0
- package/dist/server/mcp/classifier/BouncerClassifier.js.map +1 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.d.ts +17 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.d.ts.map +1 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.js +142 -0
- package/dist/server/mcp/classifier/ClaudeBouncerClassifier.js.map +1 -0
- package/dist/server/mcp/classifier/OpenCodeBouncerClassifier.d.ts +68 -0
- package/dist/server/mcp/classifier/OpenCodeBouncerClassifier.d.ts.map +1 -0
- package/dist/server/mcp/classifier/OpenCodeBouncerClassifier.js +182 -0
- package/dist/server/mcp/classifier/OpenCodeBouncerClassifier.js.map +1 -0
- package/dist/server/mcp/classifier/factory.d.ts +70 -0
- package/dist/server/mcp/classifier/factory.d.ts.map +1 -0
- package/dist/server/mcp/classifier/factory.js +155 -0
- package/dist/server/mcp/classifier/factory.js.map +1 -0
- package/dist/server/services/plan/agent-resolver.d.ts +26 -0
- package/dist/server/services/plan/agent-resolver.d.ts.map +1 -0
- package/dist/server/services/plan/agent-resolver.js +102 -0
- package/dist/server/services/plan/agent-resolver.js.map +1 -0
- package/dist/server/services/plan/composer.d.ts.map +1 -1
- package/dist/server/services/plan/composer.js +59 -11
- package/dist/server/services/plan/composer.js.map +1 -1
- package/dist/server/services/plan/executor.d.ts.map +1 -1
- package/dist/server/services/plan/executor.js +3 -1
- package/dist/server/services/plan/executor.js.map +1 -1
- package/dist/server/services/plan/issue-prompt-builder.d.ts.map +1 -1
- package/dist/server/services/plan/issue-prompt-builder.js +33 -1
- package/dist/server/services/plan/issue-prompt-builder.js.map +1 -1
- package/dist/server/services/plan/parser-core.d.ts.map +1 -1
- package/dist/server/services/plan/parser-core.js +1 -0
- package/dist/server/services/plan/parser-core.js.map +1 -1
- package/dist/server/services/plan/types.d.ts +1 -0
- package/dist/server/services/plan/types.d.ts.map +1 -1
- package/dist/server/services/settings.d.ts +76 -2
- package/dist/server/services/settings.d.ts.map +1 -1
- package/dist/server/services/settings.js +127 -4
- package/dist/server/services/settings.js.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/git-branch-handlers.js +19 -6
- package/dist/server/services/websocket/git-branch-handlers.js.map +1 -1
- package/dist/server/services/websocket/handler.d.ts +17 -1
- package/dist/server/services/websocket/handler.d.ts.map +1 -1
- package/dist/server/services/websocket/handler.js +54 -2
- package/dist/server/services/websocket/handler.js.map +1 -1
- package/dist/server/services/websocket/quality-complexity.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-complexity.js +78 -26
- package/dist/server/services/websocket/quality-complexity.js.map +1 -1
- package/dist/server/services/websocket/quality-eta.d.ts +47 -0
- package/dist/server/services/websocket/quality-eta.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-eta.js +110 -0
- package/dist/server/services/websocket/quality-eta.js.map +1 -0
- package/dist/server/services/websocket/quality-grading.d.ts +27 -4
- package/dist/server/services/websocket/quality-grading.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-grading.js +369 -201
- package/dist/server/services/websocket/quality-grading.js.map +1 -1
- package/dist/server/services/websocket/quality-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-handlers.js +145 -7
- package/dist/server/services/websocket/quality-handlers.js.map +1 -1
- package/dist/server/services/websocket/quality-operations.d.ts +34 -0
- package/dist/server/services/websocket/quality-operations.d.ts.map +1 -0
- package/dist/server/services/websocket/quality-operations.js +47 -0
- package/dist/server/services/websocket/quality-operations.js.map +1 -0
- package/dist/server/services/websocket/quality-persistence.d.ts +9 -0
- package/dist/server/services/websocket/quality-persistence.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-persistence.js +10 -0
- package/dist/server/services/websocket/quality-persistence.js.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.d.ts +1 -1
- package/dist/server/services/websocket/quality-review-agent.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-review-agent.js +105 -56
- package/dist/server/services/websocket/quality-review-agent.js.map +1 -1
- package/dist/server/services/websocket/quality-service.d.ts +9 -1
- package/dist/server/services/websocket/quality-service.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-service.js +334 -14
- package/dist/server/services/websocket/quality-service.js.map +1 -1
- package/dist/server/services/websocket/quality-tools.d.ts +21 -0
- package/dist/server/services/websocket/quality-tools.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-tools.js +49 -0
- package/dist/server/services/websocket/quality-tools.js.map +1 -1
- package/dist/server/services/websocket/quality-types.d.ts +35 -2
- package/dist/server/services/websocket/quality-types.d.ts.map +1 -1
- package/dist/server/services/websocket/quality-types.js +1 -1
- package/dist/server/services/websocket/quality-types.js.map +1 -1
- package/dist/server/services/websocket/session-handlers.d.ts +3 -1
- package/dist/server/services/websocket/session-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/session-handlers.js +57 -9
- package/dist/server/services/websocket/session-handlers.js.map +1 -1
- package/dist/server/services/websocket/session-history.js +3 -0
- package/dist/server/services/websocket/session-history.js.map +1 -1
- package/dist/server/services/websocket/session-initialization.d.ts.map +1 -1
- package/dist/server/services/websocket/session-initialization.js +158 -42
- package/dist/server/services/websocket/session-initialization.js.map +1 -1
- package/dist/server/services/websocket/session-registry.d.ts +25 -0
- package/dist/server/services/websocket/session-registry.d.ts.map +1 -1
- package/dist/server/services/websocket/session-registry.js +19 -0
- package/dist/server/services/websocket/session-registry.js.map +1 -1
- package/dist/server/services/websocket/settings-handlers.d.ts +1 -1
- package/dist/server/services/websocket/settings-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/settings-handlers.js +35 -4
- package/dist/server/services/websocket/settings-handlers.js.map +1 -1
- package/dist/server/services/websocket/tab-broadcast.d.ts +7 -2
- package/dist/server/services/websocket/tab-broadcast.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-broadcast.js +10 -2
- package/dist/server/services/websocket/tab-broadcast.js.map +1 -1
- package/dist/server/services/websocket/tab-event-buffer.d.ts +97 -8
- package/dist/server/services/websocket/tab-event-buffer.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-event-buffer.js +138 -12
- package/dist/server/services/websocket/tab-event-buffer.js.map +1 -1
- package/dist/server/services/websocket/tab-event-replay.d.ts +29 -13
- package/dist/server/services/websocket/tab-event-replay.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-event-replay.js +55 -2
- package/dist/server/services/websocket/tab-event-replay.js.map +1 -1
- package/dist/server/services/websocket/tab-handlers.d.ts +9 -1
- package/dist/server/services/websocket/tab-handlers.d.ts.map +1 -1
- package/dist/server/services/websocket/tab-handlers.js +47 -2
- package/dist/server/services/websocket/tab-handlers.js.map +1 -1
- package/dist/server/services/websocket/types.d.ts +28 -5
- package/dist/server/services/websocket/types.d.ts.map +1 -1
- package/dist/server/services/websocket/types.js +10 -4
- package/dist/server/services/websocket/types.js.map +1 -1
- package/package.json +5 -3
- package/server/cli/eta-estimator.ts +249 -0
- package/server/cli/headless/stall-assessor.ts +93 -0
- package/server/cli/headless/tool-watchdog.ts +21 -0
- package/server/cli/improvisation-history-store.ts +4 -1
- package/server/cli/improvisation-output-queue.ts +29 -7
- package/server/cli/improvisation-session-manager.ts +54 -1
- package/server/cli/improvisation-types.ts +2 -0
- package/server/engines/EngineEvent.ts +156 -0
- package/server/engines/claude/ClaudeCodeEngine.ts +404 -0
- package/server/engines/factory.ts +176 -0
- package/server/engines/opencode/OpenCodeEngine.ts +786 -0
- package/server/engines/opencode/OpenCodeServerManager.ts +577 -0
- package/server/engines/opencode/model-catalog.ts +217 -0
- package/server/engines/types.ts +173 -0
- package/server/index.ts +1 -1
- package/server/mcp/bouncer-haiku.ts +21 -145
- package/server/mcp/bouncer-integration.ts +107 -5
- package/server/mcp/classifier/BouncerClassifier.ts +40 -0
- package/server/mcp/classifier/ClaudeBouncerClassifier.ts +189 -0
- package/server/mcp/classifier/OpenCodeBouncerClassifier.ts +305 -0
- package/server/mcp/classifier/factory.ts +195 -0
- package/server/services/plan/agent-resolver.ts +115 -0
- package/server/services/plan/agents/code-review.md +38 -8
- package/server/services/plan/composer.ts +63 -11
- package/server/services/plan/executor.ts +3 -1
- package/server/services/plan/issue-prompt-builder.ts +39 -1
- package/server/services/plan/parser-core.ts +1 -0
- package/server/services/plan/types.ts +4 -0
- package/server/services/settings.ts +161 -4
- package/server/services/websocket/git-branch-handlers.ts +20 -6
- package/server/services/websocket/handler.ts +59 -2
- package/server/services/websocket/quality-complexity.ts +80 -26
- package/server/services/websocket/quality-eta.ts +155 -0
- package/server/services/websocket/quality-grading.ts +445 -222
- package/server/services/websocket/quality-handlers.ts +153 -7
- package/server/services/websocket/quality-operations.ts +72 -0
- package/server/services/websocket/quality-persistence.ts +17 -0
- package/server/services/websocket/quality-review-agent.ts +154 -64
- package/server/services/websocket/quality-service.ts +361 -13
- package/server/services/websocket/quality-tools.ts +51 -0
- package/server/services/websocket/quality-types.ts +41 -2
- package/server/services/websocket/session-handlers.ts +64 -10
- package/server/services/websocket/session-history.ts +3 -0
- package/server/services/websocket/session-initialization.ts +189 -46
- package/server/services/websocket/session-registry.ts +37 -0
- package/server/services/websocket/settings-handlers.ts +41 -4
- package/server/services/websocket/tab-broadcast.ts +10 -2
- package/server/services/websocket/tab-event-buffer.ts +143 -11
- package/server/services/websocket/tab-event-replay.ts +70 -3
- package/server/services/websocket/tab-handlers.ts +53 -5
- package/server/services/websocket/types.ts +37 -5
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
import { executeClaudeCommand } from '../../cli/headless/claude-invoker.js';
|
|
4
|
+
import { killProcessGroup } from '../../cli/headless/runner.js';
|
|
5
|
+
/**
|
|
6
|
+
* Implementation of CodingAgentEngine backed by the Claude Code headless
|
|
7
|
+
* runner. The engine holds a single logical conversation — subsequent
|
|
8
|
+
* prompts automatically continue the Claude session via --resume.
|
|
9
|
+
*/
|
|
10
|
+
export class ClaudeCodeEngine {
|
|
11
|
+
engineId = 'claude-code';
|
|
12
|
+
sessionOptions = null;
|
|
13
|
+
claudeSessionId;
|
|
14
|
+
/**
|
|
15
|
+
* Live child processes spawned by the current prompt. Keyed by pid; values
|
|
16
|
+
* are the raw ChildProcess handles. executeClaudeCommand registers the
|
|
17
|
+
* spawned process here and removes it on 'close'. cancel() iterates this
|
|
18
|
+
* map and SIGTERMs each process group — matching the pre-engine behavior
|
|
19
|
+
* from HeadlessRunner.cleanup().
|
|
20
|
+
*/
|
|
21
|
+
runningProcesses = new Map();
|
|
22
|
+
currentRunPromise = null;
|
|
23
|
+
disposed = false;
|
|
24
|
+
iteratorDone = false;
|
|
25
|
+
queue = [];
|
|
26
|
+
pending = [];
|
|
27
|
+
usage = {
|
|
28
|
+
inputTokens: 0,
|
|
29
|
+
outputTokens: 0,
|
|
30
|
+
lastUpdatedAt: Date.now(),
|
|
31
|
+
};
|
|
32
|
+
async startSession(options) {
|
|
33
|
+
if (this.sessionOptions) {
|
|
34
|
+
throw new Error('ClaudeCodeEngine: startSession called more than once');
|
|
35
|
+
}
|
|
36
|
+
if (this.disposed) {
|
|
37
|
+
throw new Error('ClaudeCodeEngine: cannot start a disposed engine');
|
|
38
|
+
}
|
|
39
|
+
this.sessionOptions = options;
|
|
40
|
+
this.claudeSessionId = options.resumeSessionId;
|
|
41
|
+
this.usage = {
|
|
42
|
+
inputTokens: 0,
|
|
43
|
+
outputTokens: 0,
|
|
44
|
+
lastUpdatedAt: Date.now(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async sendPrompt(prompt, attachments) {
|
|
48
|
+
if (!this.sessionOptions) {
|
|
49
|
+
throw new Error('ClaudeCodeEngine: sendPrompt called before startSession');
|
|
50
|
+
}
|
|
51
|
+
if (this.disposed) {
|
|
52
|
+
throw new Error('ClaudeCodeEngine: sendPrompt called after dispose');
|
|
53
|
+
}
|
|
54
|
+
if (this.currentRunPromise) {
|
|
55
|
+
throw new Error('ClaudeCodeEngine: another prompt is already in flight');
|
|
56
|
+
}
|
|
57
|
+
const opts = this.sessionOptions;
|
|
58
|
+
const imageAttachments = convertImageAttachments(attachments);
|
|
59
|
+
const toolStartTimes = new Map();
|
|
60
|
+
const toolNames = new Map();
|
|
61
|
+
const toolInputs = new Map();
|
|
62
|
+
const config = {
|
|
63
|
+
workingDir: opts.workingDir,
|
|
64
|
+
tokenBudgetThreshold: 170_000,
|
|
65
|
+
maxSessions: 50,
|
|
66
|
+
maxRetries: 3,
|
|
67
|
+
claudeCommand: process.env.CLAUDE_COMMAND || 'claude',
|
|
68
|
+
verbose: false,
|
|
69
|
+
noColor: false,
|
|
70
|
+
improvisationMode: false,
|
|
71
|
+
movementNumber: 0,
|
|
72
|
+
directPrompt: prompt,
|
|
73
|
+
promptContext: { accumulatedKnowledge: '', filesModified: [] },
|
|
74
|
+
stallWarningMs: 300_000,
|
|
75
|
+
stallKillMs: 1_800_000,
|
|
76
|
+
stallAssessEnabled: true,
|
|
77
|
+
stallMaxExtensions: 3,
|
|
78
|
+
stallHardCapMs: 3_600_000,
|
|
79
|
+
enableToolWatchdog: true,
|
|
80
|
+
maxAutoRetries: 2,
|
|
81
|
+
model: opts.model,
|
|
82
|
+
effortLevel: opts.effortLevel,
|
|
83
|
+
continueSession: !!this.claudeSessionId,
|
|
84
|
+
claudeSessionId: this.claudeSessionId,
|
|
85
|
+
imageAttachments,
|
|
86
|
+
disallowedTools: opts.disallowedTools,
|
|
87
|
+
deployMode: opts.deployMode,
|
|
88
|
+
extraEnv: opts.extraEnv,
|
|
89
|
+
outputCallback: (text) => {
|
|
90
|
+
this.emit({
|
|
91
|
+
kind: 'message.delta',
|
|
92
|
+
sessionId: this.sessionIdForEvent(),
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
text,
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
thinkingCallback: (text) => {
|
|
98
|
+
this.emit({
|
|
99
|
+
kind: 'message.thinking',
|
|
100
|
+
sessionId: this.sessionIdForEvent(),
|
|
101
|
+
timestamp: Date.now(),
|
|
102
|
+
text,
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
toolUseCallback: (event) => {
|
|
106
|
+
this.handleToolUseEvent(event, toolStartTimes, toolNames, toolInputs);
|
|
107
|
+
},
|
|
108
|
+
tokenUsageCallback: (usage) => {
|
|
109
|
+
this.usage = {
|
|
110
|
+
inputTokens: usage.inputTokens,
|
|
111
|
+
outputTokens: usage.outputTokens,
|
|
112
|
+
lastUpdatedAt: Date.now(),
|
|
113
|
+
};
|
|
114
|
+
this.emit({
|
|
115
|
+
kind: 'usage.update',
|
|
116
|
+
sessionId: this.sessionIdForEvent(),
|
|
117
|
+
timestamp: Date.now(),
|
|
118
|
+
inputTokens: usage.inputTokens,
|
|
119
|
+
outputTokens: usage.outputTokens,
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
const runPromise = executeClaudeCommand(prompt, 'engine', 1, {
|
|
124
|
+
config,
|
|
125
|
+
runningProcesses: this.runningProcesses,
|
|
126
|
+
});
|
|
127
|
+
this.currentRunPromise = runPromise;
|
|
128
|
+
runPromise.then((result) => this.onRunCompleted(result), (err) => this.onRunFailed(err));
|
|
129
|
+
}
|
|
130
|
+
async cancel() {
|
|
131
|
+
if (this.runningProcesses.size === 0 && !this.currentRunPromise)
|
|
132
|
+
return;
|
|
133
|
+
this.killAllRunningProcesses();
|
|
134
|
+
if (this.currentRunPromise) {
|
|
135
|
+
await this.currentRunPromise.catch(() => { });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
getUsage() {
|
|
139
|
+
return { ...this.usage };
|
|
140
|
+
}
|
|
141
|
+
async dispose() {
|
|
142
|
+
if (this.disposed)
|
|
143
|
+
return;
|
|
144
|
+
this.disposed = true;
|
|
145
|
+
this.killAllRunningProcesses();
|
|
146
|
+
if (this.currentRunPromise) {
|
|
147
|
+
await this.currentRunPromise.catch(() => { });
|
|
148
|
+
}
|
|
149
|
+
this.closeIterator();
|
|
150
|
+
}
|
|
151
|
+
[Symbol.asyncIterator]() {
|
|
152
|
+
return {
|
|
153
|
+
next: () => {
|
|
154
|
+
if (this.queue.length > 0) {
|
|
155
|
+
return Promise.resolve({ value: this.queue.shift(), done: false });
|
|
156
|
+
}
|
|
157
|
+
if (this.iteratorDone) {
|
|
158
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
159
|
+
}
|
|
160
|
+
return new Promise((resolve) => {
|
|
161
|
+
this.pending.push(resolve);
|
|
162
|
+
});
|
|
163
|
+
},
|
|
164
|
+
return: () => {
|
|
165
|
+
this.closeIterator();
|
|
166
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// ---------- private ----------
|
|
171
|
+
sessionIdForEvent() {
|
|
172
|
+
return this.claudeSessionId ?? 'pending';
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* SIGTERM every tracked child process group; schedule a SIGKILL fallback
|
|
176
|
+
* for any that haven't exited in 5s. Mirrors HeadlessRunner.cleanup().
|
|
177
|
+
*/
|
|
178
|
+
killAllRunningProcesses() {
|
|
179
|
+
if (this.runningProcesses.size === 0)
|
|
180
|
+
return;
|
|
181
|
+
const pids = new Set();
|
|
182
|
+
for (const pid of this.runningProcesses.keys()) {
|
|
183
|
+
pids.add(pid);
|
|
184
|
+
killProcessGroup(pid, 'SIGTERM');
|
|
185
|
+
}
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
for (const [pid, proc] of this.runningProcesses) {
|
|
188
|
+
if (pids.has(pid) && !proc.killed) {
|
|
189
|
+
killProcessGroup(pid, 'SIGKILL');
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}, 5000).unref?.();
|
|
193
|
+
}
|
|
194
|
+
emit(event) {
|
|
195
|
+
if (this.iteratorDone)
|
|
196
|
+
return;
|
|
197
|
+
const resolver = this.pending.shift();
|
|
198
|
+
if (resolver) {
|
|
199
|
+
resolver({ value: event, done: false });
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
this.queue.push(event);
|
|
203
|
+
}
|
|
204
|
+
if (event.kind === 'engine.error' && event.fatal) {
|
|
205
|
+
this.closeIterator();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
closeIterator() {
|
|
209
|
+
if (this.iteratorDone)
|
|
210
|
+
return;
|
|
211
|
+
this.iteratorDone = true;
|
|
212
|
+
const waiting = this.pending.splice(0);
|
|
213
|
+
for (const resolve of waiting) {
|
|
214
|
+
resolve({ value: undefined, done: true });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
onRunCompleted(result) {
|
|
218
|
+
this.currentRunPromise = null;
|
|
219
|
+
if (result.claudeSessionId) {
|
|
220
|
+
this.claudeSessionId = result.claudeSessionId;
|
|
221
|
+
}
|
|
222
|
+
// Fall back to the definitive end-of-run usage — the streaming callback
|
|
223
|
+
// may have missed the final numbers if the result event arrived after
|
|
224
|
+
// the last message_delta.
|
|
225
|
+
if (result.apiTokenUsage) {
|
|
226
|
+
const u = result.apiTokenUsage;
|
|
227
|
+
if (u.inputTokens > this.usage.inputTokens || u.outputTokens > this.usage.outputTokens) {
|
|
228
|
+
this.usage = {
|
|
229
|
+
inputTokens: Math.max(u.inputTokens, this.usage.inputTokens),
|
|
230
|
+
outputTokens: Math.max(u.outputTokens, this.usage.outputTokens),
|
|
231
|
+
lastUpdatedAt: Date.now(),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
this.emit({
|
|
236
|
+
kind: 'session.idle',
|
|
237
|
+
sessionId: this.sessionIdForEvent(),
|
|
238
|
+
timestamp: Date.now(),
|
|
239
|
+
stopReason: result.stopReason,
|
|
240
|
+
});
|
|
241
|
+
if (result.exitCode !== 0 && !result.assistantResponse && !result.toolUseHistory?.length) {
|
|
242
|
+
const message = result.error || `Claude exited with code ${result.exitCode}`;
|
|
243
|
+
this.emit({
|
|
244
|
+
kind: 'engine.error',
|
|
245
|
+
sessionId: this.sessionIdForEvent(),
|
|
246
|
+
timestamp: Date.now(),
|
|
247
|
+
code: 'CLAUDE_RUN_ERROR',
|
|
248
|
+
message,
|
|
249
|
+
fatal: false,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
onRunFailed(err) {
|
|
254
|
+
this.currentRunPromise = null;
|
|
255
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
256
|
+
this.emit({
|
|
257
|
+
kind: 'engine.error',
|
|
258
|
+
sessionId: this.sessionIdForEvent(),
|
|
259
|
+
timestamp: Date.now(),
|
|
260
|
+
code: 'CLAUDE_SPAWN_ERROR',
|
|
261
|
+
message,
|
|
262
|
+
fatal: true,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
handleToolUseEvent(event, starts, names, inputs) {
|
|
266
|
+
if (!event.toolId)
|
|
267
|
+
return;
|
|
268
|
+
if (event.type === 'tool_start') {
|
|
269
|
+
this.onToolStart(event, starts, names);
|
|
270
|
+
}
|
|
271
|
+
else if (event.type === 'tool_complete') {
|
|
272
|
+
this.onToolComplete(event, names, inputs);
|
|
273
|
+
}
|
|
274
|
+
else if (event.type === 'tool_result') {
|
|
275
|
+
this.onToolResult(event, starts, names, inputs);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
onToolStart(event, starts, names) {
|
|
279
|
+
const ts = Date.now();
|
|
280
|
+
const toolId = event.toolId;
|
|
281
|
+
starts.set(toolId, ts);
|
|
282
|
+
if (event.toolName)
|
|
283
|
+
names.set(toolId, event.toolName);
|
|
284
|
+
this.emit({
|
|
285
|
+
kind: 'tool.start',
|
|
286
|
+
sessionId: this.sessionIdForEvent(),
|
|
287
|
+
timestamp: ts,
|
|
288
|
+
toolCallId: toolId,
|
|
289
|
+
toolName: event.toolName ?? '',
|
|
290
|
+
input: {},
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
onToolComplete(event, names, inputs) {
|
|
294
|
+
const toolId = event.toolId;
|
|
295
|
+
if (event.completeInput)
|
|
296
|
+
inputs.set(toolId, event.completeInput);
|
|
297
|
+
if (event.toolName)
|
|
298
|
+
names.set(toolId, event.toolName);
|
|
299
|
+
// tool.end is emitted on tool_result so the result payload is included.
|
|
300
|
+
}
|
|
301
|
+
onToolResult(event, starts, names, inputs) {
|
|
302
|
+
const ts = Date.now();
|
|
303
|
+
const toolId = event.toolId;
|
|
304
|
+
const start = starts.get(toolId) ?? ts;
|
|
305
|
+
this.emit({
|
|
306
|
+
kind: 'tool.end',
|
|
307
|
+
sessionId: this.sessionIdForEvent(),
|
|
308
|
+
timestamp: ts,
|
|
309
|
+
toolCallId: toolId,
|
|
310
|
+
toolName: names.get(toolId) ?? '',
|
|
311
|
+
input: inputs.get(toolId) ?? {},
|
|
312
|
+
result: event.result ?? '',
|
|
313
|
+
isError: event.isError ?? false,
|
|
314
|
+
durationMs: ts - start,
|
|
315
|
+
});
|
|
316
|
+
starts.delete(toolId);
|
|
317
|
+
names.delete(toolId);
|
|
318
|
+
inputs.delete(toolId);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
function convertImageAttachments(attachments) {
|
|
322
|
+
if (!attachments || attachments.length === 0)
|
|
323
|
+
return undefined;
|
|
324
|
+
const images = [];
|
|
325
|
+
for (const a of attachments) {
|
|
326
|
+
if (!a.isImage || !a.base64Content)
|
|
327
|
+
continue;
|
|
328
|
+
images.push({
|
|
329
|
+
fileName: a.fileName,
|
|
330
|
+
filePath: a.filePath ?? a.fileName,
|
|
331
|
+
content: a.base64Content,
|
|
332
|
+
isImage: true,
|
|
333
|
+
mimeType: a.mimeType,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
return images.length > 0 ? images : undefined;
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=ClaudeCodeEngine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClaudeCodeEngine.js","sourceRoot":"","sources":["../../../../server/engines/claude/ClaudeCodeEngine.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,gEAAgE;AAchE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAoBhE;;;;GAIG;AACH,MAAM,OAAO,gBAAgB;IAClB,QAAQ,GAAa,aAAa,CAAC;IAEpC,cAAc,GAA+B,IAAI,CAAC;IAClD,eAAe,CAAqB;IAC5C;;;;;;OAMG;IACc,gBAAgB,GAA8B,IAAI,GAAG,EAAE,CAAC;IACjE,iBAAiB,GAAoC,IAAI,CAAC;IAE1D,QAAQ,GAAG,KAAK,CAAC;IACjB,YAAY,GAAG,KAAK,CAAC;IACZ,KAAK,GAAkB,EAAE,CAAC;IAC1B,OAAO,GAAe,EAAE,CAAC;IAElC,KAAK,GAAgB;QAC3B,WAAW,EAAE,CAAC;QACd,YAAY,EAAE,CAAC;QACf,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;KAC1B,CAAC;IAEF,KAAK,CAAC,YAAY,CAAC,OAA4B;QAC7C,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC1E,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC;QAC9B,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;QAC/C,IAAI,CAAC,KAAK,GAAG;YACX,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;YACf,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;SAC1B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAc,EAAE,WAAgC;QAC/D,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC7E,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,cAAc,CAAC;QACjC,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,WAAW,CAAC,CAAC;QAE9D,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;QACjD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;QAC5C,MAAM,UAAU,GAAG,IAAI,GAAG,EAAmC,CAAC;QAE9D,MAAM,MAAM,GAA2B;YACrC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,oBAAoB,EAAE,OAAO;YAC7B,WAAW,EAAE,EAAE;YACf,UAAU,EAAE,CAAC;YACb,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,QAAQ;YACrD,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,KAAK;YACd,iBAAiB,EAAE,KAAK;YACxB,cAAc,EAAE,CAAC;YACjB,YAAY,EAAE,MAAM;YACpB,aAAa,EAAE,EAAE,oBAAoB,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE;YAC9D,cAAc,EAAE,OAAO;YACvB,WAAW,EAAE,SAAS;YACtB,kBAAkB,EAAE,IAAI;YACxB,kBAAkB,EAAE,CAAC;YACrB,cAAc,EAAE,SAAS;YACzB,kBAAkB,EAAE,IAAI;YACxB,cAAc,EAAE,CAAC;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe;YACvC,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,gBAAgB;YAChB,eAAe,EAAE,IAAI,CAAC,eAAe;YACrC,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,cAAc,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/B,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,eAAe;oBACrB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;oBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YACD,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE;gBACjC,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,kBAAkB;oBACxB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;oBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,IAAI;iBACL,CAAC,CAAC;YACL,CAAC;YACD,eAAe,EAAE,CAAC,KAAmB,EAAE,EAAE;gBACvC,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YACxE,CAAC;YACD,kBAAkB,EAAE,CAAC,KAAoD,EAAE,EAAE;gBAC3E,IAAI,CAAC,KAAK,GAAG;oBACX,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;oBAChC,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;iBAC1B,CAAC;gBACF,IAAI,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,cAAc;oBACpB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;oBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;oBACrB,WAAW,EAAE,KAAK,CAAC,WAAW;oBAC9B,YAAY,EAAE,KAAK,CAAC,YAAY;iBACjC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;QAEF,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;YAC3D,MAAM;YACN,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;SACxC,CAAC,CAAC;QACH,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC;QAEpC,UAAU,CAAC,IAAI,CACb,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,EACvC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAC/B,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,MAAM;QACV,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB;YAAE,OAAO;QACxE,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,EAAE,GAAkC,CAAC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAED,QAAQ;QACN,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,EAAE,GAAkC,CAAC,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAED,CAAC,MAAM,CAAC,aAAa,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,GAAyC,EAAE;gBAC/C,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1B,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,EAAiB,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACpF,CAAC;gBACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACtB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBACD,OAAO,IAAI,OAAO,CAA8B,CAAC,OAAO,EAAE,EAAE;oBAC1D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC7B,CAAC,CAAC,CAAC;YACL,CAAC;YACD,MAAM,EAAE,GAAyC,EAAE;gBACjD,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,CAAC;SACF,CAAC;IACJ,CAAC;IAED,gCAAgC;IAExB,iBAAiB;QACvB,OAAO,IAAI,CAAC,eAAe,IAAI,SAAS,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACK,uBAAuB;QAC7B,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO;QAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACd,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACnC,CAAC;QACD,UAAU,CAAC,GAAG,EAAE;YACd,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBAChD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;oBAClC,gBAAgB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;IACrB,CAAC;IAEO,IAAI,CAAC,KAAkB;QAC7B,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACtC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACjD,IAAI,CAAC,aAAa,EAAE,CAAC;QACvB,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO;QAC9B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvC,KAAK,MAAM,OAAO,IAAI,OAAO,EAAE,CAAC;YAC9B,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IAEO,cAAc,CAAC,MAAuB;QAC5C,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,IAAI,MAAM,CAAC,eAAe,EAAE,CAAC;YAC3B,IAAI,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAC;QAChD,CAAC;QACD,wEAAwE;QACxE,sEAAsE;QACtE,0BAA0B;QAC1B,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,MAAM,CAAC,GAAG,MAAM,CAAC,aAAa,CAAC;YAC/B,IAAI,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;gBACvF,IAAI,CAAC,KAAK,GAAG;oBACX,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC;oBAC5D,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;oBAC/D,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE;iBAC1B,CAAC;YACJ,CAAC;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;YACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC;YACzF,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,IAAI,2BAA2B,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC7E,IAAI,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,cAAc;gBACpB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;gBACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;gBACrB,IAAI,EAAE,kBAAkB;gBACxB,OAAO;gBACP,KAAK,EAAE,KAAK;aACb,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,WAAW,CAAC,GAAY;QAC9B,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC;QAC9B,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;YACnC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,IAAI,EAAE,oBAAoB;YAC1B,OAAO;YACP,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;IACL,CAAC;IAEO,kBAAkB,CACxB,KAAmB,EACnB,MAA2B,EAC3B,KAA0B,EAC1B,MAA4C;QAE5C,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,OAAO;QAC1B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YAC1C,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAC5C,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACxC,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAEO,WAAW,CACjB,KAAmB,EACnB,MAA2B,EAC3B,KAA0B;QAE1B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAgB,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvB,IAAI,KAAK,CAAC,QAAQ;YAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,YAAY;YAClB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;YACnC,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,KAAK,CAAC,QAAQ,IAAI,EAAE;YAC9B,KAAK,EAAE,EAAE;SACV,CAAC,CAAC;IACL,CAAC;IAEO,cAAc,CACpB,KAAmB,EACnB,KAA0B,EAC1B,MAA4C;QAE5C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAgB,CAAC;QACtC,IAAI,KAAK,CAAC,aAAa;YAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;QACjE,IAAI,KAAK,CAAC,QAAQ;YAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtD,wEAAwE;IAC1E,CAAC;IAEO,YAAY,CAClB,KAAmB,EACnB,MAA2B,EAC3B,KAA0B,EAC1B,MAA4C;QAE5C,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,KAAK,CAAC,MAAgB,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE;YACnC,SAAS,EAAE,EAAE;YACb,UAAU,EAAE,MAAM;YAClB,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;YACjC,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE;YAC/B,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;YAC1B,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK;YAC/B,UAAU,EAAE,EAAE,GAAG,KAAK;SACvB,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACtB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;CACF;AAED,SAAS,uBAAuB,CAC9B,WAAgC;IAEhC,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/D,MAAM,MAAM,GAAsB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,aAAa;YAAE,SAAS;QAC7C,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ;YAClC,OAAO,EAAE,CAAC,CAAC,aAAa;YACxB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CodingAgentEngine, EngineId } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Reset the cached OpenCode manager. Primarily for tests — never called
|
|
4
|
+
* by production code. Does not shut down the previous manager; callers
|
|
5
|
+
* that need a clean state should `shutdown()` first.
|
|
6
|
+
*/
|
|
7
|
+
export declare function __resetSharedOpenCodeServerManagerForTests(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Construct a new engine instance for the given engine id. The returned
|
|
10
|
+
* engine is uninitialized — the caller must call `startSession` before
|
|
11
|
+
* any other method.
|
|
12
|
+
*
|
|
13
|
+
* Feature-flag gate: when `engineSwap` is disabled, this returns
|
|
14
|
+
* `ClaudeCodeEngine` for every id. That guarantees the pre-OpenCode
|
|
15
|
+
* behavior — in particular, `LazyOpenCodeEngine` is never constructed, so
|
|
16
|
+
* the shared `OpenCodeServerManager` is never touched and no `opencode
|
|
17
|
+
* serve` subprocess is spawned. The flag is checked on every call (rather
|
|
18
|
+
* than cached) so runtime toggles take effect on the next session start.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createEngine(engineId: EngineId): CodingAgentEngine;
|
|
21
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../server/engines/factory.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EACV,iBAAiB,EAEjB,QAAQ,EAIT,MAAM,YAAY,CAAC;AAmBpB;;;;GAIG;AACH,wBAAgB,0CAA0C,IAAI,IAAI,CAEjE;AA8FD;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,GAAG,iBAAiB,CAclE"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Copyright (c) 2025-present Mstro, Inc. All rights reserved.
|
|
2
|
+
// Licensed under the MIT License. See LICENSE file for details.
|
|
3
|
+
/**
|
|
4
|
+
* Engine factory — returns a concrete CodingAgentEngine for the requested
|
|
5
|
+
* EngineId. Callers pass the value of `settings.engine` and the factory
|
|
6
|
+
* dispatches to the matching implementation:
|
|
7
|
+
*
|
|
8
|
+
* - 'claude-code' → ClaudeCodeEngine (headless runner, stdout JSON)
|
|
9
|
+
* - 'opencode' → OpenCodeEngine (OpenCode SDK + SSE)
|
|
10
|
+
*
|
|
11
|
+
* The OpenCode path is backed by a single process-lifetime
|
|
12
|
+
* OpenCodeServerManager that owns the `opencode serve` subprocess. The
|
|
13
|
+
* factory itself stays synchronous; manager startup is awaited inside
|
|
14
|
+
* `startSession` via `LazyOpenCodeEngine` (below) so callers observe the
|
|
15
|
+
* same lifecycle as ClaudeCodeEngine.
|
|
16
|
+
*/
|
|
17
|
+
import { isEngineSwapEnabled } from '../services/settings.js';
|
|
18
|
+
import { ClaudeCodeEngine } from './claude/ClaudeCodeEngine.js';
|
|
19
|
+
import { OpenCodeEngine } from './opencode/OpenCodeEngine.js';
|
|
20
|
+
import { OpenCodeServerManager } from './opencode/OpenCodeServerManager.js';
|
|
21
|
+
/**
|
|
22
|
+
* Process-lifetime singleton for the `opencode serve` subprocess. Created
|
|
23
|
+
* lazily on the first request for an opencode engine so Claude-only
|
|
24
|
+
* deployments never spawn the binary. `registerProcessHandlers` is set so
|
|
25
|
+
* the subprocess exits with the CLI — no orphan processes on SIGINT.
|
|
26
|
+
*/
|
|
27
|
+
let sharedOpenCodeManager = null;
|
|
28
|
+
function getSharedOpenCodeServerManager() {
|
|
29
|
+
if (!sharedOpenCodeManager) {
|
|
30
|
+
sharedOpenCodeManager = new OpenCodeServerManager({
|
|
31
|
+
registerProcessHandlers: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
return sharedOpenCodeManager;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reset the cached OpenCode manager. Primarily for tests — never called
|
|
38
|
+
* by production code. Does not shut down the previous manager; callers
|
|
39
|
+
* that need a clean state should `shutdown()` first.
|
|
40
|
+
*/
|
|
41
|
+
export function __resetSharedOpenCodeServerManagerForTests() {
|
|
42
|
+
sharedOpenCodeManager = null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Thin adapter that defers `OpenCodeEngine` construction until
|
|
46
|
+
* `startSession` runs. The real engine requires an already-bound
|
|
47
|
+
* `OpencodeClient`, but the underlying HTTP server is spawned
|
|
48
|
+
* asynchronously by `OpenCodeServerManager`. `startSession` is the first
|
|
49
|
+
* async call on the engine lifecycle, so we await `manager.start()`
|
|
50
|
+
* there, then construct the inner engine once the client is available
|
|
51
|
+
* and forward every subsequent call to it.
|
|
52
|
+
*
|
|
53
|
+
* The wrapper preserves the public `CodingAgentEngine` contract:
|
|
54
|
+
* - `engineId` is stable at `'opencode'` from construction.
|
|
55
|
+
* - Methods called before `startSession` resolve reject with the same
|
|
56
|
+
* error wording the inner engine would have produced.
|
|
57
|
+
* - `dispose()` is idempotent and tolerates the uninitialized case.
|
|
58
|
+
*/
|
|
59
|
+
class LazyOpenCodeEngine {
|
|
60
|
+
manager;
|
|
61
|
+
engineId = 'opencode';
|
|
62
|
+
inner = null;
|
|
63
|
+
started = false;
|
|
64
|
+
disposed = false;
|
|
65
|
+
constructor(manager) {
|
|
66
|
+
this.manager = manager;
|
|
67
|
+
}
|
|
68
|
+
async startSession(options) {
|
|
69
|
+
if (this.disposed) {
|
|
70
|
+
throw new Error('OpenCodeEngine: cannot start a disposed engine');
|
|
71
|
+
}
|
|
72
|
+
if (this.started) {
|
|
73
|
+
throw new Error('OpenCodeEngine: startSession called more than once');
|
|
74
|
+
}
|
|
75
|
+
await this.manager.start();
|
|
76
|
+
const client = this.manager.getClient();
|
|
77
|
+
this.inner = new OpenCodeEngine({
|
|
78
|
+
client,
|
|
79
|
+
directory: options.workingDir,
|
|
80
|
+
});
|
|
81
|
+
await this.inner.startSession(options);
|
|
82
|
+
this.started = true;
|
|
83
|
+
}
|
|
84
|
+
sendPrompt(prompt, attachments) {
|
|
85
|
+
if (this.disposed) {
|
|
86
|
+
return Promise.reject(new Error('OpenCodeEngine: sendPrompt called after dispose'));
|
|
87
|
+
}
|
|
88
|
+
if (!this.inner) {
|
|
89
|
+
return Promise.reject(new Error('OpenCodeEngine: sendPrompt called before startSession'));
|
|
90
|
+
}
|
|
91
|
+
return this.inner.sendPrompt(prompt, attachments);
|
|
92
|
+
}
|
|
93
|
+
cancel() {
|
|
94
|
+
if (!this.inner)
|
|
95
|
+
return Promise.resolve();
|
|
96
|
+
return this.inner.cancel();
|
|
97
|
+
}
|
|
98
|
+
getUsage() {
|
|
99
|
+
if (!this.inner) {
|
|
100
|
+
return { inputTokens: 0, outputTokens: 0, lastUpdatedAt: Date.now() };
|
|
101
|
+
}
|
|
102
|
+
return this.inner.getUsage();
|
|
103
|
+
}
|
|
104
|
+
async dispose() {
|
|
105
|
+
if (this.disposed)
|
|
106
|
+
return;
|
|
107
|
+
this.disposed = true;
|
|
108
|
+
if (this.inner) {
|
|
109
|
+
await this.inner.dispose();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
[Symbol.asyncIterator]() {
|
|
113
|
+
// The contract only allows iteration after `startSession` has resolved,
|
|
114
|
+
// so `this.inner` is guaranteed to be set when consumers begin the
|
|
115
|
+
// for-await loop. We delegate directly to the inner engine's iterator
|
|
116
|
+
// to preserve its ordering and terminal-event semantics.
|
|
117
|
+
if (!this.inner) {
|
|
118
|
+
return {
|
|
119
|
+
next: () => Promise.resolve({ value: undefined, done: true }),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return this.inner[Symbol.asyncIterator]();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Construct a new engine instance for the given engine id. The returned
|
|
127
|
+
* engine is uninitialized — the caller must call `startSession` before
|
|
128
|
+
* any other method.
|
|
129
|
+
*
|
|
130
|
+
* Feature-flag gate: when `engineSwap` is disabled, this returns
|
|
131
|
+
* `ClaudeCodeEngine` for every id. That guarantees the pre-OpenCode
|
|
132
|
+
* behavior — in particular, `LazyOpenCodeEngine` is never constructed, so
|
|
133
|
+
* the shared `OpenCodeServerManager` is never touched and no `opencode
|
|
134
|
+
* serve` subprocess is spawned. The flag is checked on every call (rather
|
|
135
|
+
* than cached) so runtime toggles take effect on the next session start.
|
|
136
|
+
*/
|
|
137
|
+
export function createEngine(engineId) {
|
|
138
|
+
if (!isEngineSwapEnabled()) {
|
|
139
|
+
return new ClaudeCodeEngine();
|
|
140
|
+
}
|
|
141
|
+
switch (engineId) {
|
|
142
|
+
case 'claude-code':
|
|
143
|
+
return new ClaudeCodeEngine();
|
|
144
|
+
case 'opencode':
|
|
145
|
+
return new LazyOpenCodeEngine(getSharedOpenCodeServerManager());
|
|
146
|
+
default: {
|
|
147
|
+
const exhaustive = engineId;
|
|
148
|
+
throw new Error(`Unknown engine id: ${String(exhaustive)}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../server/engines/factory.ts"],"names":[],"mappings":"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"}
|