poe-code 1.2.1 → 2.0.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.
Files changed (156) hide show
  1. package/README.md +16 -20
  2. package/dist/cli/bootstrap.d.ts +4 -0
  3. package/dist/cli/bootstrap.js +75 -0
  4. package/dist/cli/bootstrap.js.map +1 -0
  5. package/dist/cli/commands/configure.d.ts +2 -1
  6. package/dist/cli/commands/configure.js +7 -7
  7. package/dist/cli/commands/configure.js.map +1 -1
  8. package/dist/cli/container.d.ts +0 -5
  9. package/dist/cli/container.js +0 -8
  10. package/dist/cli/container.js.map +1 -1
  11. package/dist/cli/error-logger.d.ts +17 -2
  12. package/dist/cli/error-logger.js.map +1 -1
  13. package/dist/cli/errors.d.ts +6 -0
  14. package/dist/cli/errors.js +8 -0
  15. package/dist/cli/errors.js.map +1 -1
  16. package/dist/cli/program.js +6 -26
  17. package/dist/cli/program.js.map +1 -1
  18. package/dist/cli/prompt-runner.d.ts +3 -0
  19. package/dist/cli/prompt-runner.js +9 -0
  20. package/dist/cli/prompt-runner.js.map +1 -0
  21. package/dist/cli/service-registry.d.ts +8 -0
  22. package/dist/cli/service-registry.js.map +1 -1
  23. package/dist/cli/ui/service-menu.d.ts +6 -0
  24. package/dist/cli/ui/service-menu.js +37 -0
  25. package/dist/cli/ui/service-menu.js.map +1 -0
  26. package/dist/cli/ui/theme.d.ts +16 -0
  27. package/dist/cli/ui/theme.js +78 -0
  28. package/dist/cli/ui/theme.js.map +1 -0
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +2 -74
  31. package/dist/index.js.map +1 -1
  32. package/dist/providers/claude-code-adapter.js +6 -0
  33. package/dist/providers/claude-code-adapter.js.map +1 -1
  34. package/dist/providers/codex-adapter.js +6 -0
  35. package/dist/providers/codex-adapter.js.map +1 -1
  36. package/dist/providers/opencode-adapter.js +6 -0
  37. package/dist/providers/opencode-adapter.js.map +1 -1
  38. package/package.json +13 -34
  39. package/dist/cli/api-client.d.ts +0 -14
  40. package/dist/cli/api-client.js +0 -140
  41. package/dist/cli/api-client.js.map +0 -1
  42. package/dist/cli/chat.d.ts +0 -32
  43. package/dist/cli/chat.js +0 -2
  44. package/dist/cli/chat.js.map +0 -1
  45. package/dist/cli/commands/agent.d.ts +0 -18
  46. package/dist/cli/commands/agent.js +0 -84
  47. package/dist/cli/commands/agent.js.map +0 -1
  48. package/dist/cli/commands/configure-agents.d.ts +0 -3
  49. package/dist/cli/commands/configure-agents.js +0 -72
  50. package/dist/cli/commands/configure-agents.js.map +0 -1
  51. package/dist/cli/commands/init.d.ts +0 -8
  52. package/dist/cli/commands/init.js +0 -45
  53. package/dist/cli/commands/init.js.map +0 -1
  54. package/dist/cli/commands/interactive.d.ts +0 -3
  55. package/dist/cli/commands/interactive.js +0 -17
  56. package/dist/cli/commands/interactive.js.map +0 -1
  57. package/dist/cli/commands/login.d.ts +0 -6
  58. package/dist/cli/commands/login.js +0 -51
  59. package/dist/cli/commands/login.js.map +0 -1
  60. package/dist/cli/commands/logout.d.ts +0 -3
  61. package/dist/cli/commands/logout.js +0 -31
  62. package/dist/cli/commands/logout.js.map +0 -1
  63. package/dist/cli/commands/prerequisites.d.ts +0 -3
  64. package/dist/cli/commands/prerequisites.js +0 -23
  65. package/dist/cli/commands/prerequisites.js.map +0 -1
  66. package/dist/cli/commands/query.d.ts +0 -7
  67. package/dist/cli/commands/query.js +0 -46
  68. package/dist/cli/commands/query.js.map +0 -1
  69. package/dist/cli/commands/remove.d.ts +0 -6
  70. package/dist/cli/commands/remove.js +0 -80
  71. package/dist/cli/commands/remove.js.map +0 -1
  72. package/dist/cli/commands/root.d.ts +0 -3
  73. package/dist/cli/commands/root.js +0 -7
  74. package/dist/cli/commands/root.js.map +0 -1
  75. package/dist/cli/commands/spawn-worktree.d.ts +0 -6
  76. package/dist/cli/commands/spawn-worktree.js +0 -91
  77. package/dist/cli/commands/spawn-worktree.js.map +0 -1
  78. package/dist/cli/commands/spawn.d.ts +0 -7
  79. package/dist/cli/commands/spawn.js +0 -112
  80. package/dist/cli/commands/spawn.js.map +0 -1
  81. package/dist/cli/commands/test.d.ts +0 -6
  82. package/dist/cli/commands/test.js +0 -26
  83. package/dist/cli/commands/test.js.map +0 -1
  84. package/dist/cli/file-mentions.d.ts +0 -13
  85. package/dist/cli/file-mentions.js +0 -87
  86. package/dist/cli/file-mentions.js.map +0 -1
  87. package/dist/cli/file-picker-state.d.ts +0 -14
  88. package/dist/cli/file-picker-state.js +0 -23
  89. package/dist/cli/file-picker-state.js.map +0 -1
  90. package/dist/cli/interactive-command-runner.d.ts +0 -11
  91. package/dist/cli/interactive-command-runner.js +0 -142
  92. package/dist/cli/interactive-command-runner.js.map +0 -1
  93. package/dist/cli/interactive-launcher.d.ts +0 -2
  94. package/dist/cli/interactive-launcher.js +0 -404
  95. package/dist/cli/interactive-launcher.js.map +0 -1
  96. package/dist/cli/interactive-tasks.d.ts +0 -7
  97. package/dist/cli/interactive-tasks.js +0 -199
  98. package/dist/cli/interactive-tasks.js.map +0 -1
  99. package/dist/cli/interactive.d.ts +0 -19
  100. package/dist/cli/interactive.js +0 -479
  101. package/dist/cli/interactive.js.map +0 -1
  102. package/dist/cli/markdown-renderer.d.ts +0 -27
  103. package/dist/cli/markdown-renderer.js +0 -178
  104. package/dist/cli/markdown-renderer.js.map +0 -1
  105. package/dist/cli/markdown-renderer.test.d.ts +0 -1
  106. package/dist/cli/markdown-renderer.test.js +0 -105
  107. package/dist/cli/markdown-renderer.test.js.map +0 -1
  108. package/dist/commands/init.d.ts +0 -9
  109. package/dist/commands/init.js +0 -43
  110. package/dist/commands/init.js.map +0 -1
  111. package/dist/commands/spawn-worktree.d.ts +0 -25
  112. package/dist/commands/spawn-worktree.js +0 -139
  113. package/dist/commands/spawn-worktree.js.map +0 -1
  114. package/dist/services/agent-config-manager.d.ts +0 -32
  115. package/dist/services/agent-config-manager.js +0 -130
  116. package/dist/services/agent-config-manager.js.map +0 -1
  117. package/dist/services/agent-registry.d.ts +0 -27
  118. package/dist/services/agent-registry.js +0 -89
  119. package/dist/services/agent-registry.js.map +0 -1
  120. package/dist/services/agent-session.d.ts +0 -24
  121. package/dist/services/agent-session.js +0 -107
  122. package/dist/services/agent-session.js.map +0 -1
  123. package/dist/services/agent-task-registry.d.ts +0 -131
  124. package/dist/services/agent-task-registry.js +0 -491
  125. package/dist/services/agent-task-registry.js.map +0 -1
  126. package/dist/services/chat.d.ts +0 -94
  127. package/dist/services/chat.js +0 -241
  128. package/dist/services/chat.js.map +0 -1
  129. package/dist/services/mcp-client.d.ts +0 -38
  130. package/dist/services/mcp-client.js +0 -170
  131. package/dist/services/mcp-client.js.map +0 -1
  132. package/dist/services/mcp-manager.d.ts +0 -28
  133. package/dist/services/mcp-manager.js +0 -157
  134. package/dist/services/mcp-manager.js.map +0 -1
  135. package/dist/services/poe-code.d.ts +0 -7
  136. package/dist/services/poe-code.js +0 -5
  137. package/dist/services/poe-code.js.map +0 -1
  138. package/dist/services/task-logger.d.ts +0 -24
  139. package/dist/services/task-logger.js +0 -73
  140. package/dist/services/task-logger.js.map +0 -1
  141. package/dist/services/task-runner.d.ts +0 -19
  142. package/dist/services/task-runner.js +0 -157
  143. package/dist/services/task-runner.js.map +0 -1
  144. package/dist/services/tools.d.ts +0 -76
  145. package/dist/services/tools.js +0 -870
  146. package/dist/services/tools.js.map +0 -1
  147. package/dist/utils/e2e-flags.d.ts +0 -1
  148. package/dist/utils/e2e-flags.js +0 -9
  149. package/dist/utils/e2e-flags.js.map +0 -1
  150. package/dist/utils/worktree.d.ts +0 -40
  151. package/dist/utils/worktree.js +0 -179
  152. package/dist/utils/worktree.js.map +0 -1
  153. package/shared/conversation-layout.cjs +0 -11
  154. package/shared/conversation-layout.d.ts +0 -7
  155. package/shared/conversation-layout.js +0 -11
  156. package/shared/package.json +0 -13
