@brainst0rm/cli 0.13.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 (55) hide show
  1. package/README.md +32 -0
  2. package/dist/App-DPXJYXKH.js +2794 -0
  3. package/dist/App-DPXJYXKH.js.map +1 -0
  4. package/dist/App-SSKWB7CT.js +2795 -0
  5. package/dist/App-SSKWB7CT.js.map +1 -0
  6. package/dist/brainstorm.js +4636 -0
  7. package/dist/brainstorm.js.map +1 -0
  8. package/dist/chunk-2CHZHDIM.js +391 -0
  9. package/dist/chunk-2CHZHDIM.js.map +1 -0
  10. package/dist/chunk-55ITCWZZ.js +1307 -0
  11. package/dist/chunk-55ITCWZZ.js.map +1 -0
  12. package/dist/chunk-5NA3GH6X.js +1308 -0
  13. package/dist/chunk-5NA3GH6X.js.map +1 -0
  14. package/dist/chunk-7D4SUZUM.js +38 -0
  15. package/dist/chunk-7D4SUZUM.js.map +1 -0
  16. package/dist/chunk-D474E47D.js +148 -0
  17. package/dist/chunk-D474E47D.js.map +1 -0
  18. package/dist/chunk-GJXEX2A3.js +146 -0
  19. package/dist/chunk-GJXEX2A3.js.map +1 -0
  20. package/dist/chunk-OVGL3NJQ.js +307 -0
  21. package/dist/chunk-OVGL3NJQ.js.map +1 -0
  22. package/dist/chunk-VY6MPJXL.js +389 -0
  23. package/dist/chunk-VY6MPJXL.js.map +1 -0
  24. package/dist/chunk-YWXOPUDW.js +305 -0
  25. package/dist/chunk-YWXOPUDW.js.map +1 -0
  26. package/dist/chunk-ZWE3DS7E.js +39 -0
  27. package/dist/chunk-ZWE3DS7E.js.map +1 -0
  28. package/dist/dist-DUDO3RDM.js +9573 -0
  29. package/dist/dist-DUDO3RDM.js.map +1 -0
  30. package/dist/dist-GNHTH2DH.js +292 -0
  31. package/dist/dist-GNHTH2DH.js.map +1 -0
  32. package/dist/dist-JUDVPE7G.js +293 -0
  33. package/dist/dist-JUDVPE7G.js.map +1 -0
  34. package/dist/dist-V5DTSTKJ.js +9572 -0
  35. package/dist/dist-V5DTSTKJ.js.map +1 -0
  36. package/dist/dist-WLTQTLFO.js +14 -0
  37. package/dist/dist-WLTQTLFO.js.map +1 -0
  38. package/dist/dist-YIGU37Q2.js +15 -0
  39. package/dist/dist-YIGU37Q2.js.map +1 -0
  40. package/dist/index.d.ts +3 -0
  41. package/dist/index.js +4635 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/recorder-D6ILEOZP.js +67 -0
  44. package/dist/recorder-D6ILEOZP.js.map +1 -0
  45. package/dist/recorder-SPYYF4DL.js +66 -0
  46. package/dist/recorder-SPYYF4DL.js.map +1 -0
  47. package/dist/roles-2DGF4PZU.js +16 -0
  48. package/dist/roles-2DGF4PZU.js.map +1 -0
  49. package/dist/roles-UIPX7GBC.js +17 -0
  50. package/dist/roles-UIPX7GBC.js.map +1 -0
  51. package/dist/slash-PDWKCZOQ.js +13 -0
  52. package/dist/slash-PDWKCZOQ.js.map +1 -0
  53. package/dist/slash-ZDC4DKL4.js +14 -0
  54. package/dist/slash-ZDC4DKL4.js.map +1 -0
  55. package/package.json +76 -0
