clitrigger 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +9 -0
- package/LICENSE +21 -0
- package/README.md +186 -0
- package/bin/clitrigger.js +106 -0
- package/dist/client/assets/index-BkOCv65b.css +1 -0
- package/dist/client/assets/index-Fbf16Lh1.js +129 -0
- package/dist/client/index.html +24 -0
- package/dist/server/db/connection.d.ts +4 -0
- package/dist/server/db/connection.d.ts.map +1 -0
- package/dist/server/db/connection.js +24 -0
- package/dist/server/db/connection.js.map +1 -0
- package/dist/server/db/queries.d.ts +265 -0
- package/dist/server/db/queries.d.ts.map +1 -0
- package/dist/server/db/queries.js +836 -0
- package/dist/server/db/queries.js.map +1 -0
- package/dist/server/db/schema.d.ts +3 -0
- package/dist/server/db/schema.d.ts.map +1 -0
- package/dist/server/db/schema.js +325 -0
- package/dist/server/db/schema.js.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +207 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/auth.d.ts +5 -0
- package/dist/server/middleware/auth.d.ts.map +1 -0
- package/dist/server/middleware/auth.js +45 -0
- package/dist/server/middleware/auth.js.map +1 -0
- package/dist/server/plugins/github/index.d.ts +3 -0
- package/dist/server/plugins/github/index.d.ts.map +1 -0
- package/dist/server/plugins/github/index.js +18 -0
- package/dist/server/plugins/github/index.js.map +1 -0
- package/dist/server/plugins/github/router.d.ts +4 -0
- package/dist/server/plugins/github/router.d.ts.map +1 -0
- package/dist/server/plugins/github/router.js +250 -0
- package/dist/server/plugins/github/router.js.map +1 -0
- package/dist/server/plugins/gstack/index.d.ts +3 -0
- package/dist/server/plugins/gstack/index.d.ts.map +1 -0
- package/dist/server/plugins/gstack/index.js +36 -0
- package/dist/server/plugins/gstack/index.js.map +1 -0
- package/dist/server/plugins/jira/index.d.ts +3 -0
- package/dist/server/plugins/jira/index.d.ts.map +1 -0
- package/dist/server/plugins/jira/index.js +19 -0
- package/dist/server/plugins/jira/index.js.map +1 -0
- package/dist/server/plugins/jira/router.d.ts +4 -0
- package/dist/server/plugins/jira/router.d.ts.map +1 -0
- package/dist/server/plugins/jira/router.js +332 -0
- package/dist/server/plugins/jira/router.js.map +1 -0
- package/dist/server/plugins/notion/index.d.ts +3 -0
- package/dist/server/plugins/notion/index.d.ts.map +1 -0
- package/dist/server/plugins/notion/index.js +17 -0
- package/dist/server/plugins/notion/index.js.map +1 -0
- package/dist/server/plugins/notion/router.d.ts +4 -0
- package/dist/server/plugins/notion/router.d.ts.map +1 -0
- package/dist/server/plugins/notion/router.js +313 -0
- package/dist/server/plugins/notion/router.js.map +1 -0
- package/dist/server/plugins/registry.d.ts +8 -0
- package/dist/server/plugins/registry.d.ts.map +1 -0
- package/dist/server/plugins/registry.js +31 -0
- package/dist/server/plugins/registry.js.map +1 -0
- package/dist/server/plugins/types.d.ts +32 -0
- package/dist/server/plugins/types.d.ts.map +1 -0
- package/dist/server/plugins/types.js +2 -0
- package/dist/server/plugins/types.js.map +1 -0
- package/dist/server/resources/gstack-skills/LICENSE +21 -0
- package/dist/server/resources/gstack-skills/benchmark/SKILL.md +528 -0
- package/dist/server/resources/gstack-skills/careful/SKILL.md +59 -0
- package/dist/server/resources/gstack-skills/cso/SKILL.md +898 -0
- package/dist/server/resources/gstack-skills/investigate/SKILL.md +474 -0
- package/dist/server/resources/gstack-skills/qa/SKILL.md +1055 -0
- package/dist/server/resources/gstack-skills/qa-only/SKILL.md +672 -0
- package/dist/server/resources/gstack-skills/review/SKILL.md +1044 -0
- package/dist/server/resources/gstack-skills/skills-manifest.d.ts +9 -0
- package/dist/server/resources/gstack-skills/skills-manifest.d.ts.map +1 -0
- package/dist/server/resources/gstack-skills/skills-manifest.js +52 -0
- package/dist/server/resources/gstack-skills/skills-manifest.js.map +1 -0
- package/dist/server/resources/gstack-skills/skills-manifest.ts +59 -0
- package/dist/server/routes/auth.d.ts +3 -0
- package/dist/server/routes/auth.d.ts.map +1 -0
- package/dist/server/routes/auth.js +70 -0
- package/dist/server/routes/auth.js.map +1 -0
- package/dist/server/routes/debug-logs.d.ts +3 -0
- package/dist/server/routes/debug-logs.d.ts.map +1 -0
- package/dist/server/routes/debug-logs.js +43 -0
- package/dist/server/routes/debug-logs.js.map +1 -0
- package/dist/server/routes/discussions.d.ts +3 -0
- package/dist/server/routes/discussions.d.ts.map +1 -0
- package/dist/server/routes/discussions.js +544 -0
- package/dist/server/routes/discussions.js.map +1 -0
- package/dist/server/routes/execution.d.ts +3 -0
- package/dist/server/routes/execution.d.ts.map +1 -0
- package/dist/server/routes/execution.js +339 -0
- package/dist/server/routes/execution.js.map +1 -0
- package/dist/server/routes/github.d.ts +3 -0
- package/dist/server/routes/github.d.ts.map +1 -0
- package/dist/server/routes/github.js +251 -0
- package/dist/server/routes/github.js.map +1 -0
- package/dist/server/routes/images.d.ts +17 -0
- package/dist/server/routes/images.d.ts.map +1 -0
- package/dist/server/routes/images.js +152 -0
- package/dist/server/routes/images.js.map +1 -0
- package/dist/server/routes/jira.d.ts +3 -0
- package/dist/server/routes/jira.d.ts.map +1 -0
- package/dist/server/routes/jira.js +333 -0
- package/dist/server/routes/jira.js.map +1 -0
- package/dist/server/routes/logs.d.ts +3 -0
- package/dist/server/routes/logs.d.ts.map +1 -0
- package/dist/server/routes/logs.js +156 -0
- package/dist/server/routes/logs.js.map +1 -0
- package/dist/server/routes/models.d.ts +3 -0
- package/dist/server/routes/models.d.ts.map +1 -0
- package/dist/server/routes/models.js +65 -0
- package/dist/server/routes/models.js.map +1 -0
- package/dist/server/routes/notion.d.ts +3 -0
- package/dist/server/routes/notion.d.ts.map +1 -0
- package/dist/server/routes/notion.js +312 -0
- package/dist/server/routes/notion.js.map +1 -0
- package/dist/server/routes/pipelines.d.ts +3 -0
- package/dist/server/routes/pipelines.d.ts.map +1 -0
- package/dist/server/routes/pipelines.js +315 -0
- package/dist/server/routes/pipelines.js.map +1 -0
- package/dist/server/routes/plugins.d.ts +3 -0
- package/dist/server/routes/plugins.d.ts.map +1 -0
- package/dist/server/routes/plugins.js +71 -0
- package/dist/server/routes/plugins.js.map +1 -0
- package/dist/server/routes/projects.d.ts +3 -0
- package/dist/server/routes/projects.d.ts.map +1 -0
- package/dist/server/routes/projects.js +557 -0
- package/dist/server/routes/projects.js.map +1 -0
- package/dist/server/routes/schedules.d.ts +3 -0
- package/dist/server/routes/schedules.d.ts.map +1 -0
- package/dist/server/routes/schedules.js +247 -0
- package/dist/server/routes/schedules.js.map +1 -0
- package/dist/server/routes/todos.d.ts +3 -0
- package/dist/server/routes/todos.d.ts.map +1 -0
- package/dist/server/routes/todos.js +103 -0
- package/dist/server/routes/todos.js.map +1 -0
- package/dist/server/routes/tunnel.d.ts +3 -0
- package/dist/server/routes/tunnel.d.ts.map +1 -0
- package/dist/server/routes/tunnel.js +44 -0
- package/dist/server/routes/tunnel.js.map +1 -0
- package/dist/server/services/claude-manager.d.ts +42 -0
- package/dist/server/services/claude-manager.d.ts.map +1 -0
- package/dist/server/services/claude-manager.js +275 -0
- package/dist/server/services/claude-manager.js.map +1 -0
- package/dist/server/services/cli-adapters.d.ts +35 -0
- package/dist/server/services/cli-adapters.d.ts.map +1 -0
- package/dist/server/services/cli-adapters.js +139 -0
- package/dist/server/services/cli-adapters.js.map +1 -0
- package/dist/server/services/debug-logger.d.ts +35 -0
- package/dist/server/services/debug-logger.d.ts.map +1 -0
- package/dist/server/services/debug-logger.js +168 -0
- package/dist/server/services/debug-logger.js.map +1 -0
- package/dist/server/services/discussion-orchestrator.d.ts +47 -0
- package/dist/server/services/discussion-orchestrator.d.ts.map +1 -0
- package/dist/server/services/discussion-orchestrator.js +599 -0
- package/dist/server/services/discussion-orchestrator.js.map +1 -0
- package/dist/server/services/log-streamer.d.ts +45 -0
- package/dist/server/services/log-streamer.d.ts.map +1 -0
- package/dist/server/services/log-streamer.js +348 -0
- package/dist/server/services/log-streamer.js.map +1 -0
- package/dist/server/services/orchestrator.d.ts +69 -0
- package/dist/server/services/orchestrator.d.ts.map +1 -0
- package/dist/server/services/orchestrator.js +642 -0
- package/dist/server/services/orchestrator.js.map +1 -0
- package/dist/server/services/pipeline-orchestrator.d.ts +43 -0
- package/dist/server/services/pipeline-orchestrator.d.ts.map +1 -0
- package/dist/server/services/pipeline-orchestrator.js +503 -0
- package/dist/server/services/pipeline-orchestrator.js.map +1 -0
- package/dist/server/services/prompt-guard.d.ts +19 -0
- package/dist/server/services/prompt-guard.d.ts.map +1 -0
- package/dist/server/services/prompt-guard.js +43 -0
- package/dist/server/services/prompt-guard.js.map +1 -0
- package/dist/server/services/scheduler.d.ts +43 -0
- package/dist/server/services/scheduler.d.ts.map +1 -0
- package/dist/server/services/scheduler.js +199 -0
- package/dist/server/services/scheduler.js.map +1 -0
- package/dist/server/services/skill-injector.d.ts +17 -0
- package/dist/server/services/skill-injector.d.ts.map +1 -0
- package/dist/server/services/skill-injector.js +60 -0
- package/dist/server/services/skill-injector.js.map +1 -0
- package/dist/server/services/tunnel-manager.d.ts +42 -0
- package/dist/server/services/tunnel-manager.d.ts.map +1 -0
- package/dist/server/services/tunnel-manager.js +265 -0
- package/dist/server/services/tunnel-manager.js.map +1 -0
- package/dist/server/services/worktree-manager.d.ts +117 -0
- package/dist/server/services/worktree-manager.d.ts.map +1 -0
- package/dist/server/services/worktree-manager.js +400 -0
- package/dist/server/services/worktree-manager.js.map +1 -0
- package/dist/server/websocket/broadcaster.d.ts +12 -0
- package/dist/server/websocket/broadcaster.d.ts.map +1 -0
- package/dist/server/websocket/broadcaster.js +23 -0
- package/dist/server/websocket/broadcaster.js.map +1 -0
- package/dist/server/websocket/events.d.ts +94 -0
- package/dist/server/websocket/events.d.ts.map +1 -0
- package/dist/server/websocket/events.js +2 -0
- package/dist/server/websocket/events.js.map +1 -0
- package/dist/server/websocket/index.d.ts +3 -0
- package/dist/server/websocket/index.d.ts.map +1 -0
- package/dist/server/websocket/index.js +82 -0
- package/dist/server/websocket/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { Readable, Writable } from 'stream';
|
|
3
|
+
import * as pty from 'node-pty';
|
|
4
|
+
import treeKill from 'tree-kill';
|
|
5
|
+
import { getAdapter } from './cli-adapters.js';
|
|
6
|
+
export class ClaudeManager {
|
|
7
|
+
processes = new Map();
|
|
8
|
+
stdinStreams = new Map();
|
|
9
|
+
/**
|
|
10
|
+
* Start a CLI tool in a worktree directory.
|
|
11
|
+
* Uses node-pty for tools that require a TTY (e.g. Codex),
|
|
12
|
+
* falls back to child_process.spawn for others.
|
|
13
|
+
*/
|
|
14
|
+
async startClaude(worktreePath, prompt, model, extraOptions, mode = 'headless', tool = 'claude', maxTurns, projectPath, sandboxMode) {
|
|
15
|
+
const adapter = getAdapter(tool);
|
|
16
|
+
const args = adapter.buildArgs({ mode, prompt, model, extraOptions, maxTurns, workDir: worktreePath, projectPath: projectPath || worktreePath, sandboxMode });
|
|
17
|
+
if (adapter.requiresTty || mode === 'interactive') {
|
|
18
|
+
const stdinPrompt = adapter.needsStdin(mode) ? adapter.formatStdinPrompt(prompt, mode) : undefined;
|
|
19
|
+
const result = await this.startWithPty(adapter.command, args, worktreePath, adapter.displayName, stdinPrompt, mode === 'interactive');
|
|
20
|
+
return { ...result, command: adapter.command, args };
|
|
21
|
+
}
|
|
22
|
+
const result = await this.startWithSpawn(adapter, args, worktreePath, prompt, mode);
|
|
23
|
+
return { ...result, command: adapter.command, args };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Spawn using node-pty for CLIs that require a TTY.
|
|
27
|
+
*/
|
|
28
|
+
startWithPty(command, args, cwd, displayName, stdinPrompt, interactive) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
let ptyProcess;
|
|
31
|
+
try {
|
|
32
|
+
// On Windows, use cmd.exe to resolve .cmd shims (e.g. codex.cmd)
|
|
33
|
+
const ptyCommand = process.platform === 'win32' ? 'cmd.exe' : command;
|
|
34
|
+
const ptyArgs = process.platform === 'win32' ? ['/c', command, ...args] : args;
|
|
35
|
+
ptyProcess = pty.spawn(ptyCommand, ptyArgs, {
|
|
36
|
+
name: 'xterm-256color',
|
|
37
|
+
cols: 200,
|
|
38
|
+
rows: 50,
|
|
39
|
+
cwd,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
reject(new Error(`Failed to spawn ${displayName}. Is it installed and on PATH? ${err instanceof Error ? err.message : String(err)}`));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const pid = ptyProcess.pid;
|
|
47
|
+
// ANSI escape code stripper
|
|
48
|
+
const stripAnsi = (str) => str.replace(/\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\)|\x1B[()][A-Z0-9]|\x1B[>=<]|\x1B\[[\?]?[0-9;]*[hlJKm]/g, '');
|
|
49
|
+
// Create a Readable stream from pty data (PTY merges stdout+stderr)
|
|
50
|
+
const stdoutStream = new Readable({ read() { } });
|
|
51
|
+
let stdinDelivered = false;
|
|
52
|
+
let exited = false;
|
|
53
|
+
// Trust prompt tracking: block stdin delivery only while trust prompt is visible
|
|
54
|
+
let trustPending = false;
|
|
55
|
+
ptyProcess.onData((data) => {
|
|
56
|
+
const clean = stripAnsi(data);
|
|
57
|
+
stdoutStream.push(clean);
|
|
58
|
+
// Auto-confirm workspace trust prompt (shown when Claude CLI runs without --print)
|
|
59
|
+
if (!trustPending && !exited && /Yes,\s*I\s*trust\s*this/i.test(clean)) {
|
|
60
|
+
trustPending = true;
|
|
61
|
+
try {
|
|
62
|
+
ptyProcess.write('\r');
|
|
63
|
+
}
|
|
64
|
+
catch { /* PTY may have exited */ }
|
|
65
|
+
}
|
|
66
|
+
// Clear pending flag once trust is confirmed (CLI proceeds past the prompt)
|
|
67
|
+
if (trustPending && /Welcome\s*back|›|>\s*$/.test(clean) && !/trust/i.test(clean)) {
|
|
68
|
+
trustPending = false;
|
|
69
|
+
}
|
|
70
|
+
// Detect CLI ready state and deliver prompt via stdin.
|
|
71
|
+
// Codex outputs '›' when ready for input. We also detect common
|
|
72
|
+
// prompt characters ($, >, %) as fallback for other PTY-based CLIs.
|
|
73
|
+
// A 10-second fallback timer ensures delivery even if detection fails.
|
|
74
|
+
// Skip detection while trust prompt is pending to avoid matching its '>' marker.
|
|
75
|
+
if (stdinPrompt && !stdinDelivered && !exited && !trustPending) {
|
|
76
|
+
if (/[›>$%]\s*$/.test(clean)) {
|
|
77
|
+
stdinDelivered = true;
|
|
78
|
+
try {
|
|
79
|
+
ptyProcess.write(stdinPrompt);
|
|
80
|
+
}
|
|
81
|
+
catch { /* PTY may have exited */ }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
// Empty stderr (PTY combines both streams)
|
|
86
|
+
const stderrStream = new Readable({ read() { } });
|
|
87
|
+
stderrStream.push(null);
|
|
88
|
+
const managedProcess = {
|
|
89
|
+
kill: () => { try {
|
|
90
|
+
ptyProcess.kill();
|
|
91
|
+
}
|
|
92
|
+
catch { /* ignore */ } },
|
|
93
|
+
pid,
|
|
94
|
+
};
|
|
95
|
+
this.processes.set(pid, managedProcess);
|
|
96
|
+
// For interactive mode, expose PTY write as a stdin stream for relay
|
|
97
|
+
if (interactive) {
|
|
98
|
+
const ptyWritable = new Writable({
|
|
99
|
+
write(chunk, _encoding, callback) {
|
|
100
|
+
try {
|
|
101
|
+
ptyProcess.write(chunk.toString());
|
|
102
|
+
}
|
|
103
|
+
catch { /* PTY may have exited */ }
|
|
104
|
+
callback();
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
this.stdinStreams.set(pid, ptyWritable);
|
|
108
|
+
}
|
|
109
|
+
const exitPromise = new Promise((resolveExit) => {
|
|
110
|
+
ptyProcess.onExit(({ exitCode }) => {
|
|
111
|
+
exited = true;
|
|
112
|
+
stdoutStream.push(null);
|
|
113
|
+
this.processes.delete(pid);
|
|
114
|
+
this.stdinStreams.delete(pid);
|
|
115
|
+
resolveExit(exitCode);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
// Fallback: if ready-state detection doesn't trigger within 10s, send anyway
|
|
119
|
+
if (stdinPrompt) {
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
if (!stdinDelivered && !exited) {
|
|
122
|
+
stdinDelivered = true;
|
|
123
|
+
try {
|
|
124
|
+
ptyProcess.write(stdinPrompt);
|
|
125
|
+
}
|
|
126
|
+
catch { /* PTY may have exited */ }
|
|
127
|
+
}
|
|
128
|
+
}, 10000);
|
|
129
|
+
}
|
|
130
|
+
setImmediate(() => {
|
|
131
|
+
resolve({
|
|
132
|
+
pid,
|
|
133
|
+
stdout: stdoutStream,
|
|
134
|
+
stderr: stderrStream,
|
|
135
|
+
stdin: null,
|
|
136
|
+
exitPromise,
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Spawn using child_process for standard CLIs.
|
|
143
|
+
*/
|
|
144
|
+
startWithSpawn(adapter, args, cwd, prompt, mode) {
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
let child;
|
|
147
|
+
const needsStdin = adapter.needsStdin(mode);
|
|
148
|
+
try {
|
|
149
|
+
child = spawn(adapter.command, args, {
|
|
150
|
+
cwd,
|
|
151
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
152
|
+
// shell needed on Windows to resolve .cmd shims (claude.cmd, gemini.cmd)
|
|
153
|
+
// Safe: prompts are delivered via stdin, not as command-line arguments
|
|
154
|
+
shell: process.platform === 'win32',
|
|
155
|
+
windowsHide: true,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
reject(new Error(`Failed to spawn ${adapter.displayName}. Is it installed and on PATH? ${err instanceof Error ? err.message : String(err)}`));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
child.on('error', (err) => {
|
|
163
|
+
reject(new Error(`Failed to start ${adapter.displayName}. Is it installed and on PATH? ${err.message}`));
|
|
164
|
+
});
|
|
165
|
+
const pid = child.pid;
|
|
166
|
+
if (pid === undefined) {
|
|
167
|
+
reject(new Error(`Failed to get PID for ${adapter.displayName} process`));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const managedProcess = {
|
|
171
|
+
kill: (signal) => child.kill(signal),
|
|
172
|
+
pid,
|
|
173
|
+
};
|
|
174
|
+
this.processes.set(pid, managedProcess);
|
|
175
|
+
// Handle stdin based on mode
|
|
176
|
+
if (needsStdin && child.stdin) {
|
|
177
|
+
child.stdin.write(adapter.formatStdinPrompt(prompt, mode));
|
|
178
|
+
if (mode === 'interactive') {
|
|
179
|
+
this.stdinStreams.set(pid, child.stdin);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
child.stdin.end();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (child.stdin) {
|
|
186
|
+
child.stdin.end();
|
|
187
|
+
}
|
|
188
|
+
const exitPromise = new Promise((resolveExit) => {
|
|
189
|
+
child.on('exit', (code) => {
|
|
190
|
+
this.processes.delete(pid);
|
|
191
|
+
this.stdinStreams.delete(pid);
|
|
192
|
+
resolveExit(code ?? 1);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
setImmediate(() => {
|
|
196
|
+
resolve({
|
|
197
|
+
pid,
|
|
198
|
+
stdout: child.stdout,
|
|
199
|
+
stderr: child.stderr,
|
|
200
|
+
stdin: child.stdin ?? null,
|
|
201
|
+
exitPromise,
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Write data to the stdin of an interactive process.
|
|
208
|
+
*/
|
|
209
|
+
writeToStdin(pid, data) {
|
|
210
|
+
const stdin = this.stdinStreams.get(pid);
|
|
211
|
+
if (!stdin || stdin.destroyed)
|
|
212
|
+
return false;
|
|
213
|
+
stdin.write(data);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Stop a CLI process. Uses tree-kill to kill the entire process tree
|
|
218
|
+
* (necessary on Windows where shell: true wraps CLIs in cmd.exe).
|
|
219
|
+
* Sends SIGTERM first, escalates to SIGKILL after 5 seconds.
|
|
220
|
+
*/
|
|
221
|
+
async stopClaude(pid) {
|
|
222
|
+
const proc = this.processes.get(pid);
|
|
223
|
+
if (!proc) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
// End stdin stream before killing
|
|
227
|
+
const stdin = this.stdinStreams.get(pid);
|
|
228
|
+
if (stdin) {
|
|
229
|
+
try {
|
|
230
|
+
stdin.end();
|
|
231
|
+
}
|
|
232
|
+
catch { /* ignore */ }
|
|
233
|
+
this.stdinStreams.delete(pid);
|
|
234
|
+
}
|
|
235
|
+
// Try graceful tree-kill first (kills entire process tree)
|
|
236
|
+
try {
|
|
237
|
+
treeKill(pid, 'SIGTERM');
|
|
238
|
+
}
|
|
239
|
+
catch { /* ignore */ }
|
|
240
|
+
return new Promise((resolve) => {
|
|
241
|
+
// Poll for process exit (exit handler in startWithSpawn/startWithPty deletes from map)
|
|
242
|
+
const checkInterval = setInterval(() => {
|
|
243
|
+
if (!this.processes.has(pid)) {
|
|
244
|
+
clearInterval(checkInterval);
|
|
245
|
+
clearTimeout(killTimer);
|
|
246
|
+
clearTimeout(deadline);
|
|
247
|
+
resolve();
|
|
248
|
+
}
|
|
249
|
+
}, 200);
|
|
250
|
+
// Escalate to SIGKILL after 5 seconds if still alive
|
|
251
|
+
const killTimer = setTimeout(() => {
|
|
252
|
+
try {
|
|
253
|
+
treeKill(pid, 'SIGKILL');
|
|
254
|
+
}
|
|
255
|
+
catch { /* ignore */ }
|
|
256
|
+
}, 5000);
|
|
257
|
+
// Final deadline: force-cleanup and resolve after 7 seconds
|
|
258
|
+
const deadline = setTimeout(() => {
|
|
259
|
+
clearInterval(checkInterval);
|
|
260
|
+
clearTimeout(killTimer);
|
|
261
|
+
this.processes.delete(pid);
|
|
262
|
+
resolve();
|
|
263
|
+
}, 7000);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
isRunning(pid) {
|
|
267
|
+
return this.processes.has(pid);
|
|
268
|
+
}
|
|
269
|
+
async killAll() {
|
|
270
|
+
const pids = Array.from(this.processes.keys());
|
|
271
|
+
await Promise.all(pids.map((pid) => this.stopClaude(pid)));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
export const claudeManager = new ClaudeManager();
|
|
275
|
+
//# sourceMappingURL=claude-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-manager.js","sourceRoot":"","sources":["../../../src/server/services/claude-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type CliTool = 'claude' | 'gemini' | 'codex';
|
|
2
|
+
export type CliMode = 'headless' | 'interactive' | 'verbose';
|
|
3
|
+
export type SandboxMode = 'strict' | 'permissive';
|
|
4
|
+
/**
|
|
5
|
+
* Validate and sanitize extra CLI options from user input.
|
|
6
|
+
* Only allows simple flags like --flag or --flag=value.
|
|
7
|
+
*/
|
|
8
|
+
export declare function sanitizeExtraOptions(extraOptions: string): string[];
|
|
9
|
+
export interface CliAdapter {
|
|
10
|
+
/** Executable command name */
|
|
11
|
+
command: string;
|
|
12
|
+
/** Display name for logs */
|
|
13
|
+
displayName: string;
|
|
14
|
+
/** Build the args array for spawning */
|
|
15
|
+
buildArgs(opts: {
|
|
16
|
+
mode: CliMode;
|
|
17
|
+
prompt: string;
|
|
18
|
+
model?: string;
|
|
19
|
+
extraOptions?: string;
|
|
20
|
+
maxTurns?: number;
|
|
21
|
+
workDir?: string;
|
|
22
|
+
projectPath?: string;
|
|
23
|
+
sandboxMode?: SandboxMode;
|
|
24
|
+
}): string[];
|
|
25
|
+
/** Whether this mode needs stdin pipe */
|
|
26
|
+
needsStdin(mode: CliMode): boolean;
|
|
27
|
+
/** Format prompt for stdin delivery */
|
|
28
|
+
formatStdinPrompt(prompt: string, mode?: CliMode): string;
|
|
29
|
+
/** Whether this CLI requires a TTY (pseudo-terminal) to run */
|
|
30
|
+
requiresTty?: boolean;
|
|
31
|
+
/** Output format: 'stream-json' for structured JSON lines, 'text' for plain text */
|
|
32
|
+
outputFormat?: 'text' | 'stream-json';
|
|
33
|
+
}
|
|
34
|
+
export declare function getAdapter(tool: CliTool): CliAdapter;
|
|
35
|
+
//# sourceMappingURL=cli-adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-adapters.d.ts","sourceRoot":"","sources":["../../../src/server/services/cli-adapters.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AACpD,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;AAC7D,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,YAAY,CAAC;AAQlD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAmBnE;AASD,MAAM,WAAW,UAAU;IACzB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,SAAS,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,MAAM,EAAE,CAAC;IAC1L,yCAAyC;IACzC,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,uCAAuC;IACvC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1D,+DAA+D;IAC/D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oFAAoF;IACpF,YAAY,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CACvC;AAmGD,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAEpD"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { isModelSupported } from '../db/queries.js';
|
|
3
|
+
// Allowed CLI option patterns (flags that are safe to pass through)
|
|
4
|
+
const ALLOWED_OPTION_PATTERN = /^--?[a-zA-Z][a-zA-Z0-9_-]*(?:=\S+)?$/;
|
|
5
|
+
// Dangerous shell characters that could enable injection
|
|
6
|
+
const DANGEROUS_CHARS = /[;&|`$(){}[\]<>!#~'"\\]/;
|
|
7
|
+
/**
|
|
8
|
+
* Validate and sanitize extra CLI options from user input.
|
|
9
|
+
* Only allows simple flags like --flag or --flag=value.
|
|
10
|
+
*/
|
|
11
|
+
export function sanitizeExtraOptions(extraOptions) {
|
|
12
|
+
if (!extraOptions || typeof extraOptions !== 'string')
|
|
13
|
+
return [];
|
|
14
|
+
const parts = extraOptions.split(/\s+/).filter(Boolean);
|
|
15
|
+
const sanitized = [];
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
if (DANGEROUS_CHARS.test(part)) {
|
|
18
|
+
console.warn(`Rejected dangerous CLI option: ${part}`);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (!ALLOWED_OPTION_PATTERN.test(part)) {
|
|
22
|
+
console.warn(`Rejected invalid CLI option format: ${part}`);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
sanitized.push(part);
|
|
26
|
+
}
|
|
27
|
+
return sanitized;
|
|
28
|
+
}
|
|
29
|
+
function normalizeModel(model, cliTool) {
|
|
30
|
+
if (!model)
|
|
31
|
+
return undefined;
|
|
32
|
+
if (isModelSupported(cliTool, model))
|
|
33
|
+
return model;
|
|
34
|
+
console.warn(`Unsupported ${cliTool} model "${model}" ignored; falling back to default model.`);
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
const TASK_COMPLETION_SUFFIX = `
|
|
38
|
+
|
|
39
|
+
IMPORTANT: Work efficiently and stop when done.
|
|
40
|
+
- Use grep/glob to find target files. Do NOT read every file or use Explore agents for simple tasks.
|
|
41
|
+
- Only read files you need to modify. Make edits directly without re-reading.
|
|
42
|
+
- Once complete, commit all changes and stop. No additional refactoring, testing, or review.`;
|
|
43
|
+
const claudeAdapter = {
|
|
44
|
+
command: 'claude',
|
|
45
|
+
displayName: 'Claude CLI',
|
|
46
|
+
outputFormat: 'stream-json',
|
|
47
|
+
buildArgs({ mode, prompt, model, extraOptions, maxTurns, sandboxMode }) {
|
|
48
|
+
const normalizedModel = normalizeModel(model, 'claude');
|
|
49
|
+
const args = [];
|
|
50
|
+
if (sandboxMode === 'strict') {
|
|
51
|
+
args.push('--permission-mode', 'dontAsk');
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
args.push('--dangerously-skip-permissions');
|
|
55
|
+
}
|
|
56
|
+
if (mode !== 'interactive') {
|
|
57
|
+
args.push('--print', '--verbose', '--output-format', 'stream-json');
|
|
58
|
+
}
|
|
59
|
+
if (normalizedModel)
|
|
60
|
+
args.push('--model', normalizedModel);
|
|
61
|
+
if (maxTurns && maxTurns > 0)
|
|
62
|
+
args.push('--max-turns', String(maxTurns));
|
|
63
|
+
if (extraOptions) {
|
|
64
|
+
args.push(...sanitizeExtraOptions(extraOptions));
|
|
65
|
+
}
|
|
66
|
+
// Prompt is delivered via stdin pipe (avoids shell escaping issues with newlines)
|
|
67
|
+
return args;
|
|
68
|
+
},
|
|
69
|
+
needsStdin(_mode) {
|
|
70
|
+
return true;
|
|
71
|
+
},
|
|
72
|
+
formatStdinPrompt(prompt, mode) {
|
|
73
|
+
if (mode === 'interactive')
|
|
74
|
+
return prompt + '\n';
|
|
75
|
+
return prompt + TASK_COMPLETION_SUFFIX + '\n';
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
const geminiAdapter = {
|
|
79
|
+
command: 'gemini',
|
|
80
|
+
displayName: 'Gemini CLI',
|
|
81
|
+
buildArgs({ mode, prompt, model, extraOptions }) {
|
|
82
|
+
// Gemini CLI: --yolo auto-approves all tool actions (file writes, shell commands)
|
|
83
|
+
// -p enables headless (non-interactive) mode; prompt text is delivered via stdin pipe
|
|
84
|
+
const args = ['--yolo'];
|
|
85
|
+
if (model)
|
|
86
|
+
args.push('--model', model);
|
|
87
|
+
if (extraOptions) {
|
|
88
|
+
args.push(...sanitizeExtraOptions(extraOptions));
|
|
89
|
+
}
|
|
90
|
+
return args;
|
|
91
|
+
},
|
|
92
|
+
needsStdin(_mode) {
|
|
93
|
+
return true;
|
|
94
|
+
},
|
|
95
|
+
formatStdinPrompt(prompt) {
|
|
96
|
+
return prompt + '\n';
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
const codexAdapter = {
|
|
100
|
+
command: 'codex',
|
|
101
|
+
displayName: 'Codex CLI',
|
|
102
|
+
buildArgs({ mode, prompt, model, extraOptions, workDir, projectPath, sandboxMode }) {
|
|
103
|
+
const normalizedModel = normalizeModel(model, 'codex');
|
|
104
|
+
const args = ['exec'];
|
|
105
|
+
if (sandboxMode === 'strict') {
|
|
106
|
+
// Use --full-auto (workspace-write sandbox) with --add-dir to allow git metadata access.
|
|
107
|
+
// Git worktree metadata lives at <projectPath>/.git/worktrees/, so we whitelist the .git dir.
|
|
108
|
+
args.push('--full-auto');
|
|
109
|
+
if (workDir && projectPath && workDir !== projectPath) {
|
|
110
|
+
const gitDir = path.join(projectPath, '.git');
|
|
111
|
+
args.push('--add-dir', gitDir);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
args.push('--dangerously-bypass-approvals-and-sandbox');
|
|
116
|
+
}
|
|
117
|
+
if (normalizedModel)
|
|
118
|
+
args.push('--model', normalizedModel);
|
|
119
|
+
if (extraOptions) {
|
|
120
|
+
args.push(...sanitizeExtraOptions(extraOptions));
|
|
121
|
+
}
|
|
122
|
+
return args;
|
|
123
|
+
},
|
|
124
|
+
needsStdin(_mode) {
|
|
125
|
+
return true;
|
|
126
|
+
},
|
|
127
|
+
formatStdinPrompt(prompt) {
|
|
128
|
+
return prompt + '\n';
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
const adapters = {
|
|
132
|
+
claude: claudeAdapter,
|
|
133
|
+
gemini: geminiAdapter,
|
|
134
|
+
codex: codexAdapter,
|
|
135
|
+
};
|
|
136
|
+
export function getAdapter(tool) {
|
|
137
|
+
return adapters[tool] ?? adapters.claude;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=cli-adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-adapters.js","sourceRoot":"","sources":["../../../src/server/services/cli-adapters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface DebugSession {
|
|
2
|
+
writeStdin(content: string): void;
|
|
3
|
+
teeStdout(original: NodeJS.ReadableStream): NodeJS.ReadableStream;
|
|
4
|
+
teeStderr(original: NodeJS.ReadableStream): NodeJS.ReadableStream;
|
|
5
|
+
finalize(exitCode: number): void;
|
|
6
|
+
readonly filePath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface DebugLogFile {
|
|
9
|
+
name: string;
|
|
10
|
+
todoId: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
size: number;
|
|
13
|
+
}
|
|
14
|
+
declare class DebugLogger {
|
|
15
|
+
private getDebugDir;
|
|
16
|
+
private ensureDir;
|
|
17
|
+
startSession(opts: {
|
|
18
|
+
todoId: string;
|
|
19
|
+
projectPath: string;
|
|
20
|
+
cliTool: string;
|
|
21
|
+
command: string;
|
|
22
|
+
args: string[];
|
|
23
|
+
workDir: string;
|
|
24
|
+
model?: string;
|
|
25
|
+
sandboxMode?: string;
|
|
26
|
+
}): DebugSession;
|
|
27
|
+
listLogs(projectPath: string, todoId?: string): DebugLogFile[];
|
|
28
|
+
readLog(projectPath: string, filename: string): string | null;
|
|
29
|
+
deleteLog(projectPath: string, filename: string): boolean;
|
|
30
|
+
deleteAllLogs(projectPath: string): number;
|
|
31
|
+
cleanupOldLogs(projectPath: string, retentionDays: number): number;
|
|
32
|
+
}
|
|
33
|
+
export declare const debugLogger: DebugLogger;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=debug-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-logger.d.ts","sourceRoot":"","sources":["../../../src/server/services/debug-logger.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IAClE,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,cAAM,WAAW;IACf,OAAO,CAAC,WAAW;IAInB,OAAO,CAAC,SAAS;IAMjB,YAAY,CAAC,IAAI,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,YAAY;IAmFhB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IA0B9D,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO7D,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQzD,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;IAU1C,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM;CAgBnE;AAED,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|