aegiscode 3.1.10 → 3.4.2
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/bin/aegis.js +165 -0
- package/package.json +18 -86
- package/LICENSE +0 -21
- package/README.md +0 -394
- package/dist/main.js +0 -2171
- package/gui/run-gui.cjs +0 -13
- package/src/agent/Agent.ts +0 -903
- package/src/agent/SimpleAgent.ts +0 -48
- package/src/agent/index.ts +0 -54
- package/src/agent/orchestrator/AppBuilder.ts +0 -443
- package/src/agent/orchestrator/CouncilAgent.ts +0 -310
- package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
- package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
- package/src/agent/orchestrator/index.ts +0 -38
- package/src/agent/orchestrator/utils.ts +0 -397
- package/src/agent/pricing.ts +0 -115
- package/src/agent/router.ts +0 -74
- package/src/agent/routerStats.ts +0 -121
- package/src/agent/types.ts +0 -318
- package/src/auth/login.ts +0 -383
- package/src/cli/config.ts +0 -189
- package/src/cli/index.ts +0 -17
- package/src/cli/middleware.ts +0 -119
- package/src/cli/types.ts +0 -75
- package/src/config/ConfigManager.ts +0 -587
- package/src/config/index.ts +0 -7
- package/src/config/types.ts +0 -584
- package/src/context/CompactionService.ts +0 -300
- package/src/context/ContextManager.ts +0 -450
- package/src/context/FileAnalyzer.ts +0 -267
- package/src/context/TokenCounter.ts +0 -265
- package/src/context/index.ts +0 -27
- package/src/context/storage/CacheStore.ts +0 -176
- package/src/context/storage/JSONLStore.ts +0 -201
- package/src/context/storage/MemoryStore.ts +0 -205
- package/src/context/storage/PersistentStore.ts +0 -327
- package/src/context/storage/index.ts +0 -9
- package/src/context/storage/pathUtils.ts +0 -114
- package/src/context/test.ts +0 -309
- package/src/context/types.ts +0 -268
- package/src/hooks/HookExecutor.ts +0 -434
- package/src/hooks/HookManager.ts +0 -596
- package/src/hooks/HookService.ts +0 -269
- package/src/hooks/Matcher.ts +0 -157
- package/src/hooks/index.ts +0 -63
- package/src/hooks/types.ts +0 -424
- package/src/main.tsx +0 -596
- package/src/mcp/HealthMonitor.ts +0 -150
- package/src/mcp/McpClient.ts +0 -491
- package/src/mcp/McpRegistry.ts +0 -321
- package/src/mcp/createMcpTool.ts +0 -251
- package/src/mcp/index.ts +0 -15
- package/src/mcp/server.ts +0 -334
- package/src/mcp/test-server.ts +0 -88
- package/src/mcp/test.ts +0 -372
- package/src/mcp/types.ts +0 -247
- package/src/memory/AgentMemoryBus.ts +0 -432
- package/src/memory/CloudSync.ts +0 -99
- package/src/memory/DriveSync.ts +0 -106
- package/src/memory/SharedMemory.ts +0 -951
- package/src/memory/index.ts +0 -14
- package/src/memory/machineFingerprint.ts +0 -40
- package/src/orchestrator/SubAgentMetadata.ts +0 -136
- package/src/prompts/builder.ts +0 -213
- package/src/prompts/default.ts +0 -144
- package/src/prompts/index.ts +0 -16
- package/src/prompts/plan.ts +0 -64
- package/src/prompts/test.ts +0 -78
- package/src/services/AnthropicChatService.ts +0 -341
- package/src/services/ChatService.ts +0 -347
- package/src/services/ClaudeCliChatService.ts +0 -256
- package/src/services/CloudSync.ts +0 -168
- package/src/services/CostLedger.ts +0 -211
- package/src/services/Heartbeat.ts +0 -135
- package/src/services/LearningCollector.ts +0 -291
- package/src/services/OllamaInstaller.ts +0 -342
- package/src/services/VersionChecker.ts +0 -445
- package/src/services/index.ts +0 -57
- package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
- package/src/services/streaming/RenderingProfile.ts +0 -90
- package/src/services/streaming/StreamEventParser.ts +0 -181
- package/src/services/streaming/ThrottledRenderer.ts +0 -139
- package/src/services/streaming/TranscriptBuffer.ts +0 -574
- package/src/services/streaming/eventStatusMap.ts +0 -52
- package/src/services/streaming/index.ts +0 -46
- package/src/services/streaming/renderFormatting.ts +0 -79
- package/src/services/streaming/types.ts +0 -234
- package/src/skills/SkillLoader.ts +0 -126
- package/src/skills/SkillRegistry.ts +0 -366
- package/src/skills/index.ts +0 -48
- package/src/skills/types.ts +0 -146
- package/src/slash-commands/billing.ts +0 -70
- package/src/slash-commands/build.ts +0 -413
- package/src/slash-commands/builtinCommands.ts +0 -2733
- package/src/slash-commands/clone.ts +0 -242
- package/src/slash-commands/council.ts +0 -125
- package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
- package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
- package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
- package/src/slash-commands/custom/index.ts +0 -7
- package/src/slash-commands/debate.ts +0 -254
- package/src/slash-commands/gmail.ts +0 -105
- package/src/slash-commands/index.ts +0 -388
- package/src/slash-commands/mcpCommand.ts +0 -205
- package/src/slash-commands/types.ts +0 -201
- package/src/store/index.ts +0 -76
- package/src/store/selectors.ts +0 -246
- package/src/store/slices/appSlice.ts +0 -205
- package/src/store/slices/commandSlice.ts +0 -115
- package/src/store/slices/configSlice.ts +0 -46
- package/src/store/slices/focusSlice.ts +0 -64
- package/src/store/slices/index.ts +0 -9
- package/src/store/slices/sessionSlice.ts +0 -424
- package/src/store/streaming-buffer.ts +0 -425
- package/src/store/test.ts +0 -296
- package/src/store/types.ts +0 -274
- package/src/store/vanilla.ts +0 -186
- package/src/tools/builtin/bash.ts +0 -236
- package/src/tools/builtin/council.ts +0 -105
- package/src/tools/builtin/edit.ts +0 -213
- package/src/tools/builtin/glob.ts +0 -136
- package/src/tools/builtin/grep.ts +0 -263
- package/src/tools/builtin/index.ts +0 -61
- package/src/tools/builtin/memory.ts +0 -66
- package/src/tools/builtin/read.ts +0 -168
- package/src/tools/builtin/skill.ts +0 -97
- package/src/tools/builtin/snapshot.ts +0 -40
- package/src/tools/builtin/task.ts +0 -106
- package/src/tools/builtin/write.ts +0 -134
- package/src/tools/createTool.ts +0 -221
- package/src/tools/execution/ExecutionPipeline.ts +0 -263
- package/src/tools/execution/index.ts +0 -40
- package/src/tools/execution/stages/CacheStage.ts +0 -131
- package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
- package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
- package/src/tools/execution/stages/ExecutionStage.ts +0 -48
- package/src/tools/execution/stages/FormattingStage.ts +0 -44
- package/src/tools/execution/stages/HookStage.ts +0 -72
- package/src/tools/execution/stages/PermissionStage.ts +0 -287
- package/src/tools/execution/stages/PostHookStage.ts +0 -71
- package/src/tools/execution/stages/index.ts +0 -12
- package/src/tools/execution/test.ts +0 -266
- package/src/tools/execution/types.ts +0 -273
- package/src/tools/index.ts +0 -81
- package/src/tools/registry.ts +0 -304
- package/src/tools/schemas.ts +0 -109
- package/src/tools/test.ts +0 -220
- package/src/tools/types.ts +0 -175
- package/src/tools/validation/PermissionChecker.ts +0 -242
- package/src/tools/validation/SensitiveFileDetector.ts +0 -210
- package/src/tools/validation/index.ts +0 -11
- package/src/ui/App.tsx +0 -166
- package/src/ui/components/AegisInterface.tsx +0 -484
- package/src/ui/components/common/ChatSearch.tsx +0 -150
- package/src/ui/components/common/ErrorBoundary.tsx +0 -82
- package/src/ui/components/common/ExitMessage.tsx +0 -120
- package/src/ui/components/common/LoadingIndicator.tsx +0 -49
- package/src/ui/components/common/index.ts +0 -6
- package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
- package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
- package/src/ui/components/dialog/SetupWizard.tsx +0 -297
- package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
- package/src/ui/components/dialog/index.ts +0 -8
- package/src/ui/components/index.ts +0 -28
- package/src/ui/components/input/CommandSuggestions.tsx +0 -139
- package/src/ui/components/input/CustomTextInput.tsx +0 -220
- package/src/ui/components/input/InputArea.tsx +0 -361
- package/src/ui/components/input/PromptSuggestions.tsx +0 -66
- package/src/ui/components/input/index.ts +0 -6
- package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
- package/src/ui/components/layout/ContextBar.tsx +0 -79
- package/src/ui/components/layout/MessageArea.tsx +0 -96
- package/src/ui/components/layout/MessageList.tsx +0 -647
- package/src/ui/components/layout/MessageSeparator.tsx +0 -26
- package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
- package/src/ui/components/layout/index.ts +0 -7
- package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
- package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
- package/src/ui/components/markdown/index.ts +0 -8
- package/src/ui/components/markdown/parser.ts +0 -336
- package/src/ui/components/markdown/types.ts +0 -66
- package/src/ui/focus/FocusManager.ts +0 -137
- package/src/ui/focus/index.ts +0 -13
- package/src/ui/focus/types.ts +0 -54
- package/src/ui/focus/useFocus.ts +0 -75
- package/src/ui/hooks/index.ts +0 -11
- package/src/ui/hooks/useAgent.ts +0 -284
- package/src/ui/hooks/useCommandHistory.ts +0 -87
- package/src/ui/hooks/useCommandProcessor.ts +0 -443
- package/src/ui/hooks/useConfirmation.ts +0 -99
- package/src/ui/hooks/useCtrlCHandler.ts +0 -100
- package/src/ui/hooks/useInputBuffer.ts +0 -122
- package/src/ui/hooks/useTerminalSize.ts +0 -68
- package/src/ui/hooks/useTerminalWidth.ts +0 -5
- package/src/ui/hooks/useWindowedList.ts +0 -118
- package/src/ui/render-debugger.ts +0 -621
- package/src/ui/test.ts +0 -189
- package/src/ui/themes/ThemeManager.ts +0 -332
- package/src/ui/themes/aegisTheme.ts +0 -87
- package/src/ui/themes/darkTheme.ts +0 -87
- package/src/ui/themes/defaultTheme.ts +0 -85
- package/src/ui/themes/index.ts +0 -10
- package/src/ui/themes/lightTheme.ts +0 -89
- package/src/ui/themes/popularThemes.ts +0 -187
- package/src/ui/themes/types.ts +0 -130
- package/src/utils/clipboard.ts +0 -48
- package/src/utils/debug.ts +0 -43
- package/src/utils/environment.ts +0 -68
- 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
|
-
};
|