aegiscode 3.1.10 → 3.2.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 (209) hide show
  1. package/bin/aegis-cli-linux-x64 +0 -0
  2. package/bin/cli.js +68 -0
  3. package/package.json +11 -48
  4. package/scripts/download-binary.mjs +155 -0
  5. package/dist/main.js +0 -2171
  6. package/gui/run-gui.cjs +0 -13
  7. package/src/agent/Agent.ts +0 -903
  8. package/src/agent/SimpleAgent.ts +0 -48
  9. package/src/agent/index.ts +0 -54
  10. package/src/agent/orchestrator/AppBuilder.ts +0 -443
  11. package/src/agent/orchestrator/CouncilAgent.ts +0 -310
  12. package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
  13. package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
  14. package/src/agent/orchestrator/index.ts +0 -38
  15. package/src/agent/orchestrator/utils.ts +0 -397
  16. package/src/agent/pricing.ts +0 -115
  17. package/src/agent/router.ts +0 -74
  18. package/src/agent/routerStats.ts +0 -121
  19. package/src/agent/types.ts +0 -318
  20. package/src/auth/login.ts +0 -383
  21. package/src/cli/config.ts +0 -189
  22. package/src/cli/index.ts +0 -17
  23. package/src/cli/middleware.ts +0 -119
  24. package/src/cli/types.ts +0 -75
  25. package/src/config/ConfigManager.ts +0 -587
  26. package/src/config/index.ts +0 -7
  27. package/src/config/types.ts +0 -584
  28. package/src/context/CompactionService.ts +0 -300
  29. package/src/context/ContextManager.ts +0 -450
  30. package/src/context/FileAnalyzer.ts +0 -267
  31. package/src/context/TokenCounter.ts +0 -265
  32. package/src/context/index.ts +0 -27
  33. package/src/context/storage/CacheStore.ts +0 -176
  34. package/src/context/storage/JSONLStore.ts +0 -201
  35. package/src/context/storage/MemoryStore.ts +0 -205
  36. package/src/context/storage/PersistentStore.ts +0 -327
  37. package/src/context/storage/index.ts +0 -9
  38. package/src/context/storage/pathUtils.ts +0 -114
  39. package/src/context/test.ts +0 -309
  40. package/src/context/types.ts +0 -268
  41. package/src/hooks/HookExecutor.ts +0 -434
  42. package/src/hooks/HookManager.ts +0 -596
  43. package/src/hooks/HookService.ts +0 -269
  44. package/src/hooks/Matcher.ts +0 -157
  45. package/src/hooks/index.ts +0 -63
  46. package/src/hooks/types.ts +0 -424
  47. package/src/main.tsx +0 -596
  48. package/src/mcp/HealthMonitor.ts +0 -150
  49. package/src/mcp/McpClient.ts +0 -491
  50. package/src/mcp/McpRegistry.ts +0 -321
  51. package/src/mcp/createMcpTool.ts +0 -251
  52. package/src/mcp/index.ts +0 -15
  53. package/src/mcp/server.ts +0 -334
  54. package/src/mcp/test-server.ts +0 -88
  55. package/src/mcp/test.ts +0 -372
  56. package/src/mcp/types.ts +0 -247
  57. package/src/memory/AgentMemoryBus.ts +0 -432
  58. package/src/memory/CloudSync.ts +0 -99
  59. package/src/memory/DriveSync.ts +0 -106
  60. package/src/memory/SharedMemory.ts +0 -951
  61. package/src/memory/index.ts +0 -14
  62. package/src/memory/machineFingerprint.ts +0 -40
  63. package/src/orchestrator/SubAgentMetadata.ts +0 -136
  64. package/src/prompts/builder.ts +0 -213
  65. package/src/prompts/default.ts +0 -144
  66. package/src/prompts/index.ts +0 -16
  67. package/src/prompts/plan.ts +0 -64
  68. package/src/prompts/test.ts +0 -78
  69. package/src/services/AnthropicChatService.ts +0 -341
  70. package/src/services/ChatService.ts +0 -347
  71. package/src/services/ClaudeCliChatService.ts +0 -256
  72. package/src/services/CloudSync.ts +0 -168
  73. package/src/services/CostLedger.ts +0 -211
  74. package/src/services/Heartbeat.ts +0 -135
  75. package/src/services/LearningCollector.ts +0 -291
  76. package/src/services/OllamaInstaller.ts +0 -342
  77. package/src/services/VersionChecker.ts +0 -445
  78. package/src/services/index.ts +0 -57
  79. package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
  80. package/src/services/streaming/RenderingProfile.ts +0 -90
  81. package/src/services/streaming/StreamEventParser.ts +0 -181
  82. package/src/services/streaming/ThrottledRenderer.ts +0 -139
  83. package/src/services/streaming/TranscriptBuffer.ts +0 -574
  84. package/src/services/streaming/eventStatusMap.ts +0 -52
  85. package/src/services/streaming/index.ts +0 -46
  86. package/src/services/streaming/renderFormatting.ts +0 -79
  87. package/src/services/streaming/types.ts +0 -234
  88. package/src/skills/SkillLoader.ts +0 -126
  89. package/src/skills/SkillRegistry.ts +0 -366
  90. package/src/skills/index.ts +0 -48
  91. package/src/skills/types.ts +0 -146
  92. package/src/slash-commands/billing.ts +0 -70
  93. package/src/slash-commands/build.ts +0 -413
  94. package/src/slash-commands/builtinCommands.ts +0 -2733
  95. package/src/slash-commands/clone.ts +0 -242
  96. package/src/slash-commands/council.ts +0 -125
  97. package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
  98. package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
  99. package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
  100. package/src/slash-commands/custom/index.ts +0 -7
  101. package/src/slash-commands/debate.ts +0 -254
  102. package/src/slash-commands/gmail.ts +0 -105
  103. package/src/slash-commands/index.ts +0 -388
  104. package/src/slash-commands/mcpCommand.ts +0 -205
  105. package/src/slash-commands/types.ts +0 -201
  106. package/src/store/index.ts +0 -76
  107. package/src/store/selectors.ts +0 -246
  108. package/src/store/slices/appSlice.ts +0 -205
  109. package/src/store/slices/commandSlice.ts +0 -115
  110. package/src/store/slices/configSlice.ts +0 -46
  111. package/src/store/slices/focusSlice.ts +0 -64
  112. package/src/store/slices/index.ts +0 -9
  113. package/src/store/slices/sessionSlice.ts +0 -424
  114. package/src/store/streaming-buffer.ts +0 -425
  115. package/src/store/test.ts +0 -296
  116. package/src/store/types.ts +0 -274
  117. package/src/store/vanilla.ts +0 -186
  118. package/src/tools/builtin/bash.ts +0 -236
  119. package/src/tools/builtin/council.ts +0 -105
  120. package/src/tools/builtin/edit.ts +0 -213
  121. package/src/tools/builtin/glob.ts +0 -136
  122. package/src/tools/builtin/grep.ts +0 -263
  123. package/src/tools/builtin/index.ts +0 -61
  124. package/src/tools/builtin/memory.ts +0 -66
  125. package/src/tools/builtin/read.ts +0 -168
  126. package/src/tools/builtin/skill.ts +0 -97
  127. package/src/tools/builtin/snapshot.ts +0 -40
  128. package/src/tools/builtin/task.ts +0 -106
  129. package/src/tools/builtin/write.ts +0 -134
  130. package/src/tools/createTool.ts +0 -221
  131. package/src/tools/execution/ExecutionPipeline.ts +0 -263
  132. package/src/tools/execution/index.ts +0 -40
  133. package/src/tools/execution/stages/CacheStage.ts +0 -131
  134. package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
  135. package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
  136. package/src/tools/execution/stages/ExecutionStage.ts +0 -48
  137. package/src/tools/execution/stages/FormattingStage.ts +0 -44
  138. package/src/tools/execution/stages/HookStage.ts +0 -72
  139. package/src/tools/execution/stages/PermissionStage.ts +0 -287
  140. package/src/tools/execution/stages/PostHookStage.ts +0 -71
  141. package/src/tools/execution/stages/index.ts +0 -12
  142. package/src/tools/execution/test.ts +0 -266
  143. package/src/tools/execution/types.ts +0 -273
  144. package/src/tools/index.ts +0 -81
  145. package/src/tools/registry.ts +0 -304
  146. package/src/tools/schemas.ts +0 -109
  147. package/src/tools/test.ts +0 -220
  148. package/src/tools/types.ts +0 -175
  149. package/src/tools/validation/PermissionChecker.ts +0 -242
  150. package/src/tools/validation/SensitiveFileDetector.ts +0 -210
  151. package/src/tools/validation/index.ts +0 -11
  152. package/src/ui/App.tsx +0 -166
  153. package/src/ui/components/AegisInterface.tsx +0 -484
  154. package/src/ui/components/common/ChatSearch.tsx +0 -150
  155. package/src/ui/components/common/ErrorBoundary.tsx +0 -82
  156. package/src/ui/components/common/ExitMessage.tsx +0 -120
  157. package/src/ui/components/common/LoadingIndicator.tsx +0 -49
  158. package/src/ui/components/common/index.ts +0 -6
  159. package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
  160. package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
  161. package/src/ui/components/dialog/SetupWizard.tsx +0 -297
  162. package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
  163. package/src/ui/components/dialog/index.ts +0 -8
  164. package/src/ui/components/index.ts +0 -28
  165. package/src/ui/components/input/CommandSuggestions.tsx +0 -139
  166. package/src/ui/components/input/CustomTextInput.tsx +0 -220
  167. package/src/ui/components/input/InputArea.tsx +0 -361
  168. package/src/ui/components/input/PromptSuggestions.tsx +0 -66
  169. package/src/ui/components/input/index.ts +0 -6
  170. package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
  171. package/src/ui/components/layout/ContextBar.tsx +0 -79
  172. package/src/ui/components/layout/MessageArea.tsx +0 -96
  173. package/src/ui/components/layout/MessageList.tsx +0 -647
  174. package/src/ui/components/layout/MessageSeparator.tsx +0 -26
  175. package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
  176. package/src/ui/components/layout/index.ts +0 -7
  177. package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
  178. package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
  179. package/src/ui/components/markdown/index.ts +0 -8
  180. package/src/ui/components/markdown/parser.ts +0 -336
  181. package/src/ui/components/markdown/types.ts +0 -66
  182. package/src/ui/focus/FocusManager.ts +0 -137
  183. package/src/ui/focus/index.ts +0 -13
  184. package/src/ui/focus/types.ts +0 -54
  185. package/src/ui/focus/useFocus.ts +0 -75
  186. package/src/ui/hooks/index.ts +0 -11
  187. package/src/ui/hooks/useAgent.ts +0 -284
  188. package/src/ui/hooks/useCommandHistory.ts +0 -87
  189. package/src/ui/hooks/useCommandProcessor.ts +0 -443
  190. package/src/ui/hooks/useConfirmation.ts +0 -99
  191. package/src/ui/hooks/useCtrlCHandler.ts +0 -100
  192. package/src/ui/hooks/useInputBuffer.ts +0 -122
  193. package/src/ui/hooks/useTerminalSize.ts +0 -68
  194. package/src/ui/hooks/useTerminalWidth.ts +0 -5
  195. package/src/ui/hooks/useWindowedList.ts +0 -118
  196. package/src/ui/render-debugger.ts +0 -621
  197. package/src/ui/test.ts +0 -189
  198. package/src/ui/themes/ThemeManager.ts +0 -332
  199. package/src/ui/themes/aegisTheme.ts +0 -87
  200. package/src/ui/themes/darkTheme.ts +0 -87
  201. package/src/ui/themes/defaultTheme.ts +0 -85
  202. package/src/ui/themes/index.ts +0 -10
  203. package/src/ui/themes/lightTheme.ts +0 -89
  204. package/src/ui/themes/popularThemes.ts +0 -187
  205. package/src/ui/themes/types.ts +0 -130
  206. package/src/utils/clipboard.ts +0 -48
  207. package/src/utils/debug.ts +0 -43
  208. package/src/utils/environment.ts +0 -68
  209. package/src/utils/index.ts +0 -10