@@ -0,0 +1,292 @@
1
+ import {
2
+ ProjectRepository
3
+ } from "./chunk-VY6MPJXL.js";
4
+ import "./chunk-7D4SUZUM.js";
5
+
6
+ // ../orchestrator/dist/index.js
7
+ import { randomUUID } from "crypto";
8
+ function rowToRun(row) {
9
+ return {
10
+ id: row.id,
11
+ name: row.name,
12
+ description: row.description,
13
+ leadSessionId: row.lead_session_id ?? void 0,
14
+ status: row.status,
15
+ projectIds: JSON.parse(row.project_ids || "[]"),
16
+ budgetLimit: row.budget_limit ?? void 0,
17
+ totalCost: row.total_cost,
18
+ createdAt: row.created_at,
19
+ updatedAt: row.updated_at
20
+ };
21
+ }
22
+ function rowToTask(row) {
23
+ return {
24
+ id: row.id,
25
+ runId: row.run_id,
26
+ projectId: row.project_id,
27
+ prompt: row.prompt,
28
+ status: row.status,
29
+ subagentType: row.subagent_type,
30
+ resultSummary: row.result_summary ?? void 0,
31
+ cost: row.cost,
32
+ sessionId: row.session_id ?? void 0,
33
+ dependsOn: JSON.parse(row.depends_on || "[]"),
34
+ startedAt: row.started_at ?? void 0,
35
+ completedAt: row.completed_at ?? void 0
36
+ };
37
+ }
38
+ var OrchestrationRunRepository = class {
39
+ constructor(db) {
40
+ this.db = db;
41
+ }
42
+ create(data) {
43
+ const id = randomUUID();
44
+ const now = Math.floor(Date.now() / 1e3);
45
+ this.db.prepare(
46
+ `INSERT INTO orchestration_runs (id, name, description, lead_session_id, project_ids, budget_limit, created_at, updated_at)
47
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
48
+ ).run(
49
+ id,
50
+ data.name,
51
+ data.description,
52
+ data.leadSessionId ?? null,
53
+ JSON.stringify(data.projectIds),
54
+ data.budgetLimit ?? null,
55
+ now,
56
+ now
57
+ );
58
+ return this.getById(id);
59
+ }
60
+ getById(id) {
61
+ const row = this.db.prepare("SELECT * FROM orchestration_runs WHERE id = ?").get(id);
62
+ return row ? rowToRun(row) : void 0;
63
+ }
64
+ listRecent(limit = 10) {
65
+ return this.db.prepare(
66
+ "SELECT * FROM orchestration_runs ORDER BY created_at DESC LIMIT ?"
67
+ ).all(limit).map(rowToRun);
68
+ }
69
+ updateStatus(id, status, cost) {
70
+ const now = Math.floor(Date.now() / 1e3);
71
+ if (cost !== void 0) {
72
+ this.db.prepare(
73
+ "UPDATE orchestration_runs SET status = ?, total_cost = ?, updated_at = ? WHERE id = ?"
74
+ ).run(status, cost, now, id);
75
+ } else {
76
+ this.db.prepare(
77
+ "UPDATE orchestration_runs SET status = ?, updated_at = ? WHERE id = ?"
78
+ ).run(status, now, id);
79
+ }
80
+ }
81
+ };
82
+ var OrchestrationTaskRepository = class {
83
+ constructor(db) {
84
+ this.db = db;
85
+ }
86
+ create(data) {
87
+ const id = randomUUID();
88
+ this.db.prepare(
89
+ `INSERT INTO orchestration_tasks (id, run_id, project_id, prompt, subagent_type, depends_on)
90
+ VALUES (?, ?, ?, ?, ?, ?)`
91
+ ).run(
92
+ id,
93
+ data.runId,
94
+ data.projectId,
95
+ data.prompt,
96
+ data.subagentType ?? "code",
97
+ JSON.stringify(data.dependsOn ?? [])
98
+ );
99
+ return this.getById(id);
100
+ }
101
+ getById(id) {
102
+ const row = this.db.prepare("SELECT * FROM orchestration_tasks WHERE id = ?").get(id);
103
+ return row ? rowToTask(row) : void 0;
104
+ }
105
+ listByRun(runId) {
106
+ return this.db.prepare("SELECT * FROM orchestration_tasks WHERE run_id = ?").all(runId).map(rowToTask);
107
+ }
108
+ updateStatus(id, status, data) {
109
+ const now = Math.floor(Date.now() / 1e3);
110
+ const completedAt = status === "completed" || status === "failed" ? now : null;
111
+ const startedAt = status === "running" ? now : void 0;
112
+ this.db.prepare(
113
+ `UPDATE orchestration_tasks SET status = ?, result_summary = COALESCE(?, result_summary),
114
+ cost = COALESCE(?, cost), session_id = COALESCE(?, session_id),
115
+ started_at = COALESCE(?, started_at), completed_at = COALESCE(?, completed_at)
116
+ WHERE id = ?`
117
+ ).run(
118
+ status,
119
+ data?.resultSummary ?? null,
120
+ data?.cost ?? null,
121
+ data?.sessionId ?? null,
122
+ startedAt ?? null,
123
+ completedAt,
124
+ id
125
+ );
126
+ }
127
+ };
128
+ var OrchestrationEngine = class {
129
+ constructor(db) {
130
+ this.db = db;
131
+ this.runs = new OrchestrationRunRepository(db);
132
+ this.tasks = new OrchestrationTaskRepository(db);
133
+ this.projects = new ProjectRepository(db);
134
+ }
135
+ runs;
136
+ tasks;
137
+ projects;
138
+ /**
139
+ * Run an orchestration as an async generator yielding events.
140
+ */
141
+ async *run(opts) {
142
+ const resolvedProjects = [];
143
+ for (const name of opts.projectNames) {
144
+ const project = this.projects.getByName(name);
145
+ if (!project) {
146
+ throw new Error(
147
+ `Project "${name}" not found. Run 'storm projects list' to see registered projects.`
148
+ );
149
+ }
150
+ resolvedProjects.push(project);
151
+ }
152
+ const orchestrationRun = this.runs.create({
153
+ name: opts.description.slice(0, 100),
154
+ description: opts.description,
155
+ projectIds: resolvedProjects.map((p) => p.id),
156
+ budgetLimit: opts.budgetLimit
157
+ });
158
+ this.runs.updateStatus(orchestrationRun.id, "running");
159
+ const budgetPerProject = opts.budgetLimit ? opts.budgetLimit / resolvedProjects.length * 1.2 : void 0;
160
+ const orchestrationTasks = [];
161
+ for (const project of resolvedProjects) {
162
+ const prompt = opts.perProjectPrompts?.get(project.name) ?? `In the context of the "${project.name}" project at ${project.path}:
163
+
164
+ ${opts.description}`;
165
+ const task = this.tasks.create({
166
+ runId: orchestrationRun.id,
167
+ projectId: project.id,
168
+ prompt,
169
+ subagentType: opts.subagentType ?? "code"
170
+ });
171
+ orchestrationTasks.push(task);
172
+ }
173
+ yield {
174
+ type: "plan-ready",
175
+ run: orchestrationRun,
176
+ tasks: orchestrationTasks
177
+ };
178
+ const results = [];
179
+ let totalCost = 0;
180
+ for (let i = 0; i < orchestrationTasks.length; i++) {
181
+ const task = orchestrationTasks[i];
182
+ const project = resolvedProjects[i];
183
+ this.tasks.updateStatus(task.id, "running");
184
+ yield { type: "task-started", task, project };
185
+ try {
186
+ let summary;
187
+ let cost;
188
+ if (opts.executeTask) {
189
+ const result = await opts.executeTask(project, task.prompt, {
190
+ budget: budgetPerProject ?? 1,
191
+ subagentType: opts.subagentType ?? "code"
192
+ });
193
+ summary = result.summary;
194
+ cost = result.cost;
195
+ } else {
196
+ summary = `[Placeholder] Would execute in ${project.name}: ${task.prompt.slice(0, 80)}...`;
197
+ cost = 0;
198
+ }
199
+ totalCost += cost;
200
+ this.tasks.updateStatus(task.id, "completed", {
201
+ resultSummary: summary,
202
+ cost
203
+ });
204
+ results.push({ projectName: project.name, summary, cost });
205
+ yield { type: "task-completed", task, project, summary, cost };
206
+ } catch (err) {
207
+ const error = err instanceof Error ? err.message : String(err);
208
+ this.tasks.updateStatus(task.id, "failed", {
209
+ resultSummary: error,
210
+ cost: 0
211
+ });
212
+ yield { type: "task-failed", task, project, error };
213
+ results.push({
214
+ projectName: project.name,
215
+ summary: `FAILED: ${error}`,
216
+ cost: 0
217
+ });
218
+ }
219
+ }
220
+ this.runs.updateStatus(orchestrationRun.id, "completed", totalCost);
221
+ const updatedRun = this.runs.getById(orchestrationRun.id);
222
+ yield { type: "orchestration-completed", run: updatedRun, results };
223
+ }
224
+ /** Get run details with all tasks. */
225
+ getRunWithTasks(runId) {
226
+ const run = this.runs.getById(runId);
227
+ if (!run) return void 0;
228
+ const tasks = this.tasks.listByRun(runId);
229
+ return { run, tasks };
230
+ }
231
+ /** List recent orchestration runs. */
232
+ listRecent(limit = 10) {
233
+ return this.runs.listRecent(limit);
234
+ }
235
+ /** Cancel a running orchestration. */
236
+ cancel(runId) {
237
+ const run = this.runs.getById(runId);
238
+ if (!run || run.status !== "running") return;
239
+ const tasks = this.tasks.listByRun(runId);
240
+ for (const task of tasks) {
241
+ if (task.status === "pending") {
242
+ this.tasks.updateStatus(task.id, "skipped");
243
+ }
244
+ }
245
+ this.runs.updateStatus(runId, "cancelled");
246
+ }
247
+ };
248
+ function aggregateResults(run, tasks, projectNames) {
249
+ const perProject = tasks.map((t) => ({
250
+ name: projectNames.get(t.projectId) ?? t.projectId.slice(0, 8),
251
+ status: t.status,
252
+ summary: t.resultSummary ?? "No output",
253
+ cost: t.cost
254
+ }));
255
+ const successCount = tasks.filter((t) => t.status === "completed").length;
256
+ const failureCount = tasks.filter((t) => t.status === "failed").length;
257
+ return {
258
+ summary: run.description,
259
+ totalCost: run.totalCost,
260
+ projectCount: tasks.length,
261
+ successCount,
262
+ failureCount,
263
+ perProject
264
+ };
265
+ }
266
+ function formatAggregatedResults(result) {
267
+ const lines = [];
268
+ lines.push(`Orchestration: ${result.summary}`);
269
+ lines.push(
270
+ `${result.successCount}/${result.projectCount} projects completed \xB7 $${result.totalCost.toFixed(4)} total`
271
+ );
272
+ lines.push("");
273
+ for (const p of result.perProject) {
274
+ const icon = p.status === "completed" ? "\u2713" : p.status === "failed" ? "\u2717" : p.status === "skipped" ? "\u25CB" : "\u25CF";
275
+ lines.push(` ${icon} ${p.name} ($${p.cost.toFixed(4)})`);
276
+ if (p.summary && p.summary !== "No output") {
277
+ const summaryLines = p.summary.split("\n").slice(0, 3);
278
+ for (const sl of summaryLines) {
279
+ lines.push(` ${sl.slice(0, 120)}`);
280
+ }
281
+ }
282
+ }
283
+ return lines.join("\n");
284
+ }
285
+ export {
286
+ OrchestrationEngine,
287
+ OrchestrationRunRepository,
288
+ OrchestrationTaskRepository,
289
+ aggregateResults,
290
+ formatAggregatedResults
291
+ };
292
+ //# sourceMappingURL=dist-GNHTH2DH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../orchestrator/src/repository.ts","../../orchestrator/src/engine.ts","../../orchestrator/src/aggregator.ts"],"sourcesContent":["/**\n * Repositories for orchestration_runs and orchestration_tasks tables.\n */\n\nimport type Database from \"better-sqlite3\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n OrchestrationRun,\n OrchestrationStatus,\n OrchestrationTask,\n OrchTaskStatus,\n} from \"@brainst0rm/shared\";\n\nfunction rowToRun(row: any): OrchestrationRun {\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n leadSessionId: row.lead_session_id ?? undefined,\n status: row.status as OrchestrationStatus,\n projectIds: JSON.parse(row.project_ids || \"[]\"),\n budgetLimit: row.budget_limit ?? undefined,\n totalCost: row.total_cost,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nfunction rowToTask(row: any): OrchestrationTask {\n return {\n id: row.id,\n runId: row.run_id,\n projectId: row.project_id,\n prompt: row.prompt,\n status: row.status as OrchTaskStatus,\n subagentType: row.subagent_type,\n resultSummary: row.result_summary ?? undefined,\n cost: row.cost,\n sessionId: row.session_id ?? undefined,\n dependsOn: JSON.parse(row.depends_on || \"[]\"),\n startedAt: row.started_at ?? undefined,\n completedAt: row.completed_at ?? undefined,\n };\n}\n\nexport class OrchestrationRunRepository {\n constructor(private db: Database.Database) {}\n\n create(data: {\n name: string;\n description: string;\n projectIds: string[];\n budgetLimit?: number;\n leadSessionId?: string;\n }): OrchestrationRun {\n const id = randomUUID();\n const now = Math.floor(Date.now() / 1000);\n this.db\n .prepare(\n `INSERT INTO orchestration_runs (id, name, description, lead_session_id, project_ids, budget_limit, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n data.name,\n data.description,\n data.leadSessionId ?? null,\n JSON.stringify(data.projectIds),\n data.budgetLimit ?? null,\n now,\n now,\n );\n return this.getById(id)!;\n }\n\n getById(id: string): OrchestrationRun | undefined {\n const row = this.db\n .prepare(\"SELECT * FROM orchestration_runs WHERE id = ?\")\n .get(id);\n return row ? rowToRun(row) : undefined;\n }\n\n listRecent(limit = 10): OrchestrationRun[] {\n return this.db\n .prepare(\n \"SELECT * FROM orchestration_runs ORDER BY created_at DESC LIMIT ?\",\n )\n .all(limit)\n .map(rowToRun);\n }\n\n updateStatus(id: string, status: OrchestrationStatus, cost?: number): void {\n const now = Math.floor(Date.now() / 1000);\n if (cost !== undefined) {\n this.db\n .prepare(\n \"UPDATE orchestration_runs SET status = ?, total_cost = ?, updated_at = ? WHERE id = ?\",\n )\n .run(status, cost, now, id);\n } else {\n this.db\n .prepare(\n \"UPDATE orchestration_runs SET status = ?, updated_at = ? WHERE id = ?\",\n )\n .run(status, now, id);\n }\n }\n}\n\nexport class OrchestrationTaskRepository {\n constructor(private db: Database.Database) {}\n\n create(data: {\n runId: string;\n projectId: string;\n prompt: string;\n subagentType?: string;\n dependsOn?: string[];\n }): OrchestrationTask {\n const id = randomUUID();\n this.db\n .prepare(\n `INSERT INTO orchestration_tasks (id, run_id, project_id, prompt, subagent_type, depends_on)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n data.runId,\n data.projectId,\n data.prompt,\n data.subagentType ?? \"code\",\n JSON.stringify(data.dependsOn ?? []),\n );\n return this.getById(id)!;\n }\n\n getById(id: string): OrchestrationTask | undefined {\n const row = this.db\n .prepare(\"SELECT * FROM orchestration_tasks WHERE id = ?\")\n .get(id);\n return row ? rowToTask(row) : undefined;\n }\n\n listByRun(runId: string): OrchestrationTask[] {\n return this.db\n .prepare(\"SELECT * FROM orchestration_tasks WHERE run_id = ?\")\n .all(runId)\n .map(rowToTask);\n }\n\n updateStatus(\n id: string,\n status: OrchTaskStatus,\n data?: { resultSummary?: string; cost?: number; sessionId?: string },\n ): void {\n const now = Math.floor(Date.now() / 1000);\n const completedAt =\n status === \"completed\" || status === \"failed\" ? now : null;\n const startedAt = status === \"running\" ? now : undefined;\n\n this.db\n .prepare(\n `UPDATE orchestration_tasks SET status = ?, result_summary = COALESCE(?, result_summary),\n cost = COALESCE(?, cost), session_id = COALESCE(?, session_id),\n started_at = COALESCE(?, started_at), completed_at = COALESCE(?, completed_at)\n WHERE id = ?`,\n )\n .run(\n status,\n data?.resultSummary ?? null,\n data?.cost ?? null,\n data?.sessionId ?? null,\n startedAt ?? null,\n completedAt,\n id,\n );\n }\n}\n","/**\n * OrchestrationEngine — coordinates work across multiple projects.\n *\n * Flow:\n * 1. Receives a high-level request + list of target projects\n * 2. Generates per-project tasks (via planner or direct decomposition)\n * 3. Executes tasks in dependency order, each in its own project context\n * 4. Aggregates results into a unified summary\n *\n * Each project task runs as an isolated subagent scoped to that project's directory.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type {\n OrchestrationRun,\n OrchestrationTask,\n Project,\n} from \"@brainst0rm/shared\";\nimport {\n OrchestrationRunRepository,\n OrchestrationTaskRepository,\n} from \"./repository.js\";\nimport { ProjectRepository } from \"@brainst0rm/projects\";\n\n// ── Event Types ─────────────────────────────────────────────────────\n\nexport type OrchestrationEvent =\n | { type: \"plan-ready\"; run: OrchestrationRun; tasks: OrchestrationTask[] }\n | { type: \"task-started\"; task: OrchestrationTask; project: Project }\n | {\n type: \"task-completed\";\n task: OrchestrationTask;\n project: Project;\n summary: string;\n cost: number;\n }\n | {\n type: \"task-failed\";\n task: OrchestrationTask;\n project: Project;\n error: string;\n }\n | {\n type: \"orchestration-completed\";\n run: OrchestrationRun;\n results: Array<{ projectName: string; summary: string; cost: number }>;\n }\n | { type: \"orchestration-failed\"; run: OrchestrationRun; error: string };\n\n// ── Engine ──────────────────────────────────────────────────────────\n\nexport interface OrchestrationOptions {\n description: string;\n projectNames: string[];\n budgetLimit?: number;\n subagentType?: string;\n /** Optional: provide pre-decomposed per-project prompts */\n perProjectPrompts?: Map<string, string>;\n /** Callback to execute a task in a project context */\n executeTask?: (\n project: Project,\n prompt: string,\n opts: { budget: number; subagentType: string },\n ) => Promise<{ summary: string; cost: number }>;\n}\n\nexport class OrchestrationEngine {\n private runs: OrchestrationRunRepository;\n private tasks: OrchestrationTaskRepository;\n private projects: ProjectRepository;\n\n constructor(private db: Database.Database) {\n this.runs = new OrchestrationRunRepository(db);\n this.tasks = new OrchestrationTaskRepository(db);\n this.projects = new ProjectRepository(db);\n }\n\n /**\n * Run an orchestration as an async generator yielding events.\n */\n async *run(opts: OrchestrationOptions): AsyncGenerator<OrchestrationEvent> {\n // Resolve project names to Project records\n const resolvedProjects: Project[] = [];\n for (const name of opts.projectNames) {\n const project = this.projects.getByName(name);\n if (!project) {\n throw new Error(\n `Project \"${name}\" not found. Run 'storm projects list' to see registered projects.`,\n );\n }\n resolvedProjects.push(project);\n }\n\n // Create orchestration run\n const orchestrationRun = this.runs.create({\n name: opts.description.slice(0, 100),\n description: opts.description,\n projectIds: resolvedProjects.map((p) => p.id),\n budgetLimit: opts.budgetLimit,\n });\n\n this.runs.updateStatus(orchestrationRun.id, \"running\");\n\n // Create per-project tasks\n const budgetPerProject = opts.budgetLimit\n ? (opts.budgetLimit / resolvedProjects.length) * 1.2 // 20% slack\n : undefined;\n\n const orchestrationTasks: OrchestrationTask[] = [];\n for (const project of resolvedProjects) {\n const prompt =\n opts.perProjectPrompts?.get(project.name) ??\n `In the context of the \"${project.name}\" project at ${project.path}:\\n\\n${opts.description}`;\n\n const task = this.tasks.create({\n runId: orchestrationRun.id,\n projectId: project.id,\n prompt,\n subagentType: opts.subagentType ?? \"code\",\n });\n orchestrationTasks.push(task);\n }\n\n yield {\n type: \"plan-ready\",\n run: orchestrationRun,\n tasks: orchestrationTasks,\n };\n\n // Execute tasks (currently sequential — parallel with dep resolution in future)\n const results: Array<{\n projectName: string;\n summary: string;\n cost: number;\n }> = [];\n let totalCost = 0;\n\n for (let i = 0; i < orchestrationTasks.length; i++) {\n const task = orchestrationTasks[i];\n const project = resolvedProjects[i];\n\n this.tasks.updateStatus(task.id, \"running\");\n yield { type: \"task-started\", task, project };\n\n try {\n let summary: string;\n let cost: number;\n\n if (opts.executeTask) {\n // Use provided execution callback (wired to real agent loop)\n const result = await opts.executeTask(project, task.prompt, {\n budget: budgetPerProject ?? 1.0,\n subagentType: opts.subagentType ?? \"code\",\n });\n summary = result.summary;\n cost = result.cost;\n } else {\n // Placeholder: no agent loop available\n summary = `[Placeholder] Would execute in ${project.name}: ${task.prompt.slice(0, 80)}...`;\n cost = 0;\n }\n\n totalCost += cost;\n\n this.tasks.updateStatus(task.id, \"completed\", {\n resultSummary: summary,\n cost,\n });\n\n results.push({ projectName: project.name, summary, cost });\n yield { type: \"task-completed\", task, project, summary, cost };\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.tasks.updateStatus(task.id, \"failed\", {\n resultSummary: error,\n cost: 0,\n });\n yield { type: \"task-failed\", task, project, error };\n\n // Continue with remaining projects (don't fail the whole orchestration)\n results.push({\n projectName: project.name,\n summary: `FAILED: ${error}`,\n cost: 0,\n });\n }\n }\n\n // Mark orchestration complete\n this.runs.updateStatus(orchestrationRun.id, \"completed\", totalCost);\n const updatedRun = this.runs.getById(orchestrationRun.id)!;\n\n yield { type: \"orchestration-completed\", run: updatedRun, results };\n }\n\n /** Get run details with all tasks. */\n getRunWithTasks(\n runId: string,\n ): { run: OrchestrationRun; tasks: OrchestrationTask[] } | undefined {\n const run = this.runs.getById(runId);\n if (!run) return undefined;\n const tasks = this.tasks.listByRun(runId);\n return { run, tasks };\n }\n\n /** List recent orchestration runs. */\n listRecent(limit = 10): OrchestrationRun[] {\n return this.runs.listRecent(limit);\n }\n\n /** Cancel a running orchestration. */\n cancel(runId: string): void {\n const run = this.runs.getById(runId);\n if (!run || run.status !== \"running\") return;\n\n // Cancel pending tasks\n const tasks = this.tasks.listByRun(runId);\n for (const task of tasks) {\n if (task.status === \"pending\") {\n this.tasks.updateStatus(task.id, \"skipped\");\n }\n }\n\n this.runs.updateStatus(runId, \"cancelled\");\n }\n}\n","/**\n * Aggregator — formats orchestration results into a unified summary.\n */\n\nimport type { OrchestrationRun, OrchestrationTask } from \"@brainst0rm/shared\";\n\nexport interface AggregatedResult {\n summary: string;\n totalCost: number;\n projectCount: number;\n successCount: number;\n failureCount: number;\n perProject: Array<{\n name: string;\n status: string;\n summary: string;\n cost: number;\n }>;\n}\n\n/**\n * Aggregate orchestration results into a readable summary.\n */\nexport function aggregateResults(\n run: OrchestrationRun,\n tasks: OrchestrationTask[],\n projectNames: Map<string, string>,\n): AggregatedResult {\n const perProject = tasks.map((t) => ({\n name: projectNames.get(t.projectId) ?? t.projectId.slice(0, 8),\n status: t.status,\n summary: t.resultSummary ?? \"No output\",\n cost: t.cost,\n }));\n\n const successCount = tasks.filter((t) => t.status === \"completed\").length;\n const failureCount = tasks.filter((t) => t.status === \"failed\").length;\n\n return {\n summary: run.description,\n totalCost: run.totalCost,\n projectCount: tasks.length,\n successCount,\n failureCount,\n perProject,\n };\n}\n\n/**\n * Format aggregated results as a markdown string for display.\n */\nexport function formatAggregatedResults(result: AggregatedResult): string {\n const lines: string[] = [];\n\n lines.push(`Orchestration: ${result.summary}`);\n lines.push(\n `${result.successCount}/${result.projectCount} projects completed · $${result.totalCost.toFixed(4)} total`,\n );\n lines.push(\"\");\n\n for (const p of result.perProject) {\n const icon =\n p.status === \"completed\"\n ? \"✓\"\n : p.status === \"failed\"\n ? \"✗\"\n : p.status === \"skipped\"\n ? \"○\"\n : \"●\";\n lines.push(` ${icon} ${p.name} ($${p.cost.toFixed(4)})`);\n if (p.summary && p.summary !== \"No output\") {\n // Indent and truncate summary\n const summaryLines = p.summary.split(\"\\n\").slice(0, 3);\n for (const sl of summaryLines) {\n lines.push(` ${sl.slice(0, 120)}`);\n }\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,293 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ProjectRepository
4
+ } from "./chunk-2CHZHDIM.js";
5
+ import "./chunk-ZWE3DS7E.js";
6
+
7
+ // ../orchestrator/dist/index.js
8
+ import { randomUUID } from "crypto";
9
+ function rowToRun(row) {
10
+ return {
11
+ id: row.id,
12
+ name: row.name,
13
+ description: row.description,
14
+ leadSessionId: row.lead_session_id ?? void 0,
15
+ status: row.status,
16
+ projectIds: JSON.parse(row.project_ids || "[]"),
17
+ budgetLimit: row.budget_limit ?? void 0,
18
+ totalCost: row.total_cost,
19
+ createdAt: row.created_at,
20
+ updatedAt: row.updated_at
21
+ };
22
+ }
23
+ function rowToTask(row) {
24
+ return {
25
+ id: row.id,
26
+ runId: row.run_id,
27
+ projectId: row.project_id,
28
+ prompt: row.prompt,
29
+ status: row.status,
30
+ subagentType: row.subagent_type,
31
+ resultSummary: row.result_summary ?? void 0,
32
+ cost: row.cost,
33
+ sessionId: row.session_id ?? void 0,
34
+ dependsOn: JSON.parse(row.depends_on || "[]"),
35
+ startedAt: row.started_at ?? void 0,
36
+ completedAt: row.completed_at ?? void 0
37
+ };
38
+ }
39
+ var OrchestrationRunRepository = class {
40
+ constructor(db) {
41
+ this.db = db;
42
+ }
43
+ create(data) {
44
+ const id = randomUUID();
45
+ const now = Math.floor(Date.now() / 1e3);
46
+ this.db.prepare(
47
+ `INSERT INTO orchestration_runs (id, name, description, lead_session_id, project_ids, budget_limit, created_at, updated_at)
48
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`
49
+ ).run(
50
+ id,
51
+ data.name,
52
+ data.description,
53
+ data.leadSessionId ?? null,
54
+ JSON.stringify(data.projectIds),
55
+ data.budgetLimit ?? null,
56
+ now,
57
+ now
58
+ );
59
+ return this.getById(id);
60
+ }
61
+ getById(id) {
62
+ const row = this.db.prepare("SELECT * FROM orchestration_runs WHERE id = ?").get(id);
63
+ return row ? rowToRun(row) : void 0;
64
+ }
65
+ listRecent(limit = 10) {
66
+ return this.db.prepare(
67
+ "SELECT * FROM orchestration_runs ORDER BY created_at DESC LIMIT ?"
68
+ ).all(limit).map(rowToRun);
69
+ }
70
+ updateStatus(id, status, cost) {
71
+ const now = Math.floor(Date.now() / 1e3);
72
+ if (cost !== void 0) {
73
+ this.db.prepare(
74
+ "UPDATE orchestration_runs SET status = ?, total_cost = ?, updated_at = ? WHERE id = ?"
75
+ ).run(status, cost, now, id);
76
+ } else {
77
+ this.db.prepare(
78
+ "UPDATE orchestration_runs SET status = ?, updated_at = ? WHERE id = ?"
79
+ ).run(status, now, id);
80
+ }
81
+ }
82
+ };
83
+ var OrchestrationTaskRepository = class {
84
+ constructor(db) {
85
+ this.db = db;
86
+ }
87
+ create(data) {
88
+ const id = randomUUID();
89
+ this.db.prepare(
90
+ `INSERT INTO orchestration_tasks (id, run_id, project_id, prompt, subagent_type, depends_on)
91
+ VALUES (?, ?, ?, ?, ?, ?)`
92
+ ).run(
93
+ id,
94
+ data.runId,
95
+ data.projectId,
96
+ data.prompt,
97
+ data.subagentType ?? "code",
98
+ JSON.stringify(data.dependsOn ?? [])
99
+ );
100
+ return this.getById(id);
101
+ }
102
+ getById(id) {
103
+ const row = this.db.prepare("SELECT * FROM orchestration_tasks WHERE id = ?").get(id);
104
+ return row ? rowToTask(row) : void 0;
105
+ }
106
+ listByRun(runId) {
107
+ return this.db.prepare("SELECT * FROM orchestration_tasks WHERE run_id = ?").all(runId).map(rowToTask);
108
+ }
109
+ updateStatus(id, status, data) {
110
+ const now = Math.floor(Date.now() / 1e3);
111
+ const completedAt = status === "completed" || status === "failed" ? now : null;
112
+ const startedAt = status === "running" ? now : void 0;
113
+ this.db.prepare(
114
+ `UPDATE orchestration_tasks SET status = ?, result_summary = COALESCE(?, result_summary),
115
+ cost = COALESCE(?, cost), session_id = COALESCE(?, session_id),
116
+ started_at = COALESCE(?, started_at), completed_at = COALESCE(?, completed_at)
117
+ WHERE id = ?`
118
+ ).run(
119
+ status,
120
+ data?.resultSummary ?? null,
121
+ data?.cost ?? null,
122
+ data?.sessionId ?? null,
123
+ startedAt ?? null,
124
+ completedAt,
125
+ id
126
+ );
127
+ }
128
+ };
129
+ var OrchestrationEngine = class {
130
+ constructor(db) {
131
+ this.db = db;
132
+ this.runs = new OrchestrationRunRepository(db);
133
+ this.tasks = new OrchestrationTaskRepository(db);
134
+ this.projects = new ProjectRepository(db);
135
+ }
136
+ runs;
137
+ tasks;
138
+ projects;
139
+ /**
140
+ * Run an orchestration as an async generator yielding events.
141
+ */
142
+ async *run(opts) {
143
+ const resolvedProjects = [];
144
+ for (const name of opts.projectNames) {
145
+ const project = this.projects.getByName(name);
146
+ if (!project) {
147
+ throw new Error(
148
+ `Project "${name}" not found. Run 'storm projects list' to see registered projects.`
149
+ );
150
+ }
151
+ resolvedProjects.push(project);
152
+ }
153
+ const orchestrationRun = this.runs.create({
154
+ name: opts.description.slice(0, 100),
155
+ description: opts.description,
156
+ projectIds: resolvedProjects.map((p) => p.id),
157
+ budgetLimit: opts.budgetLimit
158
+ });
159
+ this.runs.updateStatus(orchestrationRun.id, "running");
160
+ const budgetPerProject = opts.budgetLimit ? opts.budgetLimit / resolvedProjects.length * 1.2 : void 0;
161
+ const orchestrationTasks = [];
162
+ for (const project of resolvedProjects) {
163
+ const prompt = opts.perProjectPrompts?.get(project.name) ?? `In the context of the "${project.name}" project at ${project.path}:
164
+
165
+ ${opts.description}`;
166
+ const task = this.tasks.create({
167
+ runId: orchestrationRun.id,
168
+ projectId: project.id,
169
+ prompt,
170
+ subagentType: opts.subagentType ?? "code"
171
+ });
172
+ orchestrationTasks.push(task);
173
+ }
174
+ yield {
175
+ type: "plan-ready",
176
+ run: orchestrationRun,
177
+ tasks: orchestrationTasks
178
+ };
179
+ const results = [];
180
+ let totalCost = 0;
181
+ for (let i = 0; i < orchestrationTasks.length; i++) {
182
+ const task = orchestrationTasks[i];
183
+ const project = resolvedProjects[i];
184
+ this.tasks.updateStatus(task.id, "running");
185
+ yield { type: "task-started", task, project };
186
+ try {
187
+ let summary;
188
+ let cost;
189
+ if (opts.executeTask) {
190
+ const result = await opts.executeTask(project, task.prompt, {
191
+ budget: budgetPerProject ?? 1,
192
+ subagentType: opts.subagentType ?? "code"
193
+ });
194
+ summary = result.summary;
195
+ cost = result.cost;
196
+ } else {
197
+ summary = `[Placeholder] Would execute in ${project.name}: ${task.prompt.slice(0, 80)}...`;
198
+ cost = 0;
199
+ }
200
+ totalCost += cost;
201
+ this.tasks.updateStatus(task.id, "completed", {
202
+ resultSummary: summary,
203
+ cost
204
+ });
205
+ results.push({ projectName: project.name, summary, cost });
206
+ yield { type: "task-completed", task, project, summary, cost };
207
+ } catch (err) {
208
+ const error = err instanceof Error ? err.message : String(err);
209
+ this.tasks.updateStatus(task.id, "failed", {
210
+ resultSummary: error,
211
+ cost: 0
212
+ });
213
+ yield { type: "task-failed", task, project, error };
214
+ results.push({
215
+ projectName: project.name,
216
+ summary: `FAILED: ${error}`,
217
+ cost: 0
218
+ });
219
+ }
220
+ }
221
+ this.runs.updateStatus(orchestrationRun.id, "completed", totalCost);
222
+ const updatedRun = this.runs.getById(orchestrationRun.id);
223
+ yield { type: "orchestration-completed", run: updatedRun, results };
224
+ }
225
+ /** Get run details with all tasks. */
226
+ getRunWithTasks(runId) {
227
+ const run = this.runs.getById(runId);
228
+ if (!run) return void 0;
229
+ const tasks = this.tasks.listByRun(runId);
230
+ return { run, tasks };
231
+ }
232
+ /** List recent orchestration runs. */
233
+ listRecent(limit = 10) {
234
+ return this.runs.listRecent(limit);
235
+ }
236
+ /** Cancel a running orchestration. */
237
+ cancel(runId) {
238
+ const run = this.runs.getById(runId);
239
+ if (!run || run.status !== "running") return;
240
+ const tasks = this.tasks.listByRun(runId);
241
+ for (const task of tasks) {
242
+ if (task.status === "pending") {
243
+ this.tasks.updateStatus(task.id, "skipped");
244
+ }
245
+ }
246
+ this.runs.updateStatus(runId, "cancelled");
247
+ }
248
+ };
249
+ function aggregateResults(run, tasks, projectNames) {
250
+ const perProject = tasks.map((t) => ({
251
+ name: projectNames.get(t.projectId) ?? t.projectId.slice(0, 8),
252
+ status: t.status,
253
+ summary: t.resultSummary ?? "No output",
254
+ cost: t.cost
255
+ }));
256
+ const successCount = tasks.filter((t) => t.status === "completed").length;
257
+ const failureCount = tasks.filter((t) => t.status === "failed").length;
258
+ return {
259
+ summary: run.description,
260
+ totalCost: run.totalCost,
261
+ projectCount: tasks.length,
262
+ successCount,
263
+ failureCount,
264
+ perProject
265
+ };
266
+ }
267
+ function formatAggregatedResults(result) {
268
+ const lines = [];
269
+ lines.push(`Orchestration: ${result.summary}`);
270
+ lines.push(
271
+ `${result.successCount}/${result.projectCount} projects completed \xB7 $${result.totalCost.toFixed(4)} total`
272
+ );
273
+ lines.push("");
274
+ for (const p of result.perProject) {
275
+ const icon = p.status === "completed" ? "\u2713" : p.status === "failed" ? "\u2717" : p.status === "skipped" ? "\u25CB" : "\u25CF";
276
+ lines.push(` ${icon} ${p.name} ($${p.cost.toFixed(4)})`);
277
+ if (p.summary && p.summary !== "No output") {
278
+ const summaryLines = p.summary.split("\n").slice(0, 3);
279
+ for (const sl of summaryLines) {
280
+ lines.push(` ${sl.slice(0, 120)}`);
281
+ }
282
+ }
283
+ }
284
+ return lines.join("\n");
285
+ }
286
+ export {
287
+ OrchestrationEngine,
288
+ OrchestrationRunRepository,
289
+ OrchestrationTaskRepository,
290
+ aggregateResults,
291
+ formatAggregatedResults
292
+ };
293
+ //# sourceMappingURL=dist-JUDVPE7G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../orchestrator/src/repository.ts","../../orchestrator/src/engine.ts","../../orchestrator/src/aggregator.ts"],"sourcesContent":["/**\n * Repositories for orchestration_runs and orchestration_tasks tables.\n */\n\nimport type Database from \"better-sqlite3\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n OrchestrationRun,\n OrchestrationStatus,\n OrchestrationTask,\n OrchTaskStatus,\n} from \"@brainst0rm/shared\";\n\nfunction rowToRun(row: any): OrchestrationRun {\n return {\n id: row.id,\n name: row.name,\n description: row.description,\n leadSessionId: row.lead_session_id ?? undefined,\n status: row.status as OrchestrationStatus,\n projectIds: JSON.parse(row.project_ids || \"[]\"),\n budgetLimit: row.budget_limit ?? undefined,\n totalCost: row.total_cost,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nfunction rowToTask(row: any): OrchestrationTask {\n return {\n id: row.id,\n runId: row.run_id,\n projectId: row.project_id,\n prompt: row.prompt,\n status: row.status as OrchTaskStatus,\n subagentType: row.subagent_type,\n resultSummary: row.result_summary ?? undefined,\n cost: row.cost,\n sessionId: row.session_id ?? undefined,\n dependsOn: JSON.parse(row.depends_on || \"[]\"),\n startedAt: row.started_at ?? undefined,\n completedAt: row.completed_at ?? undefined,\n };\n}\n\nexport class OrchestrationRunRepository {\n constructor(private db: Database.Database) {}\n\n create(data: {\n name: string;\n description: string;\n projectIds: string[];\n budgetLimit?: number;\n leadSessionId?: string;\n }): OrchestrationRun {\n const id = randomUUID();\n const now = Math.floor(Date.now() / 1000);\n this.db\n .prepare(\n `INSERT INTO orchestration_runs (id, name, description, lead_session_id, project_ids, budget_limit, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n data.name,\n data.description,\n data.leadSessionId ?? null,\n JSON.stringify(data.projectIds),\n data.budgetLimit ?? null,\n now,\n now,\n );\n return this.getById(id)!;\n }\n\n getById(id: string): OrchestrationRun | undefined {\n const row = this.db\n .prepare(\"SELECT * FROM orchestration_runs WHERE id = ?\")\n .get(id);\n return row ? rowToRun(row) : undefined;\n }\n\n listRecent(limit = 10): OrchestrationRun[] {\n return this.db\n .prepare(\n \"SELECT * FROM orchestration_runs ORDER BY created_at DESC LIMIT ?\",\n )\n .all(limit)\n .map(rowToRun);\n }\n\n updateStatus(id: string, status: OrchestrationStatus, cost?: number): void {\n const now = Math.floor(Date.now() / 1000);\n if (cost !== undefined) {\n this.db\n .prepare(\n \"UPDATE orchestration_runs SET status = ?, total_cost = ?, updated_at = ? WHERE id = ?\",\n )\n .run(status, cost, now, id);\n } else {\n this.db\n .prepare(\n \"UPDATE orchestration_runs SET status = ?, updated_at = ? WHERE id = ?\",\n )\n .run(status, now, id);\n }\n }\n}\n\nexport class OrchestrationTaskRepository {\n constructor(private db: Database.Database) {}\n\n create(data: {\n runId: string;\n projectId: string;\n prompt: string;\n subagentType?: string;\n dependsOn?: string[];\n }): OrchestrationTask {\n const id = randomUUID();\n this.db\n .prepare(\n `INSERT INTO orchestration_tasks (id, run_id, project_id, prompt, subagent_type, depends_on)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(\n id,\n data.runId,\n data.projectId,\n data.prompt,\n data.subagentType ?? \"code\",\n JSON.stringify(data.dependsOn ?? []),\n );\n return this.getById(id)!;\n }\n\n getById(id: string): OrchestrationTask | undefined {\n const row = this.db\n .prepare(\"SELECT * FROM orchestration_tasks WHERE id = ?\")\n .get(id);\n return row ? rowToTask(row) : undefined;\n }\n\n listByRun(runId: string): OrchestrationTask[] {\n return this.db\n .prepare(\"SELECT * FROM orchestration_tasks WHERE run_id = ?\")\n .all(runId)\n .map(rowToTask);\n }\n\n updateStatus(\n id: string,\n status: OrchTaskStatus,\n data?: { resultSummary?: string; cost?: number; sessionId?: string },\n ): void {\n const now = Math.floor(Date.now() / 1000);\n const completedAt =\n status === \"completed\" || status === \"failed\" ? now : null;\n const startedAt = status === \"running\" ? now : undefined;\n\n this.db\n .prepare(\n `UPDATE orchestration_tasks SET status = ?, result_summary = COALESCE(?, result_summary),\n cost = COALESCE(?, cost), session_id = COALESCE(?, session_id),\n started_at = COALESCE(?, started_at), completed_at = COALESCE(?, completed_at)\n WHERE id = ?`,\n )\n .run(\n status,\n data?.resultSummary ?? null,\n data?.cost ?? null,\n data?.sessionId ?? null,\n startedAt ?? null,\n completedAt,\n id,\n );\n }\n}\n","/**\n * OrchestrationEngine — coordinates work across multiple projects.\n *\n * Flow:\n * 1. Receives a high-level request + list of target projects\n * 2. Generates per-project tasks (via planner or direct decomposition)\n * 3. Executes tasks in dependency order, each in its own project context\n * 4. Aggregates results into a unified summary\n *\n * Each project task runs as an isolated subagent scoped to that project's directory.\n */\n\nimport type Database from \"better-sqlite3\";\nimport type {\n OrchestrationRun,\n OrchestrationTask,\n Project,\n} from \"@brainst0rm/shared\";\nimport {\n OrchestrationRunRepository,\n OrchestrationTaskRepository,\n} from \"./repository.js\";\nimport { ProjectRepository } from \"@brainst0rm/projects\";\n\n// ── Event Types ─────────────────────────────────────────────────────\n\nexport type OrchestrationEvent =\n | { type: \"plan-ready\"; run: OrchestrationRun; tasks: OrchestrationTask[] }\n | { type: \"task-started\"; task: OrchestrationTask; project: Project }\n | {\n type: \"task-completed\";\n task: OrchestrationTask;\n project: Project;\n summary: string;\n cost: number;\n }\n | {\n type: \"task-failed\";\n task: OrchestrationTask;\n project: Project;\n error: string;\n }\n | {\n type: \"orchestration-completed\";\n run: OrchestrationRun;\n results: Array<{ projectName: string; summary: string; cost: number }>;\n }\n | { type: \"orchestration-failed\"; run: OrchestrationRun; error: string };\n\n// ── Engine ──────────────────────────────────────────────────────────\n\nexport interface OrchestrationOptions {\n description: string;\n projectNames: string[];\n budgetLimit?: number;\n subagentType?: string;\n /** Optional: provide pre-decomposed per-project prompts */\n perProjectPrompts?: Map<string, string>;\n /** Callback to execute a task in a project context */\n executeTask?: (\n project: Project,\n prompt: string,\n opts: { budget: number; subagentType: string },\n ) => Promise<{ summary: string; cost: number }>;\n}\n\nexport class OrchestrationEngine {\n private runs: OrchestrationRunRepository;\n private tasks: OrchestrationTaskRepository;\n private projects: ProjectRepository;\n\n constructor(private db: Database.Database) {\n this.runs = new OrchestrationRunRepository(db);\n this.tasks = new OrchestrationTaskRepository(db);\n this.projects = new ProjectRepository(db);\n }\n\n /**\n * Run an orchestration as an async generator yielding events.\n */\n async *run(opts: OrchestrationOptions): AsyncGenerator<OrchestrationEvent> {\n // Resolve project names to Project records\n const resolvedProjects: Project[] = [];\n for (const name of opts.projectNames) {\n const project = this.projects.getByName(name);\n if (!project) {\n throw new Error(\n `Project \"${name}\" not found. Run 'storm projects list' to see registered projects.`,\n );\n }\n resolvedProjects.push(project);\n }\n\n // Create orchestration run\n const orchestrationRun = this.runs.create({\n name: opts.description.slice(0, 100),\n description: opts.description,\n projectIds: resolvedProjects.map((p) => p.id),\n budgetLimit: opts.budgetLimit,\n });\n\n this.runs.updateStatus(orchestrationRun.id, \"running\");\n\n // Create per-project tasks\n const budgetPerProject = opts.budgetLimit\n ? (opts.budgetLimit / resolvedProjects.length) * 1.2 // 20% slack\n : undefined;\n\n const orchestrationTasks: OrchestrationTask[] = [];\n for (const project of resolvedProjects) {\n const prompt =\n opts.perProjectPrompts?.get(project.name) ??\n `In the context of the \"${project.name}\" project at ${project.path}:\\n\\n${opts.description}`;\n\n const task = this.tasks.create({\n runId: orchestrationRun.id,\n projectId: project.id,\n prompt,\n subagentType: opts.subagentType ?? \"code\",\n });\n orchestrationTasks.push(task);\n }\n\n yield {\n type: \"plan-ready\",\n run: orchestrationRun,\n tasks: orchestrationTasks,\n };\n\n // Execute tasks (currently sequential — parallel with dep resolution in future)\n const results: Array<{\n projectName: string;\n summary: string;\n cost: number;\n }> = [];\n let totalCost = 0;\n\n for (let i = 0; i < orchestrationTasks.length; i++) {\n const task = orchestrationTasks[i];\n const project = resolvedProjects[i];\n\n this.tasks.updateStatus(task.id, \"running\");\n yield { type: \"task-started\", task, project };\n\n try {\n let summary: string;\n let cost: number;\n\n if (opts.executeTask) {\n // Use provided execution callback (wired to real agent loop)\n const result = await opts.executeTask(project, task.prompt, {\n budget: budgetPerProject ?? 1.0,\n subagentType: opts.subagentType ?? \"code\",\n });\n summary = result.summary;\n cost = result.cost;\n } else {\n // Placeholder: no agent loop available\n summary = `[Placeholder] Would execute in ${project.name}: ${task.prompt.slice(0, 80)}...`;\n cost = 0;\n }\n\n totalCost += cost;\n\n this.tasks.updateStatus(task.id, \"completed\", {\n resultSummary: summary,\n cost,\n });\n\n results.push({ projectName: project.name, summary, cost });\n yield { type: \"task-completed\", task, project, summary, cost };\n } catch (err) {\n const error = err instanceof Error ? err.message : String(err);\n this.tasks.updateStatus(task.id, \"failed\", {\n resultSummary: error,\n cost: 0,\n });\n yield { type: \"task-failed\", task, project, error };\n\n // Continue with remaining projects (don't fail the whole orchestration)\n results.push({\n projectName: project.name,\n summary: `FAILED: ${error}`,\n cost: 0,\n });\n }\n }\n\n // Mark orchestration complete\n this.runs.updateStatus(orchestrationRun.id, \"completed\", totalCost);\n const updatedRun = this.runs.getById(orchestrationRun.id)!;\n\n yield { type: \"orchestration-completed\", run: updatedRun, results };\n }\n\n /** Get run details with all tasks. */\n getRunWithTasks(\n runId: string,\n ): { run: OrchestrationRun; tasks: OrchestrationTask[] } | undefined {\n const run = this.runs.getById(runId);\n if (!run) return undefined;\n const tasks = this.tasks.listByRun(runId);\n return { run, tasks };\n }\n\n /** List recent orchestration runs. */\n listRecent(limit = 10): OrchestrationRun[] {\n return this.runs.listRecent(limit);\n }\n\n /** Cancel a running orchestration. */\n cancel(runId: string): void {\n const run = this.runs.getById(runId);\n if (!run || run.status !== \"running\") return;\n\n // Cancel pending tasks\n const tasks = this.tasks.listByRun(runId);\n for (const task of tasks) {\n if (task.status === \"pending\") {\n this.tasks.updateStatus(task.id, \"skipped\");\n }\n }\n\n this.runs.updateStatus(runId, \"cancelled\");\n }\n}\n","/**\n * Aggregator — formats orchestration results into a unified summary.\n */\n\nimport type { OrchestrationRun, OrchestrationTask } from \"@brainst0rm/shared\";\n\nexport interface AggregatedResult {\n summary: string;\n totalCost: number;\n projectCount: number;\n successCount: number;\n failureCount: number;\n perProject: Array<{\n name: string;\n status: string;\n summary: string;\n cost: number;\n }>;\n}\n\n/**\n * Aggregate orchestration results into a readable summary.\n */\nexport function aggregateResults(\n run: OrchestrationRun,\n tasks: OrchestrationTask[],\n projectNames: Map<string, string>,\n): AggregatedResult {\n const perProject = tasks.map((t) => ({\n name: projectNames.get(t.projectId) ?? t.projectId.slice(0, 8),\n status: t.status,\n summary: t.resultSummary ?? \"No output\",\n cost: t.cost,\n }));\n\n const successCount = tasks.filter((t) => t.status === \"completed\").length;\n const failureCount = tasks.filter((t) => t.status === \"failed\").length;\n\n return {\n summary: run.description,\n totalCost: run.totalCost,\n projectCount: tasks.length,\n successCount,\n failureCount,\n perProject,\n };\n}\n\n/**\n * Format aggregated results as a markdown string for display.\n */\nexport function formatAggregatedResults(result: AggregatedResult): string {\n const lines: string[] = [];\n\n lines.push(`Orchestration: ${result.summary}`);\n lines.push(\n `${result.successCount}/${result.projectCount} projects completed · $${result.totalCost.toFixed(4)} total`,\n );\n lines.push(\"\");\n\n for (const p of result.perProject) {\n const icon =\n p.status === \"completed\"\n ? \"✓\"\n : p.status === \"failed\"\n ? \"✗\"\n : p.status === \"skipped\"\n ? \"○\"\n : \"●\";\n lines.push(` ${icon} ${p.name} ($${p.cost.toFixed(4)})`);\n if (p.summary && p.summary !== \"No output\") {\n // Indent and truncate summary\n const summaryLines = p.summary.split(\"\\n\").slice(0, 3);\n for (const sl of summaryLines) {\n lines.push(` ${sl.slice(0, 120)}`);\n }\n }\n }\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}