@@ -1,870 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import path from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { spawnGitWorktree } from "../commands/spawn-worktree.js";
5
- import { spawnClaudeCode } from "./claude-code.js";
6
- import { simpleGit as createSimpleGit } from "simple-git";
7
- import { tokenizeCommandLine } from "../utils/command-line.js";
8
- import { createDefaultAgentRegistry, LEGACY_DEFAULT_AGENTS } from "./agent-registry.js";
9
- export class DefaultToolExecutor {
10
- constructor(dependencies) {
11
- this.fs = dependencies.fs;
12
- this.cwd = dependencies.cwd;
13
- this.allowedPaths = dependencies.allowedPaths || [dependencies.cwd];
14
- this.mcpManager = dependencies.mcpManager;
15
- this.onWriteFile = dependencies.onWriteFile;
16
- this.taskRegistry = dependencies.taskRegistry;
17
- this.eventLogger = dependencies.logger ?? (() => { });
18
- this.now = dependencies.now ?? Date.now;
19
- this.spawnTask =
20
- dependencies.spawnBackgroundTask ??
21
- (this.taskRegistry ? this.createBackgroundSpawner() : undefined);
22
- this.agentRegistry =
23
- dependencies.agentRegistry ?? createDefaultAgentRegistry();
24
- this.agentConfigManager = dependencies.agentConfigManager;
25
- this.homeDir = dependencies.homeDir;
26
- }
27
- async executeTool(name, args) {
28
- // Check if it's an MCP tool
29
- if (name.startsWith("mcp__") && this.mcpManager) {
30
- return await this.mcpManager.executeTool(name, args);
31
- }
32
- switch (name) {
33
- case "read_file":
34
- return await this.readFile(args);
35
- case "write_file":
36
- return await this.writeFile(args);
37
- case "list_files":
38
- return await this.listFiles(args);
39
- case "run_command":
40
- return await this.runCommand(args);
41
- case "search_web":
42
- return await this.searchWeb(args);
43
- case "spawn_git_worktree":
44
- return await this.spawnGitWorktreeTool(args);
45
- default:
46
- throw new Error(`Unknown tool: ${name}`);
47
- }
48
- }
49
- isPathAllowed(filePath) {
50
- const absolutePath = path.isAbsolute(filePath)
51
- ? filePath
52
- : path.join(this.cwd, filePath);
53
- return this.allowedPaths.some((allowedPath) => absolutePath.startsWith(allowedPath));
54
- }
55
- async readFile(args) {
56
- const filePath = args.path;
57
- if (!filePath) {
58
- throw new Error("Missing required parameter: path");
59
- }
60
- if (!this.isPathAllowed(filePath)) {
61
- throw new Error(`Access denied: ${filePath}`);
62
- }
63
- const absolutePath = path.isAbsolute(filePath)
64
- ? filePath
65
- : path.join(this.cwd, filePath);
66
- try {
67
- const content = await this.fs.readFile(absolutePath, "utf8");
68
- return content;
69
- }
70
- catch (error) {
71
- throw new Error(`Failed to read file: ${error instanceof Error ? error.message : String(error)}`);
72
- }
73
- }
74
- async writeFile(args) {
75
- const filePath = args.path;
76
- const content = args.content;
77
- if (!filePath || content === undefined) {
78
- throw new Error("Missing required parameters: path, content");
79
- }
80
- if (!this.isPathAllowed(filePath)) {
81
- throw new Error(`Access denied: ${filePath}`);
82
- }
83
- const absolutePath = path.isAbsolute(filePath)
84
- ? filePath
85
- : path.join(this.cwd, filePath);
86
- const previousContent = await this.tryReadFile(absolutePath);
87
- try {
88
- await this.fs.writeFile(absolutePath, content, { encoding: "utf8" });
89
- if (this.onWriteFile) {
90
- await this.onWriteFile({
91
- absolutePath,
92
- relativePath: path.relative(this.cwd, absolutePath),
93
- previousContent,
94
- nextContent: content
95
- });
96
- }
97
- return `Successfully wrote to ${filePath}`;
98
- }
99
- catch (error) {
100
- throw new Error(`Failed to write file: ${error instanceof Error ? error.message : String(error)}`);
101
- }
102
- }
103
- async listFiles(args) {
104
- const dirPath = args.path || ".";
105
- if (!this.isPathAllowed(dirPath)) {
106
- throw new Error(`Access denied: ${dirPath}`);
107
- }
108
- const absolutePath = path.isAbsolute(dirPath)
109
- ? dirPath
110
- : path.join(this.cwd, dirPath);
111
- try {
112
- const files = await this.fs.readdir(absolutePath);
113
- return JSON.stringify(files, null, 2);
114
- }
115
- catch (error) {
116
- throw new Error(`Failed to list files: ${error instanceof Error ? error.message : String(error)}`);
117
- }
118
- }
119
- async runCommand(args) {
120
- const commandValue = args.command;
121
- if (typeof commandValue !== "string" || commandValue.trim().length === 0) {
122
- throw new Error("Missing required parameter: command");
123
- }
124
- const tokens = tokenizeCommandLine(commandValue);
125
- if (tokens.length === 0) {
126
- throw new Error("Missing required parameter: command");
127
- }
128
- const [executable, ...commandArgs] = tokens;
129
- if (this.isManagedCommand(executable)) {
130
- return await this.runManagedCommand(executable, commandArgs);
131
- }
132
- return await this.executeExternalCommand(executable, commandArgs);
133
- }
134
- isManagedCommand(command) {
135
- return command === "claude-code" || command === "claude";
136
- }
137
- async runManagedCommand(command, args) {
138
- if (command === "claude-code" || command === "claude") {
139
- return await this.executeClaudeCodeCommand(args);
140
- }
141
- throw new Error(`Unsupported managed command "${command}".`);
142
- }
143
- async executeClaudeCodeCommand(args) {
144
- if (args.length === 0) {
145
- throw new Error("Claude Code requires a prompt argument (e.g. claude-code \"Write hello world\").");
146
- }
147
- const [firstArg, ...rest] = args;
148
- const promptParts = [firstArg];
149
- let forwardedArgs = [];
150
- if (rest.length > 0) {
151
- const optionIndex = rest.findIndex((value) => value.startsWith("--"));
152
- if (optionIndex === -1) {
153
- promptParts.push(...rest);
154
- }
155
- else {
156
- promptParts.push(...rest.slice(0, optionIndex));
157
- forwardedArgs = rest.slice(optionIndex);
158
- }
159
- }
160
- const prompt = promptParts.join(" ").trim();
161
- if (prompt.length === 0) {
162
- throw new Error("Claude Code requires a prompt argument (e.g. claude-code \"Write hello world\").");
163
- }
164
- const result = await spawnClaudeCode({
165
- prompt,
166
- args: forwardedArgs,
167
- runCommand: (cmd, commandArgs) => this.runProcess(cmd, commandArgs)
168
- });
169
- if (result.exitCode !== 0) {
170
- if (this.isNotFoundError(result)) {
171
- throw new Error("Claude Code CLI is not installed or not available in the PATH. Run `poe-code configure claude-code` to install it.");
172
- }
173
- const detail = this.formatProcessOutput(result);
174
- const suffix = detail.length > 0 ? ` Details: ${detail}` : "";
175
- throw new Error(`Claude Code failed with exit code ${result.exitCode}.${suffix}`);
176
- }
177
- const output = this.formatProcessOutput(result);
178
- return output.length > 0 ? output : "Claude Code command completed successfully";
179
- }
180
- async executeExternalCommand(executable, args) {
181
- const result = await this.runProcess(executable, args);
182
- if (result.exitCode !== 0) {
183
- if (this.isNotFoundError(result)) {
184
- throw new Error(`Command "${executable}" is not installed or not available in the PATH.`);
185
- }
186
- const detail = this.formatProcessOutput(result);
187
- if (detail.length > 0) {
188
- throw new Error(`Command "${executable}" exited with code ${result.exitCode}.\n${detail}`);
189
- }
190
- throw new Error(`Command "${executable}" exited with code ${result.exitCode}.`);
191
- }
192
- const output = this.formatProcessOutput(result);
193
- return output.length > 0 ? output : "Command completed successfully";
194
- }
195
- async runProcess(command, args) {
196
- return await new Promise((resolve) => {
197
- let settled = false;
198
- let stdout = "";
199
- let stderr = "";
200
- const child = spawn(command, args, {
201
- cwd: this.cwd,
202
- stdio: ["ignore", "pipe", "pipe"]
203
- });
204
- child.stdout?.setEncoding("utf8");
205
- child.stdout?.on("data", (chunk) => {
206
- stdout += chunk.toString();
207
- });
208
- child.stderr?.setEncoding("utf8");
209
- child.stderr?.on("data", (chunk) => {
210
- stderr += chunk.toString();
211
- });
212
- const finish = (result) => {
213
- if (settled) {
214
- return;
215
- }
216
- settled = true;
217
- resolve(result);
218
- };
219
- child.on("error", (error) => {
220
- const exitCode = typeof error.code === "number"
221
- ? error.code
222
- : typeof error.errno === "number"
223
- ? error.errno
224
- : 127;
225
- const message = error instanceof Error ? error.message : String(error ?? "error");
226
- const combinedStderr = stderr.length > 0 ? `${stderr}${stderr.endsWith("\n") ? "" : "\n"}${message}` : message;
227
- finish({
228
- stdout,
229
- stderr: combinedStderr,
230
- exitCode
231
- });
232
- });
233
- child.on("close", (code) => {
234
- finish({
235
- stdout,
236
- stderr,
237
- exitCode: code ?? 0
238
- });
239
- });
240
- });
241
- }
242
- formatProcessOutput(result) {
243
- const stdout = result.stdout.trim();
244
- const stderr = result.stderr.trim();
245
- if (stdout.length > 0 && stderr.length > 0) {
246
- return `${stdout}\n${stderr}`;
247
- }
248
- if (stdout.length > 0) {
249
- return stdout;
250
- }
251
- if (stderr.length > 0) {
252
- return stderr;
253
- }
254
- return "";
255
- }
256
- isNotFoundError(result) {
257
- const stderrLower = result.stderr.toLowerCase();
258
- if (stderrLower.includes("enoent")) {
259
- return true;
260
- }
261
- if (stderrLower.includes("not found")) {
262
- return true;
263
- }
264
- return result.exitCode === 127;
265
- }
266
- async searchWeb(args) {
267
- const query = args.query;
268
- if (!query) {
269
- throw new Error("Missing required parameter: query");
270
- }
271
- // Placeholder for web search - in a real implementation, you'd integrate with a search API
272
- return `Web search functionality not yet implemented. Query: ${query}`;
273
- }
274
- async spawnGitWorktreeTool(args) {
275
- const parsed = this.parseWorktreeArgs(args);
276
- const adapter = await this.resolveAgent(parsed.agent);
277
- const serializableArgs = {
278
- agent: parsed.agent,
279
- prompt: parsed.prompt,
280
- agentArgs: parsed.agentArgs
281
- };
282
- if (parsed.branch) {
283
- serializableArgs.branch = parsed.branch;
284
- }
285
- if (parsed.runAsync) {
286
- serializableArgs.async = true;
287
- }
288
- if (parsed.runAsync && this.taskRegistry && this.spawnTask) {
289
- const taskId = this.taskRegistry.registerTask({
290
- toolName: "spawn_git_worktree",
291
- args: serializableArgs
292
- });
293
- await Promise.resolve(this.spawnTask({
294
- taskId,
295
- toolName: "spawn_git_worktree",
296
- args: serializableArgs,
297
- context: { cwd: this.cwd }
298
- }));
299
- this.eventLogger("task_queued", {
300
- id: taskId,
301
- tool: "spawn_git_worktree"
302
- });
303
- return `Started background task ${taskId}`;
304
- }
305
- return await this.executeWorktreeSynchronously(parsed, adapter);
306
- }
307
- createBackgroundSpawner() {
308
- return (request) => {
309
- if (!this.taskRegistry) {
310
- return;
311
- }
312
- // Build human-readable CLI command
313
- const commandParts = ["spawn-git-worktree"];
314
- if (request.args.agent) {
315
- commandParts.push(String(request.args.agent));
316
- }
317
- if (request.args.prompt) {
318
- commandParts.push(`"${request.args.prompt}"`);
319
- }
320
- if (Array.isArray(request.args.agentArgs) && request.args.agentArgs.length > 0) {
321
- commandParts.push(...request.args.agentArgs.map(String));
322
- }
323
- if (request.args.branch) {
324
- commandParts.push(`--branch ${request.args.branch}`);
325
- }
326
- const commandString = commandParts.join(" ");
327
- // Create inline script that imports and runs the task
328
- const taskData = JSON.stringify({
329
- taskId: request.taskId,
330
- toolName: request.toolName,
331
- args: request.args,
332
- cwd: request.context.cwd,
333
- tasksDir: this.taskRegistry.getTasksDirectory(),
334
- logsDir: this.taskRegistry.getLogsDirectory(),
335
- agentConfigPath: this.agentConfigManager?.getConfigPath() ?? null,
336
- homeDir: this.homeDir ?? null
337
- });
338
- const inlineScript = `
339
- import { spawnGitWorktree } from './commands/spawn-worktree.js';
340
- import { createDefaultAgentRegistry } from './services/agent-registry.js';
341
- import { AgentConfigManager } from './services/agent-config-manager.js';
342
- import { AgentTaskRegistry } from './services/agent-task-registry.js';
343
- import { TaskLogger } from './services/task-logger.js';
344
- import { simpleGit } from 'simple-git';
345
- import { spawn } from 'node:child_process';
346
- import * as fs from 'node:fs';
347
- import path from 'node:path';
348
-
349
- const data = ${taskData};
350
- const fsLike = fs;
351
-
352
- const taskRegistry = new AgentTaskRegistry({
353
- fs: fsLike,
354
- tasksDir: data.tasksDir,
355
- logsDir: data.logsDir
356
- });
357
-
358
- const logger = new TaskLogger({
359
- fs: fsLike,
360
- filePath: path.join(data.logsDir, data.taskId + '.log'),
361
- now: () => new Date()
362
- });
363
-
364
- const progressFile = path.join(data.tasksDir, data.taskId + '.progress.jsonl');
365
- const writeProgress = (update) => {
366
- fs.appendFileSync(progressFile, JSON.stringify(update) + '\\n');
367
- };
368
-
369
- const agentRegistry = createDefaultAgentRegistry();
370
- let agentConfigManager = null;
371
- if (data.agentConfigPath && data.homeDir) {
372
- agentConfigManager = new AgentConfigManager({
373
- fs: fs.promises,
374
- homeDir: data.homeDir,
375
- registry: agentRegistry
376
- });
377
- await agentConfigManager.loadConfig();
378
- }
379
-
380
- async function resolveAgent(adapterId) {
381
- const adapter = agentRegistry.get(adapterId);
382
- if (!adapter) {
383
- throw new Error('Unsupported agent "' + adapterId + '".');
384
- }
385
- if (agentConfigManager) {
386
- const enabled = await agentConfigManager.getEnabledAgents();
387
- if (!enabled.some((entry) => entry.id === adapterId)) {
388
- throw new Error('Agent "' + adapterId + '" is disabled in configuration.');
389
- }
390
- }
391
- return adapter;
392
- }
393
-
394
- async function runCommand(cmd, args, cwd) {
395
- return new Promise((resolve) => {
396
- const child = spawn(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
397
- let stdout = '', stderr = '';
398
- child.stdout?.on('data', (d) => stdout += d);
399
- child.stderr?.on('data', (d) => stderr += d);
400
- child.on('close', (code) => resolve({ stdout, stderr, exitCode: code || 0 }));
401
- });
402
- }
403
-
404
- let agentAdapter;
405
-
406
- async function runAgent(details) {
407
- if (!agentAdapter) {
408
- agentAdapter = await resolveAgent(details.agent);
409
- }
410
- if (details.agent !== data.args.agent) {
411
- throw new Error('Mismatched agent "' + details.agent + '" (expected "' + data.args.agent + '").');
412
- }
413
- return await agentAdapter.spawn({
414
- prompt: details.prompt,
415
- args: details.args,
416
- runCommand: (c, a) => runCommand(c, a, details.cwd)
417
- });
418
- }
419
-
420
- (async () => {
421
- try {
422
- logger.info('Starting ' + data.toolName);
423
- writeProgress({ type: 'progress', message: 'Starting ' + data.toolName, timestamp: Date.now() });
424
-
425
- agentAdapter = await resolveAgent(data.args.agent);
426
-
427
- const git = simpleGit({ baseDir: data.cwd });
428
- const branch = data.args.branch || (await git.revparse(['--abbrev-ref', 'HEAD'])).trim();
429
-
430
- await spawnGitWorktree({
431
- agent: data.args.agent,
432
- prompt: data.args.prompt,
433
- agentArgs: data.args.agentArgs || [],
434
- basePath: data.cwd,
435
- targetBranch: branch,
436
- runAgent,
437
- logger: (msg) => {
438
- logger.info(msg);
439
- writeProgress({ type: 'progress', message: msg, timestamp: Date.now() });
440
- }
441
- });
442
-
443
- const result = 'Worktree workflow completed successfully';
444
- taskRegistry.updateTask(data.taskId, { status: 'completed', result, endTime: Date.now() });
445
- writeProgress({ type: 'complete', result, timestamp: Date.now() });
446
- logger.info('Task completed');
447
- } catch (error) {
448
- const message = error?.message || String(error);
449
- taskRegistry.updateTask(data.taskId, { status: 'failed', error: message, endTime: Date.now() });
450
- writeProgress({ type: 'error', error: message, timestamp: Date.now() });
451
- logger.error('Task failed: ' + message);
452
- process.exit(1);
453
- } finally {
454
- taskRegistry.dispose();
455
- }
456
- })();
457
- `.trim();
458
- try {
459
- // Spawn node with inline script
460
- const child = spawn(process.execPath, ['--input-type=module', '-e', inlineScript], {
461
- cwd: path.join(fileURLToPath(new URL('.', import.meta.url)), '..'),
462
- detached: true,
463
- stdio: ["ignore", "pipe", "pipe"], // Capture stdout/stderr for streaming
464
- env: {
465
- ...process.env
466
- }
467
- });
468
- // Capture stdout/stderr for logging and streaming
469
- let stdoutData = "";
470
- let stderrData = "";
471
- if (child.stdout) {
472
- child.stdout.on("data", (data) => {
473
- const chunk = data.toString();
474
- stdoutData += chunk;
475
- this.eventLogger("task_stdout", {
476
- id: request.taskId,
477
- tool: request.toolName,
478
- chunk
479
- });
480
- });
481
- }
482
- if (child.stderr) {
483
- child.stderr.on("data", (data) => {
484
- const chunk = data.toString();
485
- stderrData += chunk;
486
- this.eventLogger("task_stderr", {
487
- id: request.taskId,
488
- tool: request.toolName,
489
- chunk
490
- });
491
- });
492
- }
493
- // Register error handler BEFORE unref to catch early errors
494
- child.once("error", (error) => {
495
- const message = error instanceof Error ? error.message : String(error);
496
- const parts = [message];
497
- if (stdoutData) {
498
- parts.push(`Stdout: ${stdoutData}`);
499
- }
500
- if (stderrData) {
501
- parts.push(`Stderr: ${stderrData}`);
502
- }
503
- const fullError = parts.join("\n");
504
- this.eventLogger("task_spawn_failed", {
505
- id: request.taskId,
506
- message: fullError
507
- });
508
- this.taskRegistry?.updateTask(request.taskId, {
509
- status: "failed",
510
- error: `Process error: ${fullError}`,
511
- endTime: this.now()
512
- });
513
- });
514
- // Also capture exit with non-zero code
515
- child.once("exit", (code, signal) => {
516
- if (code !== null && code !== 0) {
517
- const details = [`Process exited with code ${code}`];
518
- if (stdoutData) {
519
- details.push(`Stdout: ${stdoutData}`);
520
- }
521
- if (stderrData) {
522
- details.push(`Stderr: ${stderrData}`);
523
- }
524
- const exitError = details.join("\n");
525
- this.eventLogger("task_exit_error", {
526
- id: request.taskId,
527
- code,
528
- signal,
529
- stdout: stdoutData,
530
- stderr: stderrData
531
- });
532
- this.taskRegistry?.updateTask(request.taskId, {
533
- status: "failed",
534
- error: exitError,
535
- endTime: this.now()
536
- });
537
- }
538
- });
539
- child.unref();
540
- if (typeof child.pid === "number") {
541
- this.taskRegistry.updateTask(request.taskId, {
542
- pid: child.pid,
543
- command: commandString
544
- });
545
- this.eventLogger("task_spawned", {
546
- id: request.taskId,
547
- tool: request.toolName,
548
- pid: child.pid,
549
- command: commandString
550
- });
551
- }
552
- else {
553
- // No PID means spawn failed
554
- this.eventLogger("task_spawn_no_pid", {
555
- id: request.taskId
556
- });
557
- this.taskRegistry.updateTask(request.taskId, {
558
- status: "failed",
559
- error: "Failed to spawn process (no PID)",
560
- endTime: this.now()
561
- });
562
- }
563
- }
564
- catch (error) {
565
- const message = error instanceof Error ? error.message : String(error);
566
- this.eventLogger("task_spawn_error", {
567
- id: request.taskId,
568
- message
569
- });
570
- this.taskRegistry.updateTask(request.taskId, {
571
- status: "failed",
572
- error: `Spawn error: ${message}`,
573
- endTime: this.now()
574
- });
575
- }
576
- };
577
- }
578
- async executeWorktreeSynchronously(input, adapter) {
579
- const git = createSimpleGit({ baseDir: this.cwd });
580
- const branch = input.branch
581
- ? input.branch
582
- : (await git.revparse(["--abbrev-ref", "HEAD"])).trim();
583
- const logs = [];
584
- const runner = async (command, commandArgs) => runCommandInCwd(command, commandArgs, this.cwd);
585
- const runAgent = async (details) => {
586
- if (details.agent !== input.agent) {
587
- throw new Error(`Mismatched agent "${details.agent}" (expected "${input.agent}").`);
588
- }
589
- return await adapter.spawn({
590
- prompt: details.prompt,
591
- args: details.args,
592
- runCommand: runner
593
- });
594
- };
595
- await spawnGitWorktree({
596
- agent: input.agent,
597
- prompt: input.prompt,
598
- agentArgs: input.agentArgs,
599
- basePath: this.cwd,
600
- targetBranch: branch,
601
- runAgent,
602
- logger: (message) => {
603
- logs.push(message);
604
- }
605
- });
606
- if (logs.length === 0) {
607
- logs.push("Worktree workflow completed.");
608
- }
609
- return logs.join("\n");
610
- }
611
- async resolveAgent(agentId) {
612
- const adapter = this.agentRegistry.get(agentId);
613
- if (!adapter) {
614
- throw new Error(`Unsupported agent "${agentId}".`);
615
- }
616
- if (this.agentConfigManager) {
617
- const enabled = await this.agentConfigManager.getEnabledAgents();
618
- if (!enabled.some((entry) => entry.id === agentId)) {
619
- throw new Error(`Agent "${agentId}" is disabled in configuration.`);
620
- }
621
- }
622
- else if (!LEGACY_DEFAULT_AGENTS.some((legacy) => legacy === agentId)) {
623
- throw new Error(`Unsupported agent "${agentId}".`);
624
- }
625
- return adapter;
626
- }
627
- parseWorktreeArgs(args) {
628
- const agentValue = args.agent;
629
- if (typeof agentValue !== "string" || agentValue.length === 0) {
630
- throw new Error("Missing required parameter: agent");
631
- }
632
- const promptValue = args.prompt;
633
- if (typeof promptValue !== "string" || promptValue.length === 0) {
634
- throw new Error("Missing required parameter: prompt");
635
- }
636
- const agentArgsValue = args.agentArgs;
637
- const agentArgs = Array.isArray(agentArgsValue)
638
- ? agentArgsValue.map((entry) => String(entry))
639
- : [];
640
- const branchValue = typeof args.branch === "string" && args.branch.length > 0
641
- ? args.branch
642
- : undefined;
643
- const asyncValue = args.async;
644
- let runAsync = false;
645
- if (typeof asyncValue === "boolean") {
646
- runAsync = asyncValue;
647
- }
648
- else if (typeof asyncValue === "string") {
649
- const normalized = asyncValue.trim().toLowerCase();
650
- if (normalized === "true") {
651
- runAsync = true;
652
- }
653
- else if (normalized === "false" || normalized.length === 0) {
654
- runAsync = false;
655
- }
656
- else {
657
- throw new Error(`Invalid async option "${asyncValue}". Expected boolean, "true", or "false".`);
658
- }
659
- }
660
- else if (asyncValue !== undefined) {
661
- throw new Error(`Invalid async option type "${typeof asyncValue}". Expected boolean or string.`);
662
- }
663
- return {
664
- agent: agentValue,
665
- prompt: promptValue,
666
- agentArgs,
667
- branch: branchValue,
668
- runAsync
669
- };
670
- }
671
- async tryReadFile(targetPath) {
672
- try {
673
- return await this.fs.readFile(targetPath, "utf8");
674
- }
675
- catch (error) {
676
- if (error &&
677
- typeof error === "object" &&
678
- "code" in error &&
679
- error.code === "ENOENT") {
680
- return null;
681
- }
682
- throw error;
683
- }
684
- }
685
- }
686
- function runCommandInCwd(command, args, cwd) {
687
- return new Promise((resolve) => {
688
- const child = spawn(command, args, {
689
- cwd,
690
- stdio: ["ignore", "pipe", "pipe"]
691
- });
692
- let stdout = "";
693
- let stderr = "";
694
- child.stdout?.setEncoding("utf8");
695
- child.stdout?.on("data", (chunk) => {
696
- stdout += chunk.toString();
697
- });
698
- child.stderr?.setEncoding("utf8");
699
- child.stderr?.on("data", (chunk) => {
700
- stderr += chunk.toString();
701
- });
702
- child.once("error", (error) => {
703
- const message = error instanceof Error ? error.message : String(error);
704
- const exitCode = typeof error.code === "number"
705
- ? error.code
706
- : Number.isInteger(Number(error.code))
707
- ? Number(error.code)
708
- : 127;
709
- resolve({
710
- stdout,
711
- stderr: stderr ? `${stderr}${message}` : message,
712
- exitCode
713
- });
714
- });
715
- child.once("close", (code) => {
716
- resolve({
717
- stdout,
718
- stderr,
719
- exitCode: typeof code === "number" ? code : 0
720
- });
721
- });
722
- });
723
- }
724
- export async function getAvailableTools(options = {}) {
725
- const registry = options.agentRegistry ?? createDefaultAgentRegistry();
726
- let enabledAgents = registry
727
- .list()
728
- .filter((adapter) => adapter.defaultEnabled ?? LEGACY_DEFAULT_AGENTS.some((legacy) => legacy === adapter.id))
729
- .map((adapter) => ({ id: adapter.id }));
730
- if (options.agentConfigManager) {
731
- enabledAgents = await options.agentConfigManager.getEnabledAgents();
732
- }
733
- const enabledIds = enabledAgents.map((entry) => entry.id);
734
- const fallbackIds = registry.list().map((adapter) => adapter.id);
735
- const enumValues = enabledIds.length > 0 ? enabledIds : fallbackIds;
736
- const agentDescription = enumValues.length > 0
737
- ? `Agent identifier (${enumValues.join(" | ")}).`
738
- : "Agent identifier.";
739
- const builtInTools = [
740
- {
741
- type: "function",
742
- function: {
743
- name: "read_file",
744
- description: "Read the contents of a file in the current working directory. Use this for reading project files. Supports relative paths (e.g., 'package.json', 'src/index.ts') and absolute paths.",
745
- parameters: {
746
- type: "object",
747
- properties: {
748
- path: {
749
- type: "string",
750
- description: "The file path to read. Can be relative to the current working directory or absolute."
751
- }
752
- },
753
- required: ["path"]
754
- }
755
- }
756
- },
757
- {
758
- type: "function",
759
- function: {
760
- name: "write_file",
761
- description: "Write or create a file in the current working directory. Use this for creating or updating project files. Supports relative and absolute paths.",
762
- parameters: {
763
- type: "object",
764
- properties: {
765
- path: {
766
- type: "string",
767
- description: "The file path to write. Can be relative to the current working directory or absolute."
768
- },
769
- content: {
770
- type: "string",
771
- description: "The content to write to the file"
772
- }
773
- },
774
- required: ["path", "content"]
775
- }
776
- }
777
- },
778
- {
779
- type: "function",
780
- function: {
781
- name: "list_files",
782
- description: "List files and directories in the current working directory or a specified directory. Use this to explore the project structure.",
783
- parameters: {
784
- type: "object",
785
- properties: {
786
- path: {
787
- type: "string",
788
- description: "The directory path to list. Defaults to current working directory if not specified. Can be relative or absolute."
789
- }
790
- }
791
- }
792
- }
793
- },
794
- {
795
- type: "function",
796
- function: {
797
- name: "run_command",
798
- description: "Run a shell command in the current directory",
799
- parameters: {
800
- type: "object",
801
- properties: {
802
- command: {
803
- type: "string",
804
- description: "The shell command to run"
805
- }
806
- },
807
- required: ["command"]
808
- }
809
- }
810
- },
811
- {
812
- type: "function",
813
- function: {
814
- name: "spawn_git_worktree",
815
- description: "Create a git worktree, run an agent, and attempt to merge the resulting changes.",
816
- parameters: {
817
- type: "object",
818
- properties: {
819
- agent: {
820
- type: "string",
821
- description: agentDescription,
822
- enum: enumValues
823
- },
824
- prompt: {
825
- type: "string",
826
- description: "Prompt text to provide to the agent."
827
- },
828
- agentArgs: {
829
- type: "array",
830
- description: "Additional arguments forwarded to the agent CLI.",
831
- items: {
832
- type: "string"
833
- },
834
- default: []
835
- },
836
- branch: {
837
- type: "string",
838
- description: "Target branch to merge into. Defaults to the current branch."
839
- }
840
- },
841
- required: ["agent", "prompt"]
842
- }
843
- }
844
- },
845
- {
846
- type: "function",
847
- function: {
848
- name: "search_web",
849
- description: "Search the web for information",
850
- parameters: {
851
- type: "object",
852
- properties: {
853
- query: {
854
- type: "string",
855
- description: "The search query"
856
- }
857
- },
858
- required: ["query"]
859
- }
860
- }
861
- }
862
- ];
863
- // Add MCP tools if manager is provided
864
- if (options.mcpManager) {
865
- const mcpTools = options.mcpManager.getAllTools();
866
- return [...builtInTools, ...mcpTools];
867
- }
868
- return builtInTools;
869
- }
870
- //# sourceMappingURL=tools.js.map