@@ -1,413 +0,0 @@
1
- /**
2
- * /build — Parallel multi-model app builder
3
- *
4
- * Decomposes a task into components, assigns each to the best available model,
5
- * builds everything in parallel, then synthesizes results.
6
- *
7
- * Phases:
8
- * 1. Plan — primary model produces a JSON component tree
9
- * 2. Build — all components run in parallel (different models per role)
10
- * 3. Sync — primary model synthesizes and reports what was written
11
- */
12
-
13
- import { OrchestratorAgent, type SubAgentConfig } from '../agent/orchestrator/OrchestratorAgent.js';
14
- import { requireModelConfig, buildSourceContext } from '../agent/orchestrator/utils.js';
15
- import { PermissionMode } from '../tools/index.js';
16
- import { createChatService } from '../services/ChatService.js';
17
- import type { SlashCommand, SlashCommandResult, SlashCommandContext } from './types.js';
18
-
19
- // ── Colors ────────────────────────────────────────────────────────
20
- const C = {
21
- cyan: '\x1b[38;2;0;229;192m',
22
- purple: '\x1b[38;2;124;111;212m',
23
- orange: '\x1b[38;2;249;115;22m',
24
- green: '\x1b[38;2;34;197;94m',
25
- red: '\x1b[38;2;239;68;68m',
26
- muted: '\x1b[38;2;68;64;90m',
27
- bold: '\x1b[1m',
28
- reset: '\x1b[0m',
29
- };
30
-
31
- // ── Model picker ──────────────────────────────────────────────────
32
-
33
- interface ModelCfg {
34
- model: string;
35
- baseURL?: string;
36
- apiKey: string;
37
- label: string;
38
- }
39
-
40
- function resolveAvailableModels(): Record<string, ModelCfg> {
41
- const primary = requireModelConfig();
42
- const models: Record<string, ModelCfg> = {
43
- primary: { model: primary.model, baseURL: primary.baseURL, apiKey: primary.apiKey, label: primary.model },
44
- };
45
-
46
- if (process.env.DEEPSEEK_API_KEY) {
47
- models.deepseek = {
48
- model: 'deepseek-chat',
49
- baseURL: 'https://api.deepseek.com/v1',
50
- apiKey: process.env.DEEPSEEK_API_KEY,
51
- label: 'DeepSeek',
52
- };
53
- }
54
- if (process.env.GROQ_API_KEY) {
55
- models.groq = {
56
- model: 'llama-3.3-70b-versatile',
57
- baseURL: 'https://api.groq.com/openai/v1',
58
- apiKey: process.env.GROQ_API_KEY,
59
- label: 'Llama-3.3 (Groq)',
60
- };
61
- }
62
- if (process.env.OPENAI_API_KEY) {
63
- models.openai = {
64
- model: process.env.OPENAI_MODEL || 'gpt-4o',
65
- baseURL: process.env.OPENAI_BASE_URL || 'https://api.openai.com/v1',
66
- apiKey: process.env.OPENAI_API_KEY,
67
- label: process.env.OPENAI_MODEL || 'GPT-4o',
68
- };
69
- }
70
-
71
- return models;
72
- }
73
-
74
- /**
75
- * Assign the best available model to a role.
76
- * Falls back to primary if a specific model isn't available.
77
- */
78
- function pickModel(role: string, available: Record<string, ModelCfg>): ModelCfg {
79
- // Logic-heavy / algorithm → DeepSeek
80
- if (/backend|api|database|algorithm|logic/i.test(role) && available.deepseek)
81
- return available.deepseek;
82
-
83
- // UI / frontend → OpenAI
84
- if (/frontend|ui|interface|style|css|html/i.test(role) && available.openai)
85
- return available.openai;
86
-
87
- // Tests / docs → Groq (fast)
88
- if (/test|spec|doc|readme/i.test(role) && available.groq)
89
- return available.groq;
90
-
91
- return available.primary;
92
- }
93
-
94
- // ── Plan types ────────────────────────────────────────────────────
95
-
96
- interface BuildComponent {
97
- name: string; // e.g. "backend"
98
- role: string; // e.g. "Backend Engineer"
99
- description: string; // what to build
100
- files: string[]; // files to create (hints)
101
- modelHint?: string; // preferred model class
102
- }
103
-
104
- interface BuildPlan {
105
- appName: string;
106
- stack: string;
107
- components: BuildComponent[];
108
- entrypoint: string; // e.g. "main.py" or "index.ts"
109
- }
110
-
111
- // ── Planning phase ────────────────────────────────────────────────
112
-
113
- const PLAN_PROMPT = `You are a senior software architect. The user wants to build:
114
-
115
- "{task}"
116
-
117
- Output ONLY valid JSON (no markdown, no explanation) with this exact shape:
118
- {
119
- "appName": "short-kebab-name",
120
- "stack": "one-line tech stack description",
121
- "entrypoint": "main file to run the app",
122
- "components": [
123
- {
124
- "name": "component-id",
125
- "role": "human role title",
126
- "description": "what this component builds — 2-3 sentences, be specific",
127
- "files": ["file1.py", "file2.py"],
128
- "modelHint": "backend|frontend|tests|docs"
129
- }
130
- ]
131
- }
132
-
133
- Rules:
134
- - 3-6 components maximum
135
- - Each component must be independently buildable in parallel
136
- - files[] contains the actual files this agent will write to disk
137
- - modelHint must be one of: backend, frontend, tests, docs, general
138
- - Be opinionated about the stack — choose one clear approach
139
- - Always include a "tests" component
140
- - Always include an "integrator" component (role: "Integration Engineer") that writes the main entrypoint and wires everything together`;
141
-
142
- async function planBuild(task: string): Promise<BuildPlan> {
143
- const cfg = requireModelConfig();
144
- const chat = createChatService({ apiKey: cfg.apiKey, baseURL: cfg.baseURL, model: cfg.model, timeout: 60_000 });
145
-
146
- const response = await chat.chat([
147
- { role: 'user', content: PLAN_PROMPT.replace('{task}', task) },
148
- ]);
149
-
150
- // Strip markdown fences if model added them
151
- let raw = response.content.trim();
152
- raw = raw.replace(/^```(?:json)?\n?/i, '').replace(/\n?```$/i, '').trim();
153
-
154
- try {
155
- return JSON.parse(raw) as BuildPlan;
156
- } catch {
157
- // Fallback: extract JSON block
158
- const match = raw.match(/\{[\s\S]+\}/);
159
- if (match) return JSON.parse(match[0]) as BuildPlan;
160
- throw new Error(`Planner returned invalid JSON:\n${raw.slice(0, 500)}`);
161
- }
162
- }
163
-
164
- // ── Agent system prompts ──────────────────────────────────────────
165
-
166
- function buildSystemPrompt(component: BuildComponent, plan: BuildPlan, cwd: string): string {
167
- const sourceCtx = buildSourceContext(cwd);
168
- const codeContext = sourceCtx
169
- ? `\n\nExisting code in workspace (file tree + structure summaries + git context):\n${sourceCtx}\n\nUse Read / Grep / Glob to examine these before writing — your code must integrate with existing patterns.`
170
- : '';
171
-
172
- return `You are ${component.role} on a team building: ${plan.appName}
173
- Stack: ${plan.stack}
174
- Working directory: ${cwd}
175
-
176
- Your assignment:
177
- ${component.description}
178
-
179
- Files you should write: ${component.files.join(', ')}${codeContext}
180
-
181
- CRITICAL RULES:
182
- 1. Use Write tool to create each file — write complete, production-ready code
183
- 2. Use Read / Grep / Glob to explore existing code before writing
184
- 3. Do NOT write placeholder code — implement fully working logic
185
- 4. Follow the stack: ${plan.stack}
186
- 5. When done, list each file you created with a one-line description
187
-
188
- Other agents are building the rest of the app simultaneously — focus only on your assignment.
189
- The "integrator" agent will wire everything together.`;
190
- }
191
-
192
- function integratorSystemPrompt(plan: BuildPlan, components: BuildComponent[], cwd: string): string {
193
- const sourceCtx = buildSourceContext(cwd);
194
- const others = components.filter(c => c.name !== 'integrator');
195
- const codeContext = sourceCtx
196
- ? `\n\nExisting code in workspace (file tree + structure summaries + git context):\n${sourceCtx}\n\nUse Read / Grep / Glob to check existing files before wiring.`
197
- : '';
198
-
199
- return `You are Integration Engineer on a team building: ${plan.appName}
200
- Stack: ${plan.stack}
201
- Working directory: ${cwd}${codeContext}
202
-
203
- Other agents are building:
204
- ${others.map(c => `- ${c.name}: ${c.files.join(', ')}`).join('\n')}
205
-
206
- Your job:
207
- 1. Use Read / Grep / Glob to check what each agent wrote and any existing code
208
- 2. Write the main entrypoint: ${plan.entrypoint}
209
- 3. Write a README.md with: what the app does, how to install, how to run
210
- 4. Fix any import/wiring issues between components
211
- 5. Write a requirements.txt / package.json / go.mod (whichever fits the stack)
212
-
213
- Wait — other agents run in parallel. Assume their files exist as listed above.
214
- Write ${plan.entrypoint} and README.md with correct imports for those files.`;
215
- }
216
-
217
- // ── Build command ─────────────────────────────────────────────────
218
-
219
- export const buildCommand: SlashCommand = {
220
- name: 'build',
221
- aliases: ['forge'],
222
- description: 'Build an app with multiple AI models in parallel — /build <what to build>',
223
- category: 'skills',
224
- usage: '/build <description>',
225
- examples: [
226
- '/build a REST API for a todo app with PostgreSQL',
227
- '/build a CLI tool that summarizes git commits',
228
- '/build a Flask web app with login and dashboard',
229
- ],
230
- fullDescription: `Parallel multi-model app builder.
231
-
232
- Breaks your task into components, assigns each to the best available AI model,
233
- builds everything simultaneously, then synthesizes results.
234
-
235
- Models used based on available API keys:
236
- - Primary model — architecture, integration
237
- - DeepSeek — backend, algorithms (DEEPSEEK_API_KEY)
238
- - GPT-4o — frontend, UI (OPENAI_API_KEY)
239
- - Llama via Groq — tests, docs (GROQ_API_KEY)
240
-
241
- All agents write real files to your current directory.`,
242
-
243
- async handler(args: string, context: SlashCommandContext): Promise<SlashCommandResult> {
244
- const task = args.trim();
245
- if (!task) {
246
- return { success: false, type: 'error', error: 'Usage: /build <what to build>\nExample: /build a REST API for a todo app' };
247
- }
248
-
249
- const cwd = context.cwd || process.cwd();
250
- const output: string[] = [];
251
- // Strip ANSI escape codes for clean markdown rendering in streaming buffer
252
- const stripAnsi = (s: string) => s.replace(/\x1b\[[0-9;]*m/g, '');
253
- const log = (s: string) => {
254
- output.push(s);
255
- if (context.onContentDelta) {
256
- context.onContentDelta(stripAnsi(s) + '\n');
257
- } else {
258
- process.stdout.write(s + '\n');
259
- }
260
- };
261
-
262
- log(`\n${C.cyan}${C.bold}⬡ AEGIS BUILD${C.reset}`);
263
- log(`${C.muted}Task: ${task}${C.reset}\n`);
264
-
265
- // ── Phase 1: Plan ─────────────────────────────────────────────
266
- log(`${C.muted}[1/3] Planning architecture…${C.reset}`);
267
-
268
- let plan: BuildPlan;
269
- try {
270
- plan = await planBuild(task);
271
- } catch (e: any) {
272
- return { success: false, type: 'error', error: `Planning failed: ${e.message}` };
273
- }
274
-
275
- log(`${C.cyan} App: ${plan.appName}${C.reset}`);
276
- log(`${C.muted} Stack: ${plan.stack}${C.reset}`);
277
- log(`${C.muted} Components: ${plan.components.map(c => c.name).join(', ')}${C.reset}\n`);
278
-
279
- // ── Phase 2: Build ────────────────────────────────────────────
280
- log(`${C.muted}[2/3] Building in parallel…${C.reset}\n`);
281
-
282
- const available = resolveAvailableModels();
283
- const modelNames = Object.entries(available)
284
- .filter(([k]) => k !== 'primary')
285
- .map(([, v]) => v.label);
286
-
287
- if (modelNames.length > 0) {
288
- log(`${C.muted} Models: primary + ${modelNames.join(', ')}${C.reset}\n`);
289
- } else {
290
- log(`${C.muted} Model: ${available.primary.label} (add DEEPSEEK_API_KEY / OPENAI_API_KEY / GROQ_API_KEY for more)${C.reset}\n`);
291
- }
292
-
293
- const orchestrator = new OrchestratorAgent(
294
- 'Build-Orchestrator',
295
- `You are the AEGIS Build Orchestrator. Coordinate parallel construction of ${plan.appName}.`,
296
- );
297
-
298
- for (const comp of plan.components) {
299
- const modelCfg = pickModel(comp.modelHint || comp.name, available);
300
- const prompt = comp.name === 'integrator'
301
- ? integratorSystemPrompt(plan, plan.components, cwd)
302
- : buildSystemPrompt(comp, plan, cwd);
303
-
304
- const agentCfg: SubAgentConfig = {
305
- name: comp.name,
306
- role: comp.role,
307
- systemPrompt: prompt,
308
- config: { apiKey: modelCfg.apiKey, baseURL: modelCfg.baseURL, model: modelCfg.model, timeout: 180_000 },
309
- tools: ['Read', 'Write', 'Edit', 'Bash', 'Grep', 'Glob'],
310
- permissionMode: PermissionMode.AUTO_EDIT,
311
- };
312
-
313
- orchestrator.registerAgent(agentCfg);
314
- log(` ${C.cyan}${comp.name}${C.reset} ${C.muted}→ ${modelCfg.label} · ${comp.files.join(', ')}${C.reset}`);
315
- }
316
-
317
- log('');
318
-
319
- // Separate integrator from parallel agents (runs after others)
320
- const parallelComponents = plan.components.filter(c => c.name !== 'integrator');
321
- const integratorComp = plan.components.find(c => c.name === 'integrator');
322
-
323
- // Build sub-tasks for parallel phase
324
- const subTasks: Record<string, string> = {};
325
- for (const comp of parallelComponents) {
326
- subTasks[comp.name] = comp.description;
327
- }
328
-
329
- let parallelResponses: any[] = [];
330
- try {
331
- parallelResponses = await orchestrator.delegateParallel(
332
- parallelComponents.map(c => ({ agentName: c.name, task: c.description })),
333
- parallelComponents.length,
334
- );
335
- } catch (e: any) {
336
- return { success: false, type: 'error', error: `Build phase failed: ${e.message}` };
337
- }
338
-
339
- // Log agent results
340
- for (const res of parallelResponses) {
341
- const ok = !res.content.startsWith('[Error') && !res.content.startsWith('[Fatal');
342
- const icon = ok ? `${C.green}✓${C.reset}` : `${C.red}✖${C.reset}`;
343
- log(`${icon} ${C.cyan}${res.agentName}${C.reset} ${C.muted}(${Math.round((res.metadata?.durationMs || 0) / 1000)}s)${C.reset}`);
344
- }
345
-
346
- // Run integrator after parallel phase
347
- if (integratorComp) {
348
- log(`\n${C.muted} Wiring components…${C.reset}`);
349
- try {
350
- const intRes = await orchestrator.delegate('integrator', integratorComp.description);
351
- const ok = !intRes.content.startsWith('[Error') && !intRes.content.startsWith('[Fatal');
352
- const icon = ok ? `${C.green}✓${C.reset}` : `${C.red}✖${C.reset}`;
353
- log(`${icon} ${C.cyan}integrator${C.reset} ${C.muted}(${Math.round((intRes.metadata?.durationMs || 0) / 1000)}s)${C.reset}`);
354
- parallelResponses.push(intRes);
355
- } catch (e: any) {
356
- log(`${C.red}✖ integrator failed: ${e.message}${C.reset}`);
357
- }
358
- }
359
-
360
- // ── Phase 3: Synthesis ────────────────────────────────────────
361
- log(`\n${C.muted}[3/3] Synthesizing…${C.reset}\n`);
362
-
363
- const agentSummaries = parallelResponses
364
- .map(r => `[${r.agentName}]:\n${(r.content || '').slice(0, 600)}`)
365
- .join('\n\n---\n\n');
366
-
367
- const cfg = requireModelConfig();
368
- const chat = createChatService({ apiKey: cfg.apiKey, baseURL: cfg.baseURL, model: cfg.model, timeout: 60_000 });
369
-
370
- let synthesis = '';
371
- try {
372
- const synRes = await chat.chat([{
373
- role: 'user',
374
- content: `You coordinated building: ${plan.appName} (${plan.stack})
375
-
376
- Agent reports:
377
- ${agentSummaries}
378
-
379
- Produce a concise build summary:
380
- 1. Files written (list each with one-line description)
381
- 2. How to run the app
382
- 3. Any issues to fix manually
383
-
384
- Be concrete. No fluff.`,
385
- }]);
386
- synthesis = synRes.content;
387
- } catch {
388
- synthesis = parallelResponses.map(r => `**${r.agentName}**: ${(r.content || '').slice(0, 200)}`).join('\n\n');
389
- }
390
-
391
- const errorCount = parallelResponses.filter(
392
- r => r.content?.startsWith('[Error') || r.content?.startsWith('[Fatal'),
393
- ).length;
394
-
395
- const totalMs = parallelResponses.reduce((s, r) => s + (r.metadata?.durationMs || 0), 0);
396
-
397
- const summaryText = [
398
- `## ⬡ Build: ${plan.appName}`,
399
- `**Stack:** ${plan.stack}`,
400
- `**Run:** \`${plan.entrypoint}\``,
401
- '',
402
- synthesis,
403
- '',
404
- `---`,
405
- `*${parallelResponses.length} agents · ${Math.round(totalMs / 1000)}s${errorCount > 0 ? ` · ⚠ ${errorCount} agent(s) had errors` : ' · all clean'}*`,
406
- ].join('\n');
407
-
408
- log(`\n${summaryText}`);
409
- log(`\n\n✅ **Build complete!**\n`);
410
-
411
- return { success: true, type: 'silent' };
412
- },
413
- };