baro-ai 0.30.1 → 0.32.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baro-ai",
3
- "version": "0.30.1",
3
+ "version": "0.32.0",
4
4
  "description": "Autonomous parallel coding - plan and execute with AI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,412 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/core/planner.ts
4
- import { z } from "zod";
5
- import { zodToJsonSchema } from "zod-to-json-schema";
6
-
7
- // src/core/stream.ts
8
- var API_URL = "https://api.openai.com/v1/responses";
9
- var MAX_TOOL_ROUNDS = 15;
10
- async function streamCompletion(opts) {
11
- const apiKey = process.env.OPENAI_API_KEY;
12
- if (!apiKey) throw new Error("OPENAI_API_KEY not set");
13
- let input = [
14
- ...opts.messages.map((m) => ({ role: m.role, content: m.content })),
15
- { role: "user", content: opts.task }
16
- ];
17
- for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {
18
- const body = { model: opts.model, input, stream: true };
19
- if (opts.reasoning) body.reasoning = opts.reasoning;
20
- if (opts.jsonSchema) {
21
- body.text = {
22
- format: { type: "json_schema", name: "prd_output", schema: opts.jsonSchema, strict: true }
23
- };
24
- }
25
- if (opts.tools?.length) {
26
- body.tools = opts.tools.map((t) => ({
27
- type: "function",
28
- name: t.name,
29
- description: t.description,
30
- parameters: t.parameters
31
- }));
32
- }
33
- const response = await fetch(API_URL, {
34
- method: "POST",
35
- headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
36
- body: JSON.stringify(body)
37
- });
38
- if (!response.ok) {
39
- const errText = await response.text();
40
- throw new Error(`OpenAI API error ${response.status}: ${errText}`);
41
- }
42
- if (!response.body) throw new Error("No response body");
43
- const { textOutput, toolCalls, responseId } = await parseSSE(response.body, opts);
44
- if (toolCalls.length === 0) {
45
- return textOutput;
46
- }
47
- const toolResults = [];
48
- for (const tc of toolCalls) {
49
- const toolDef = opts.tools?.find((t) => t.name === tc.name);
50
- if (!toolDef) continue;
51
- opts.onToolCall?.(tc.name, tc.args);
52
- let result;
53
- try {
54
- const parsed = JSON.parse(tc.args);
55
- result = await toolDef.invoke(parsed);
56
- } catch (err) {
57
- result = `Error: ${err.message}`;
58
- }
59
- toolResults.push({
60
- type: "function_call_output",
61
- call_id: tc.callId,
62
- output: typeof result === "string" ? result : JSON.stringify(result)
63
- });
64
- }
65
- input = toolResults;
66
- }
67
- throw new Error("Too many tool calling rounds");
68
- }
69
- async function parseSSE(body, opts) {
70
- let textOutput = "";
71
- const toolCalls = [];
72
- const toolCallArgs = /* @__PURE__ */ new Map();
73
- let responseId = "";
74
- const reader = body.getReader();
75
- const decoder = new TextDecoder();
76
- let buffer = "";
77
- while (true) {
78
- const { done, value } = await reader.read();
79
- if (done) break;
80
- buffer += decoder.decode(value, { stream: true });
81
- const lines = buffer.split("\n");
82
- buffer = lines.pop() ?? "";
83
- for (const line of lines) {
84
- if (!line.startsWith("data: ")) continue;
85
- const data = line.slice(6).trim();
86
- if (data === "[DONE]") continue;
87
- try {
88
- const ev = JSON.parse(data);
89
- if (ev.type === "response.created") {
90
- responseId = ev.response?.id ?? "";
91
- } else if (ev.type === "response.output_text.delta") {
92
- textOutput += ev.delta ?? "";
93
- opts.onToken(ev.delta ?? "");
94
- } else if (ev.type === "response.reasoning.delta") {
95
- opts.onThinking?.(ev.delta ?? "");
96
- } else if (ev.type === "response.output_item.added") {
97
- if (ev.item?.type === "function_call") {
98
- toolCallArgs.set(ev.output_index, {
99
- callId: ev.item.call_id ?? "",
100
- name: ev.item.name ?? "",
101
- args: ""
102
- });
103
- }
104
- } else if (ev.type === "response.function_call_arguments.delta") {
105
- const tc = toolCallArgs.get(ev.output_index);
106
- if (tc) tc.args += ev.delta ?? "";
107
- } else if (ev.type === "response.output_item.done") {
108
- if (ev.item?.type === "function_call") {
109
- const tc = toolCallArgs.get(ev.output_index);
110
- if (tc) {
111
- toolCalls.push({ callId: tc.callId, name: tc.name, args: tc.args });
112
- }
113
- }
114
- }
115
- } catch {
116
- }
117
- }
118
- }
119
- return { textOutput, toolCalls, responseId };
120
- }
121
-
122
- // src/core/tools.ts
123
- import * as fs from "fs";
124
- import * as path from "path";
125
- import { execSync } from "child_process";
126
- var IGNORE = /* @__PURE__ */ new Set([
127
- "node_modules",
128
- ".git",
129
- "dist",
130
- "build",
131
- ".next",
132
- ".nuxt",
133
- "coverage",
134
- ".cache",
135
- "__pycache__",
136
- "target",
137
- ".output"
138
- ]);
139
- var MAX_FILE_SIZE = 15e3;
140
- function createCodebaseTools(cwd2) {
141
- return [
142
- {
143
- name: "list_files",
144
- description: "List files and directories. Use path='' for project root. Returns file names with types. Ignores node_modules, .git, etc.",
145
- parameters: {
146
- type: "object",
147
- properties: {
148
- path: { type: "string", description: "Relative path from project root. Empty for root." },
149
- recursive: { type: "boolean", description: "List all files recursively (max 200). Default false." }
150
- },
151
- required: ["path"],
152
- additionalProperties: false
153
- },
154
- async invoke(args2) {
155
- const target = safePath(cwd2, args2.path || ".");
156
- if (!target || !fs.existsSync(target)) return `Directory not found: ${args2.path}`;
157
- if (!fs.statSync(target).isDirectory()) return `Not a directory: ${args2.path}`;
158
- const results = [];
159
- function walk(dir, prefix, depth) {
160
- if (results.length >= 200 || depth > 4) return;
161
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
162
- if (IGNORE.has(entry.name) || entry.name.startsWith(".")) continue;
163
- const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
164
- if (entry.isDirectory()) {
165
- results.push(rel + "/");
166
- if (args2.recursive) walk(path.join(dir, entry.name), rel, depth + 1);
167
- } else {
168
- results.push(rel);
169
- }
170
- }
171
- }
172
- walk(target, "", 0);
173
- return results.join("\n") || "(empty directory)";
174
- }
175
- },
176
- {
177
- name: "read_file",
178
- description: "Read file contents. Large files truncated to ~15000 chars. Use to understand code structure, configs, etc.",
179
- parameters: {
180
- type: "object",
181
- properties: {
182
- path: { type: "string", description: "Relative path to file (e.g. 'src/index.ts')" }
183
- },
184
- required: ["path"],
185
- additionalProperties: false
186
- },
187
- async invoke(args2) {
188
- const target = safePath(cwd2, args2.path);
189
- if (!target || !fs.existsSync(target)) return `File not found: ${args2.path}`;
190
- if (fs.statSync(target).isDirectory()) return `${args2.path} is a directory. Use list_files.`;
191
- if (fs.statSync(target).size > 5e5) return `File too large (${(fs.statSync(target).size / 1024).toFixed(0)}KB)`;
192
- let content = fs.readFileSync(target, "utf-8");
193
- if (content.length > MAX_FILE_SIZE) {
194
- content = content.slice(0, MAX_FILE_SIZE) + "\n... (truncated)";
195
- }
196
- return content;
197
- }
198
- },
199
- {
200
- name: "grep",
201
- description: "Search for a text pattern across project files. Returns matching lines with file paths. Ignores node_modules, .git, etc.",
202
- parameters: {
203
- type: "object",
204
- properties: {
205
- pattern: { type: "string", description: "Text to search for (case-insensitive)" },
206
- path: { type: "string", description: "Directory to search in. Default: entire project." },
207
- file_pattern: { type: "string", description: "File glob (e.g. '*.ts'). Default: all." }
208
- },
209
- required: ["pattern"],
210
- additionalProperties: false
211
- },
212
- async invoke(args2) {
213
- const searchDir = safePath(cwd2, args2.path || ".");
214
- if (!searchDir || !fs.existsSync(searchDir)) return `Directory not found: ${args2.path}`;
215
- try {
216
- const excludes = Array.from(IGNORE).map((d) => `--exclude-dir=${d}`).join(" ");
217
- const include = args2.file_pattern ? `--include='${args2.file_pattern}'` : "";
218
- const cmd = `grep -rn -i ${excludes} ${include} --max-count=50 -- ${JSON.stringify(args2.pattern)} ${JSON.stringify(searchDir)} 2>/dev/null || true`;
219
- const output = execSync(cmd, { encoding: "utf-8", maxBuffer: 1024 * 1024 });
220
- const lines = output.split("\n").filter(Boolean).map(
221
- (line) => line.startsWith(cwd2) ? line.slice(cwd2.length + 1) : line
222
- );
223
- return lines.slice(0, 50).join("\n") || "No matches found.";
224
- } catch {
225
- return "No matches found.";
226
- }
227
- }
228
- },
229
- {
230
- name: "file_tree",
231
- description: "Get a condensed tree view of the project structure up to 3 levels deep. Good starting point to understand the codebase.",
232
- parameters: {
233
- type: "object",
234
- properties: {},
235
- additionalProperties: false
236
- },
237
- async invoke() {
238
- const lines = [path.basename(cwd2) + "/"];
239
- function walk(dir, prefix, depth) {
240
- if (lines.length >= 150 || depth > 3) return;
241
- let entries;
242
- try {
243
- entries = fs.readdirSync(dir, { withFileTypes: true });
244
- } catch {
245
- return;
246
- }
247
- entries.sort((a, b) => {
248
- if (a.isDirectory() && !b.isDirectory()) return -1;
249
- if (!a.isDirectory() && b.isDirectory()) return 1;
250
- return a.name.localeCompare(b.name);
251
- });
252
- for (let i = 0; i < entries.length; i++) {
253
- if (IGNORE.has(entries[i].name) || entries[i].name.startsWith(".")) continue;
254
- const isLast = i === entries.length - 1;
255
- const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
256
- const childPrefix = isLast ? " " : "\u2502 ";
257
- if (entries[i].isDirectory()) {
258
- lines.push(`${prefix}${connector}${entries[i].name}/`);
259
- walk(path.join(dir, entries[i].name), prefix + childPrefix, depth + 1);
260
- } else {
261
- lines.push(`${prefix}${connector}${entries[i].name}`);
262
- }
263
- }
264
- }
265
- walk(cwd2, "", 0);
266
- return lines.join("\n");
267
- }
268
- }
269
- ];
270
- }
271
- function safePath(cwd2, filePath) {
272
- const resolved = path.resolve(cwd2, filePath);
273
- if (!resolved.startsWith(path.resolve(cwd2))) return null;
274
- return resolved;
275
- }
276
-
277
- // src/core/planner.ts
278
- var StorySchema = z.object({
279
- id: z.string().describe("Short ID like S1, S2, S3"),
280
- priority: z.number().describe("Priority level: lower = earlier"),
281
- title: z.string().describe("Short title for the story"),
282
- description: z.string().describe("What needs to be implemented"),
283
- dependsOn: z.array(z.string()).describe("IDs of stories this depends on"),
284
- retries: z.number().describe("Retry attempts if story fails (usually 2)"),
285
- acceptance: z.array(z.string()).describe("Testable acceptance criteria"),
286
- tests: z.array(z.string()).describe("Test commands (e.g. ['npm test'])")
287
- });
288
- var PrdSchema = z.object({
289
- project: z.string().describe("Short project name"),
290
- branchName: z.string().describe("Git branch name (kebab-case)"),
291
- description: z.string().describe("One-line project description"),
292
- userStories: z.array(StorySchema).describe("User stories forming a DAG")
293
- });
294
- var SYSTEM_PROMPT = `You are an expert software architect. Break down project goals into concrete user stories that form a dependency DAG.
295
-
296
- IMPORTANT: Before generating a plan, USE YOUR TOOLS to explore the existing codebase:
297
- 1. Call file_tree to see the project structure
298
- 2. Call read_file on key files (package.json, README, entry points, configs)
299
- 3. Call grep to find relevant patterns
300
- 4. THEN generate a plan that fits the existing code
301
-
302
- Rules:
303
- - Each story: single focused unit of work for one AI agent
304
- - Use dependsOn for dependencies; same-priority stories with no deps run IN PARALLEL
305
- - Keep stories small (15-60 min of work)
306
- - Include testable acceptance criteria and test commands
307
- - No circular dependencies
308
- - Start with foundational stories, build up
309
- - retries: 2-3 for most stories
310
- - IDs: S1, S2, S3...
311
- - branchName: kebab-case
312
- - Build on existing code, don't recreate what exists`;
313
- function fixSchemaForOpenAI(schema) {
314
- if (!schema || typeof schema !== "object") return schema;
315
- if (schema.type === "object" && schema.properties) {
316
- schema.additionalProperties = false;
317
- }
318
- if (schema.properties) {
319
- for (const key of Object.keys(schema.properties)) {
320
- fixSchemaForOpenAI(schema.properties[key]);
321
- }
322
- }
323
- if (schema.items) fixSchemaForOpenAI(schema.items);
324
- delete schema.$schema;
325
- return schema;
326
- }
327
- var Planner = class {
328
- messages;
329
- model;
330
- onToken;
331
- onToolCall;
332
- tools;
333
- constructor(options = {}) {
334
- this.model = options.model ?? "gpt-5.4";
335
- this.onToken = options.onToken;
336
- this.onToolCall = options.onToolCall;
337
- this.tools = options.cwd ? createCodebaseTools(options.cwd) : [];
338
- this.messages = [{ role: "system", content: SYSTEM_PROMPT }];
339
- }
340
- async send(userMessage) {
341
- const raw = zodToJsonSchema(PrdSchema, "prd");
342
- const schema = fixSchemaForOpenAI(
343
- raw.definitions?.prd ?? raw
344
- );
345
- const fullText = await streamCompletion({
346
- model: this.model,
347
- messages: this.messages,
348
- task: userMessage,
349
- jsonSchema: schema,
350
- reasoning: { effort: "high" },
351
- tools: this.tools.length > 0 ? this.tools : void 0,
352
- onToken: this.onToken ?? (() => {
353
- }),
354
- onToolCall: this.onToolCall
355
- });
356
- let prd;
357
- try {
358
- prd = JSON.parse(fullText);
359
- } catch {
360
- throw new Error("Failed to parse plan output as JSON");
361
- }
362
- this.messages.push(
363
- { role: "user", content: userMessage },
364
- { role: "assistant", content: fullText }
365
- );
366
- return {
367
- ...prd,
368
- userStories: prd.userStories.map((s) => ({
369
- ...s,
370
- passes: false,
371
- completedAt: null,
372
- durationSecs: null
373
- }))
374
- };
375
- }
376
- };
377
-
378
- // src/core/openai-planner.ts
379
- var args = process.argv.slice(2);
380
- var goal = "";
381
- var cwd = process.cwd();
382
- for (let i = 0; i < args.length; i++) {
383
- if (args[i] === "--cwd" && args[i + 1]) {
384
- cwd = args[++i];
385
- } else if (!goal) {
386
- goal = args[i];
387
- }
388
- }
389
- if (!goal) {
390
- console.error("Usage: openai-planner <goal> [--cwd <path>]");
391
- process.exit(1);
392
- }
393
- async function main() {
394
- const planner = new Planner({
395
- cwd,
396
- onToken: () => {
397
- },
398
- onToolCall: (name, args2) => {
399
- process.stderr.write(`[openai] tool: ${name}
400
- `);
401
- }
402
- });
403
- try {
404
- const prd = await planner.send(goal);
405
- process.stdout.write(JSON.stringify(prd, null, 2) + "\n");
406
- } catch (err) {
407
- console.error(`OpenAI planner error: ${err.message}`);
408
- process.exit(1);
409
- }
410
- }
411
- main();
412
- //# sourceMappingURL=openai-planner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/planner.ts","../src/core/stream.ts","../src/core/tools.ts","../src/core/openai-planner.ts"],"sourcesContent":["/**\n * AI Planner with streaming output.\n * Direct OpenAI streaming with fixed JSON schema for structured output.\n */\n\nimport { z } from \"zod\"\nimport { zodToJsonSchema } from \"zod-to-json-schema\"\nimport type { PrdV2 } from \"./prd.js\"\nimport { streamCompletion } from \"./stream.js\"\nimport { createCodebaseTools } from \"./tools.js\"\nimport type { ToolDef } from \"./stream.js\"\nimport * as fs from \"fs\"\nimport * as path from \"path\"\n\nconst StorySchema = z.object({\n id: z.string().describe(\"Short ID like S1, S2, S3\"),\n priority: z.number().describe(\"Priority level: lower = earlier\"),\n title: z.string().describe(\"Short title for the story\"),\n description: z.string().describe(\"What needs to be implemented\"),\n dependsOn: z.array(z.string()).describe(\"IDs of stories this depends on\"),\n retries: z.number().describe(\"Retry attempts if story fails (usually 2)\"),\n acceptance: z.array(z.string()).describe(\"Testable acceptance criteria\"),\n tests: z.array(z.string()).describe(\"Test commands (e.g. ['npm test'])\"),\n})\n\nconst PrdSchema = z.object({\n project: z.string().describe(\"Short project name\"),\n branchName: z.string().describe(\"Git branch name (kebab-case)\"),\n description: z.string().describe(\"One-line project description\"),\n userStories: z.array(StorySchema).describe(\"User stories forming a DAG\"),\n})\n\nconst SYSTEM_PROMPT = `You are an expert software architect. Break down project goals into concrete user stories that form a dependency DAG.\n\nIMPORTANT: Before generating a plan, USE YOUR TOOLS to explore the existing codebase:\n1. Call file_tree to see the project structure\n2. Call read_file on key files (package.json, README, entry points, configs)\n3. Call grep to find relevant patterns\n4. THEN generate a plan that fits the existing code\n\nRules:\n- Each story: single focused unit of work for one AI agent\n- Use dependsOn for dependencies; same-priority stories with no deps run IN PARALLEL\n- Keep stories small (15-60 min of work)\n- Include testable acceptance criteria and test commands\n- No circular dependencies\n- Start with foundational stories, build up\n- retries: 2-3 for most stories\n- IDs: S1, S2, S3...\n- branchName: kebab-case\n- Build on existing code, don't recreate what exists`\n\n/** Recursively add additionalProperties: false to all objects in schema (OpenAI strict mode requires it) */\nfunction fixSchemaForOpenAI(schema: any): any {\n if (!schema || typeof schema !== \"object\") return schema\n if (schema.type === \"object\" && schema.properties) {\n schema.additionalProperties = false\n }\n if (schema.properties) {\n for (const key of Object.keys(schema.properties)) {\n fixSchemaForOpenAI(schema.properties[key])\n }\n }\n if (schema.items) fixSchemaForOpenAI(schema.items)\n // Remove $schema if present\n delete schema.$schema\n return schema\n}\n\nexport interface PlannerOptions {\n model?: string\n cwd?: string\n onToken?: (token: string) => void\n onToolCall?: (name: string, args: any) => void\n}\n\nexport class Planner {\n private messages: { role: string; content: string }[]\n private model: string\n private onToken?: (token: string) => void\n private onToolCall?: (name: string, args: any) => void\n private tools: ToolDef[]\n\n constructor(options: PlannerOptions = {}) {\n this.model = options.model ?? \"gpt-5.4\"\n this.onToken = options.onToken\n this.onToolCall = options.onToolCall\n this.tools = options.cwd ? createCodebaseTools(options.cwd) : []\n this.messages = [{ role: \"system\", content: SYSTEM_PROMPT }]\n }\n\n async send(userMessage: string): Promise<PrdV2> {\n const raw = zodToJsonSchema(PrdSchema, \"prd\")\n const schema = fixSchemaForOpenAI(\n (raw as any).definitions?.prd ?? raw\n )\n\n const fullText = await streamCompletion({\n model: this.model,\n messages: this.messages,\n task: userMessage,\n jsonSchema: schema,\n reasoning: { effort: \"high\" },\n tools: this.tools.length > 0 ? this.tools : undefined,\n onToken: this.onToken ?? (() => {}),\n onToolCall: this.onToolCall,\n })\n\n let prd: z.infer<typeof PrdSchema>\n try {\n prd = JSON.parse(fullText)\n } catch {\n throw new Error(\"Failed to parse plan output as JSON\")\n }\n\n this.messages.push(\n { role: \"user\", content: userMessage },\n { role: \"assistant\", content: fullText },\n )\n\n return {\n ...prd,\n userStories: prd.userStories.map((s) => ({\n ...s,\n passes: false,\n completedAt: null,\n durationSecs: null,\n })),\n }\n }\n}\n\n","/**\n * OpenAI Responses API streaming with tool calling loop.\n * Model can call tools (read_file, grep, list_files) to explore the codebase,\n * then generates the final output (plan JSON).\n */\n\nexport interface ToolDef {\n name: string\n description: string\n parameters: Record<string, any>\n invoke: (args: any) => Promise<string>\n}\n\nexport interface StreamOptions {\n model: string\n messages: { role: string; content: string }[]\n task: string\n onToken: (token: string) => void\n onToolCall?: (name: string, args: any) => void\n onThinking?: (text: string) => void\n jsonSchema?: Record<string, any>\n reasoning?: { effort: \"low\" | \"medium\" | \"high\" }\n tools?: ToolDef[]\n}\n\nconst API_URL = \"https://api.openai.com/v1/responses\"\nconst MAX_TOOL_ROUNDS = 15\n\nexport async function streamCompletion(opts: StreamOptions): Promise<string> {\n const apiKey = process.env.OPENAI_API_KEY\n if (!apiKey) throw new Error(\"OPENAI_API_KEY not set\")\n\n // Build initial input\n let input: any[] = [\n ...opts.messages.map((m) => ({ role: m.role, content: m.content })),\n { role: \"user\", content: opts.task },\n ]\n\n // Tool calling loop - model may request tools multiple times before final output\n for (let round = 0; round < MAX_TOOL_ROUNDS; round++) {\n const body: any = { model: opts.model, input, stream: true }\n\n if (opts.reasoning) body.reasoning = opts.reasoning\n if (opts.jsonSchema) {\n body.text = {\n format: { type: \"json_schema\", name: \"prd_output\", schema: opts.jsonSchema, strict: true },\n }\n }\n if (opts.tools?.length) {\n body.tools = opts.tools.map((t) => ({\n type: \"function\",\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n }))\n }\n\n const response = await fetch(API_URL, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Authorization: `Bearer ${apiKey}` },\n body: JSON.stringify(body),\n })\n\n if (!response.ok) {\n const errText = await response.text()\n throw new Error(`OpenAI API error ${response.status}: ${errText}`)\n }\n\n if (!response.body) throw new Error(\"No response body\")\n\n // Parse SSE stream\n const { textOutput, toolCalls, responseId } = await parseSSE(response.body, opts)\n\n // If no tool calls, we have our final text output\n if (toolCalls.length === 0) {\n return textOutput\n }\n\n // Execute tool calls and feed results back\n const toolResults: any[] = []\n for (const tc of toolCalls) {\n const toolDef = opts.tools?.find((t) => t.name === tc.name)\n if (!toolDef) continue\n\n opts.onToolCall?.(tc.name, tc.args)\n\n let result: string\n try {\n const parsed = JSON.parse(tc.args)\n result = await toolDef.invoke(parsed)\n } catch (err: any) {\n result = `Error: ${err.message}`\n }\n\n toolResults.push({\n type: \"function_call_output\",\n call_id: tc.callId,\n output: typeof result === \"string\" ? result : JSON.stringify(result),\n })\n }\n\n // Next round: just tool results as input (API remembers conversation via response ID)\n input = toolResults\n }\n\n throw new Error(\"Too many tool calling rounds\")\n}\n\ninterface ToolCall {\n callId: string\n name: string\n args: string\n}\n\nasync function parseSSE(\n body: ReadableStream<Uint8Array>,\n opts: StreamOptions\n): Promise<{ textOutput: string; toolCalls: ToolCall[]; responseId: string }> {\n let textOutput = \"\"\n const toolCalls: ToolCall[] = []\n const toolCallArgs = new Map<number, { callId: string; name: string; args: string }>()\n let responseId = \"\"\n\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() ?? \"\"\n\n for (const line of lines) {\n if (!line.startsWith(\"data: \")) continue\n const data = line.slice(6).trim()\n if (data === \"[DONE]\") continue\n\n try {\n const ev = JSON.parse(data)\n\n if (ev.type === \"response.created\") {\n responseId = ev.response?.id ?? \"\"\n } else if (ev.type === \"response.output_text.delta\") {\n textOutput += ev.delta ?? \"\"\n opts.onToken(ev.delta ?? \"\")\n } else if (ev.type === \"response.reasoning.delta\") {\n opts.onThinking?.(ev.delta ?? \"\")\n } else if (ev.type === \"response.output_item.added\") {\n if (ev.item?.type === \"function_call\") {\n toolCallArgs.set(ev.output_index, {\n callId: ev.item.call_id ?? \"\",\n name: ev.item.name ?? \"\",\n args: \"\",\n })\n }\n } else if (ev.type === \"response.function_call_arguments.delta\") {\n const tc = toolCallArgs.get(ev.output_index)\n if (tc) tc.args += ev.delta ?? \"\"\n } else if (ev.type === \"response.output_item.done\") {\n if (ev.item?.type === \"function_call\") {\n const tc = toolCallArgs.get(ev.output_index)\n if (tc) {\n toolCalls.push({ callId: tc.callId, name: tc.name, args: tc.args })\n }\n }\n }\n } catch {}\n }\n }\n\n return { textOutput, toolCalls, responseId }\n}\n","/**\n * Codebase exploration tools for the AI planner.\n * These are passed as function-calling tools to OpenAI.\n * The model decides when and what to read/grep/list.\n */\n\nimport * as fs from \"fs\"\nimport * as path from \"path\"\nimport { execSync } from \"child_process\"\nimport type { ToolDef } from \"./stream.js\"\n\nconst IGNORE = new Set([\n \"node_modules\", \".git\", \"dist\", \"build\", \".next\", \".nuxt\",\n \"coverage\", \".cache\", \"__pycache__\", \"target\", \".output\",\n])\n\nconst MAX_FILE_SIZE = 15_000\n\nexport function createCodebaseTools(cwd: string): ToolDef[] {\n return [\n {\n name: \"list_files\",\n description: \"List files and directories. Use path='' for project root. Returns file names with types. Ignores node_modules, .git, etc.\",\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Relative path from project root. Empty for root.\" },\n recursive: { type: \"boolean\", description: \"List all files recursively (max 200). Default false.\" },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n async invoke(args: { path: string; recursive?: boolean }) {\n const target = safePath(cwd, args.path || \".\")\n if (!target || !fs.existsSync(target)) return `Directory not found: ${args.path}`\n if (!fs.statSync(target).isDirectory()) return `Not a directory: ${args.path}`\n\n const results: string[] = []\n function walk(dir: string, prefix: string, depth: number) {\n if (results.length >= 200 || depth > 4) return\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n if (IGNORE.has(entry.name) || entry.name.startsWith(\".\")) continue\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name\n if (entry.isDirectory()) {\n results.push(rel + \"/\")\n if (args.recursive) walk(path.join(dir, entry.name), rel, depth + 1)\n } else {\n results.push(rel)\n }\n }\n }\n walk(target, \"\", 0)\n return results.join(\"\\n\") || \"(empty directory)\"\n },\n },\n {\n name: \"read_file\",\n description: \"Read file contents. Large files truncated to ~15000 chars. Use to understand code structure, configs, etc.\",\n parameters: {\n type: \"object\",\n properties: {\n path: { type: \"string\", description: \"Relative path to file (e.g. 'src/index.ts')\" },\n },\n required: [\"path\"],\n additionalProperties: false,\n },\n async invoke(args: { path: string }) {\n const target = safePath(cwd, args.path)\n if (!target || !fs.existsSync(target)) return `File not found: ${args.path}`\n if (fs.statSync(target).isDirectory()) return `${args.path} is a directory. Use list_files.`\n if (fs.statSync(target).size > 500_000) return `File too large (${(fs.statSync(target).size / 1024).toFixed(0)}KB)`\n\n let content = fs.readFileSync(target, \"utf-8\")\n if (content.length > MAX_FILE_SIZE) {\n content = content.slice(0, MAX_FILE_SIZE) + \"\\n... (truncated)\"\n }\n return content\n },\n },\n {\n name: \"grep\",\n description: \"Search for a text pattern across project files. Returns matching lines with file paths. Ignores node_modules, .git, etc.\",\n parameters: {\n type: \"object\",\n properties: {\n pattern: { type: \"string\", description: \"Text to search for (case-insensitive)\" },\n path: { type: \"string\", description: \"Directory to search in. Default: entire project.\" },\n file_pattern: { type: \"string\", description: \"File glob (e.g. '*.ts'). Default: all.\" },\n },\n required: [\"pattern\"],\n additionalProperties: false,\n },\n async invoke(args: { pattern: string; path?: string; file_pattern?: string }) {\n const searchDir = safePath(cwd, args.path || \".\")\n if (!searchDir || !fs.existsSync(searchDir)) return `Directory not found: ${args.path}`\n\n try {\n const excludes = Array.from(IGNORE).map((d) => `--exclude-dir=${d}`).join(\" \")\n const include = args.file_pattern ? `--include='${args.file_pattern}'` : \"\"\n const cmd = `grep -rn -i ${excludes} ${include} --max-count=50 -- ${JSON.stringify(args.pattern)} ${JSON.stringify(searchDir)} 2>/dev/null || true`\n\n const output = execSync(cmd, { encoding: \"utf-8\", maxBuffer: 1024 * 1024 })\n const lines = output.split(\"\\n\").filter(Boolean).map((line) =>\n line.startsWith(cwd) ? line.slice(cwd.length + 1) : line\n )\n return lines.slice(0, 50).join(\"\\n\") || \"No matches found.\"\n } catch {\n return \"No matches found.\"\n }\n },\n },\n {\n name: \"file_tree\",\n description: \"Get a condensed tree view of the project structure up to 3 levels deep. Good starting point to understand the codebase.\",\n parameters: {\n type: \"object\",\n properties: {},\n additionalProperties: false,\n },\n async invoke() {\n const lines: string[] = [path.basename(cwd) + \"/\"]\n function walk(dir: string, prefix: string, depth: number) {\n if (lines.length >= 150 || depth > 3) return\n let entries: fs.Dirent[]\n try { entries = fs.readdirSync(dir, { withFileTypes: true }) } catch { return }\n\n entries.sort((a, b) => {\n if (a.isDirectory() && !b.isDirectory()) return -1\n if (!a.isDirectory() && b.isDirectory()) return 1\n return a.name.localeCompare(b.name)\n })\n\n for (let i = 0; i < entries.length; i++) {\n if (IGNORE.has(entries[i].name) || entries[i].name.startsWith(\".\")) continue\n const isLast = i === entries.length - 1\n const connector = isLast ? \"└── \" : \"├── \"\n const childPrefix = isLast ? \" \" : \"│ \"\n if (entries[i].isDirectory()) {\n lines.push(`${prefix}${connector}${entries[i].name}/`)\n walk(path.join(dir, entries[i].name), prefix + childPrefix, depth + 1)\n } else {\n lines.push(`${prefix}${connector}${entries[i].name}`)\n }\n }\n }\n walk(cwd, \"\", 0)\n return lines.join(\"\\n\")\n },\n },\n ]\n}\n\nfunction safePath(cwd: string, filePath: string): string | null {\n const resolved = path.resolve(cwd, filePath)\n if (!resolved.startsWith(path.resolve(cwd))) return null\n return resolved\n}\n","#!/usr/bin/env node\n/**\n * OpenAI planner entry point - called from Rust binary when --planner openai.\n * Usage: node openai-planner.js \"goal\" --cwd /path/to/project\n * Outputs PRD JSON to stdout.\n */\n\nimport { Planner } from \"./planner.js\"\n\nconst args = process.argv.slice(2)\nlet goal = \"\"\nlet cwd = process.cwd()\n\nfor (let i = 0; i < args.length; i++) {\n if (args[i] === \"--cwd\" && args[i + 1]) {\n cwd = args[++i]\n } else if (!goal) {\n goal = args[i]\n }\n}\n\nif (!goal) {\n console.error(\"Usage: openai-planner <goal> [--cwd <path>]\")\n process.exit(1)\n}\n\nasync function main() {\n const planner = new Planner({\n cwd,\n onToken: () => {},\n onToolCall: (name, args) => {\n process.stderr.write(`[openai] tool: ${name}\\n`)\n },\n })\n\n try {\n const prd = await planner.send(goal)\n process.stdout.write(JSON.stringify(prd, null, 2) + \"\\n\")\n } catch (err: any) {\n console.error(`OpenAI planner error: ${err.message}`)\n process.exit(1)\n }\n}\n\nmain()\n"],"mappings":"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","names":["cwd","args","args"]}