aegiscode 3.1.8 → 3.1.10

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 (206) hide show
  1. package/README.md +23 -15
  2. package/dist/main.js +549 -552
  3. package/package.json +4 -2
  4. package/src/agent/Agent.ts +903 -0
  5. package/src/agent/SimpleAgent.ts +48 -0
  6. package/src/agent/index.ts +54 -0
  7. package/src/agent/orchestrator/AppBuilder.ts +443 -0
  8. package/src/agent/orchestrator/CouncilAgent.ts +310 -0
  9. package/src/agent/orchestrator/DiscussionRoom.ts +462 -0
  10. package/src/agent/orchestrator/OrchestratorAgent.ts +637 -0
  11. package/src/agent/orchestrator/index.ts +38 -0
  12. package/src/agent/orchestrator/utils.ts +397 -0
  13. package/src/agent/pricing.ts +115 -0
  14. package/src/agent/router.ts +74 -0
  15. package/src/agent/routerStats.ts +121 -0
  16. package/src/agent/types.ts +318 -0
  17. package/src/auth/login.ts +383 -0
  18. package/src/cli/config.ts +189 -0
  19. package/src/cli/index.ts +17 -0
  20. package/src/cli/middleware.ts +119 -0
  21. package/src/cli/types.ts +75 -0
  22. package/src/config/ConfigManager.ts +587 -0
  23. package/src/config/index.ts +7 -0
  24. package/src/config/types.ts +584 -0
  25. package/src/context/CompactionService.ts +300 -0
  26. package/src/context/ContextManager.ts +450 -0
  27. package/src/context/FileAnalyzer.ts +267 -0
  28. package/src/context/TokenCounter.ts +265 -0
  29. package/src/context/index.ts +27 -0
  30. package/src/context/storage/CacheStore.ts +176 -0
  31. package/src/context/storage/JSONLStore.ts +201 -0
  32. package/src/context/storage/MemoryStore.ts +205 -0
  33. package/src/context/storage/PersistentStore.ts +327 -0
  34. package/src/context/storage/index.ts +9 -0
  35. package/src/context/storage/pathUtils.ts +114 -0
  36. package/src/context/test.ts +309 -0
  37. package/src/context/types.ts +268 -0
  38. package/src/hooks/HookExecutor.ts +434 -0
  39. package/src/hooks/HookManager.ts +596 -0
  40. package/src/hooks/HookService.ts +269 -0
  41. package/src/hooks/Matcher.ts +157 -0
  42. package/src/hooks/index.ts +63 -0
  43. package/src/hooks/types.ts +424 -0
  44. package/src/main.tsx +596 -0
  45. package/src/mcp/HealthMonitor.ts +150 -0
  46. package/src/mcp/McpClient.ts +491 -0
  47. package/src/mcp/McpRegistry.ts +321 -0
  48. package/src/mcp/createMcpTool.ts +251 -0
  49. package/src/mcp/index.ts +15 -0
  50. package/src/mcp/server.ts +334 -0
  51. package/src/mcp/test-server.ts +88 -0
  52. package/src/mcp/test.ts +372 -0
  53. package/src/mcp/types.ts +247 -0
  54. package/src/memory/AgentMemoryBus.ts +432 -0
  55. package/src/memory/CloudSync.ts +99 -0
  56. package/src/memory/DriveSync.ts +106 -0
  57. package/src/memory/SharedMemory.ts +951 -0
  58. package/src/memory/index.ts +14 -0
  59. package/src/memory/machineFingerprint.ts +40 -0
  60. package/src/orchestrator/SubAgentMetadata.ts +136 -0
  61. package/src/prompts/builder.ts +213 -0
  62. package/src/prompts/default.ts +144 -0
  63. package/src/prompts/index.ts +16 -0
  64. package/src/prompts/plan.ts +64 -0
  65. package/src/prompts/test.ts +78 -0
  66. package/src/services/AnthropicChatService.ts +341 -0
  67. package/src/services/ChatService.ts +347 -0
  68. package/src/services/ClaudeCliChatService.ts +256 -0
  69. package/src/services/CloudSync.ts +168 -0
  70. package/src/services/CostLedger.ts +211 -0
  71. package/src/services/Heartbeat.ts +135 -0
  72. package/src/services/LearningCollector.ts +291 -0
  73. package/src/services/OllamaInstaller.ts +342 -0
  74. package/src/services/VersionChecker.ts +445 -0
  75. package/src/services/index.ts +57 -0
  76. package/src/services/streaming/OpenAIEventAdapter.ts +126 -0
  77. package/src/services/streaming/RenderingProfile.ts +90 -0
  78. package/src/services/streaming/StreamEventParser.ts +181 -0
  79. package/src/services/streaming/ThrottledRenderer.ts +139 -0
  80. package/src/services/streaming/TranscriptBuffer.ts +574 -0
  81. package/src/services/streaming/eventStatusMap.ts +52 -0
  82. package/src/services/streaming/index.ts +46 -0
  83. package/src/services/streaming/renderFormatting.ts +79 -0
  84. package/src/services/streaming/types.ts +234 -0
  85. package/src/skills/SkillLoader.ts +126 -0
  86. package/src/skills/SkillRegistry.ts +366 -0
  87. package/src/skills/index.ts +48 -0
  88. package/src/skills/types.ts +146 -0
  89. package/src/slash-commands/billing.ts +70 -0
  90. package/src/slash-commands/build.ts +413 -0
  91. package/src/slash-commands/builtinCommands.ts +2733 -0
  92. package/src/slash-commands/clone.ts +242 -0
  93. package/src/slash-commands/council.ts +125 -0
  94. package/src/slash-commands/custom/CustomCommandExecutor.ts +143 -0
  95. package/src/slash-commands/custom/CustomCommandLoader.ts +251 -0
  96. package/src/slash-commands/custom/CustomCommandRegistry.ts +144 -0
  97. package/src/slash-commands/custom/index.ts +7 -0
  98. package/src/slash-commands/debate.ts +254 -0
  99. package/src/slash-commands/gmail.ts +105 -0
  100. package/src/slash-commands/index.ts +388 -0
  101. package/src/slash-commands/mcpCommand.ts +205 -0
  102. package/src/slash-commands/types.ts +201 -0
  103. package/src/store/index.ts +76 -0
  104. package/src/store/selectors.ts +246 -0
  105. package/src/store/slices/appSlice.ts +205 -0
  106. package/src/store/slices/commandSlice.ts +115 -0
  107. package/src/store/slices/configSlice.ts +46 -0
  108. package/src/store/slices/focusSlice.ts +64 -0
  109. package/src/store/slices/index.ts +9 -0
  110. package/src/store/slices/sessionSlice.ts +424 -0
  111. package/src/store/streaming-buffer.ts +425 -0
  112. package/src/store/test.ts +296 -0
  113. package/src/store/types.ts +274 -0
  114. package/src/store/vanilla.ts +186 -0
  115. package/src/tools/builtin/bash.ts +236 -0
  116. package/src/tools/builtin/council.ts +105 -0
  117. package/src/tools/builtin/edit.ts +213 -0
  118. package/src/tools/builtin/glob.ts +136 -0
  119. package/src/tools/builtin/grep.ts +263 -0
  120. package/src/tools/builtin/index.ts +61 -0
  121. package/src/tools/builtin/memory.ts +66 -0
  122. package/src/tools/builtin/read.ts +168 -0
  123. package/src/tools/builtin/skill.ts +97 -0
  124. package/src/tools/builtin/snapshot.ts +40 -0
  125. package/src/tools/builtin/task.ts +106 -0
  126. package/src/tools/builtin/write.ts +134 -0
  127. package/src/tools/createTool.ts +221 -0
  128. package/src/tools/execution/ExecutionPipeline.ts +263 -0
  129. package/src/tools/execution/index.ts +40 -0
  130. package/src/tools/execution/stages/CacheStage.ts +131 -0
  131. package/src/tools/execution/stages/ConfirmationStage.ts +203 -0
  132. package/src/tools/execution/stages/DiscoveryStage.ts +46 -0
  133. package/src/tools/execution/stages/ExecutionStage.ts +48 -0
  134. package/src/tools/execution/stages/FormattingStage.ts +44 -0
  135. package/src/tools/execution/stages/HookStage.ts +72 -0
  136. package/src/tools/execution/stages/PermissionStage.ts +287 -0
  137. package/src/tools/execution/stages/PostHookStage.ts +71 -0
  138. package/src/tools/execution/stages/index.ts +12 -0
  139. package/src/tools/execution/test.ts +266 -0
  140. package/src/tools/execution/types.ts +273 -0
  141. package/src/tools/index.ts +81 -0
  142. package/src/tools/registry.ts +304 -0
  143. package/src/tools/schemas.ts +109 -0
  144. package/src/tools/test.ts +220 -0
  145. package/src/tools/types.ts +175 -0
  146. package/src/tools/validation/PermissionChecker.ts +242 -0
  147. package/src/tools/validation/SensitiveFileDetector.ts +210 -0
  148. package/src/tools/validation/index.ts +11 -0
  149. package/src/ui/App.tsx +166 -0
  150. package/src/ui/components/AegisInterface.tsx +484 -0
  151. package/src/ui/components/common/ChatSearch.tsx +150 -0
  152. package/src/ui/components/common/ErrorBoundary.tsx +82 -0
  153. package/src/ui/components/common/ExitMessage.tsx +120 -0
  154. package/src/ui/components/common/LoadingIndicator.tsx +49 -0
  155. package/src/ui/components/common/index.ts +6 -0
  156. package/src/ui/components/dialog/ConfirmationPrompt.tsx +208 -0
  157. package/src/ui/components/dialog/InteractiveSelector.tsx +149 -0
  158. package/src/ui/components/dialog/SetupWizard.tsx +297 -0
  159. package/src/ui/components/dialog/UpdatePrompt.tsx +155 -0
  160. package/src/ui/components/dialog/index.ts +8 -0
  161. package/src/ui/components/index.ts +28 -0
  162. package/src/ui/components/input/CommandSuggestions.tsx +139 -0
  163. package/src/ui/components/input/CustomTextInput.tsx +220 -0
  164. package/src/ui/components/input/InputArea.tsx +361 -0
  165. package/src/ui/components/input/PromptSuggestions.tsx +66 -0
  166. package/src/ui/components/input/index.ts +6 -0
  167. package/src/ui/components/layout/ChatStatusBar.tsx +90 -0
  168. package/src/ui/components/layout/ContextBar.tsx +79 -0
  169. package/src/ui/components/layout/MessageArea.tsx +96 -0
  170. package/src/ui/components/layout/MessageList.tsx +647 -0
  171. package/src/ui/components/layout/MessageSeparator.tsx +26 -0
  172. package/src/ui/components/layout/WelcomeMessage.tsx +93 -0
  173. package/src/ui/components/layout/index.ts +7 -0
  174. package/src/ui/components/markdown/CodeHighlighter.tsx +292 -0
  175. package/src/ui/components/markdown/MessageRenderer.tsx +1211 -0
  176. package/src/ui/components/markdown/index.ts +8 -0
  177. package/src/ui/components/markdown/parser.ts +336 -0
  178. package/src/ui/components/markdown/types.ts +66 -0
  179. package/src/ui/focus/FocusManager.ts +137 -0
  180. package/src/ui/focus/index.ts +13 -0
  181. package/src/ui/focus/types.ts +54 -0
  182. package/src/ui/focus/useFocus.ts +75 -0
  183. package/src/ui/hooks/index.ts +11 -0
  184. package/src/ui/hooks/useAgent.ts +284 -0
  185. package/src/ui/hooks/useCommandHistory.ts +87 -0
  186. package/src/ui/hooks/useCommandProcessor.ts +443 -0
  187. package/src/ui/hooks/useConfirmation.ts +99 -0
  188. package/src/ui/hooks/useCtrlCHandler.ts +100 -0
  189. package/src/ui/hooks/useInputBuffer.ts +122 -0
  190. package/src/ui/hooks/useTerminalSize.ts +68 -0
  191. package/src/ui/hooks/useTerminalWidth.ts +5 -0
  192. package/src/ui/hooks/useWindowedList.ts +118 -0
  193. package/src/ui/render-debugger.ts +621 -0
  194. package/src/ui/test.ts +189 -0
  195. package/src/ui/themes/ThemeManager.ts +332 -0
  196. package/src/ui/themes/aegisTheme.ts +87 -0
  197. package/src/ui/themes/darkTheme.ts +87 -0
  198. package/src/ui/themes/defaultTheme.ts +85 -0
  199. package/src/ui/themes/index.ts +10 -0
  200. package/src/ui/themes/lightTheme.ts +89 -0
  201. package/src/ui/themes/popularThemes.ts +187 -0
  202. package/src/ui/themes/types.ts +130 -0
  203. package/src/utils/clipboard.ts +48 -0
  204. package/src/utils/debug.ts +43 -0
  205. package/src/utils/environment.ts +68 -0
  206. package/src/utils/index.ts +10 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * SimpleAgent - 最简单的 LLM 交互实现
3
+ *
4
+ *
5
+ *
6
+ */
7
+
8
+ import OpenAI from 'openai';
9
+
10
+ export interface AgentConfig {
11
+ apiKey: string;
12
+ baseURL?: string;
13
+ model?: string;
14
+ }
15
+
16
+ export class SimpleAgent {
17
+ private client: OpenAI;
18
+ private model: string;
19
+
20
+ constructor(config: AgentConfig) {
21
+ this.client = new OpenAI({
22
+ apiKey: config.apiKey,
23
+ baseURL: config.baseURL,
24
+ });
25
+ this.model = config.model || 'claude-sonnet-4-6';
26
+ }
27
+
28
+ /**
29
+ *
30
+ */
31
+ async chat(message: string): Promise<string> {
32
+ const response = await this.client.chat.completions.create({
33
+ model: this.model,
34
+ messages: [
35
+ {
36
+ role: 'system',
37
+ content: 'You are a helpful coding assistant. Be concise and helpful.',
38
+ },
39
+ {
40
+ role: 'user',
41
+ content: message,
42
+ },
43
+ ],
44
+ });
45
+
46
+ return response.choices[0]?.message?.content || '';
47
+ }
48
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Agent
3
+ */
4
+
5
+ export { Agent, default as AgentDefault } from './Agent.js';
6
+ export { SimpleAgent } from './SimpleAgent.js';
7
+
8
+ // Orchestrator (Multi-agent)
9
+ export {
10
+ OrchestratorAgent,
11
+ createDefaultOrchestrator,
12
+ CouncilAgent,
13
+ } from './orchestrator/index.js';
14
+
15
+ export type {
16
+ SubAgentConfig,
17
+ TaskDelegation,
18
+ AgentResponse,
19
+ OrchestrationResult,
20
+ DeliberationConfig,
21
+ DeliberationResult,
22
+ VoteResult,
23
+ VoteValue,
24
+ } from './orchestrator/index.js';
25
+
26
+ export type {
27
+ //
28
+ Message,
29
+ MessageRole,
30
+ ToolCall,
31
+
32
+ //
33
+ ChatContext,
34
+ PermissionMode,
35
+ ConfirmationHandler,
36
+
37
+ //
38
+ LoopOptions,
39
+ LoopResult,
40
+ LoopError,
41
+ LoopErrorType,
42
+
43
+ //
44
+ ToolResult,
45
+ ToolDefinition,
46
+
47
+ //
48
+ AgentConfig,
49
+ AgentOptions,
50
+
51
+ // ChatService
52
+ ChatResponse,
53
+ IChatService,
54
+ } from './types.js';
@@ -0,0 +1,443 @@
1
+ /**
2
+ * AppBuilder — Declarative multi-agent app framework
3
+ *
4
+ * Makes it trivial to build new CLI "apps" that orchestrate multiple AI agents.
5
+ *
6
+ * Usage:
7
+ * ```ts
8
+ * const auditApp = new AppBuilder('audit', 'Security Auditor')
9
+ * .describe('Audit codebase for security vulnerabilities')
10
+ * .agent('scanner', 'Vulnerability Scanner', scannerPrompt, ['Read', 'Grep', 'Glob'])
11
+ * .agent('analyzer', 'Risk Analyzer', analyzerPrompt, ['Read'])
12
+ * .agent('reporter', 'Report Generator', reporterPrompt)
13
+ * .register();
14
+ * ```
15
+ */
16
+
17
+ import type { AgentConfig, Message } from '../types.js';
18
+ import { OrchestratorAgent, type SubAgentConfig } from './OrchestratorAgent.js';
19
+ import { requireModelConfig, type ResolvedModelConfig } from './utils.js';
20
+ import { configManager } from '../../config/ConfigManager.js';
21
+
22
+ // ─── Types ────────────────────────────────────────────────────────
23
+
24
+ export interface AppDefinition {
25
+ /** Unique app ID (used to reference in slash commands) */
26
+ id: string;
27
+ /** Human-readable app name */
28
+ name: string;
29
+ /** Short description (shown in /help) */
30
+ description: string;
31
+ /** Detailed usage instructions */
32
+ usage?: string;
33
+ /** Example usages */
34
+ examples?: string[];
35
+ /** Model config (resolved lazily at run time) */
36
+ modelConfig: () => ResolvedModelConfig;
37
+ /** Sub-agent configurations */
38
+ agents: SubAgentConfig[];
39
+ /** Synthesizer agent name (defaults to first registered) */
40
+ synthesizer?: string;
41
+ /** Max parallel agent executions */
42
+ concurrency?: number;
43
+ }
44
+
45
+ export interface AppRunOptions {
46
+ /** The user's high-level task */
47
+ task: string;
48
+ /** Optional sub-task overrides (agentName → custom task) */
49
+ subTasks?: Record<string, string>;
50
+ /** Session ID for memory context sharing */
51
+ sessionId?: string;
52
+ /** Abort signal */
53
+ signal?: AbortSignal;
54
+ /** Permission mode for tool execution */
55
+ permissionMode?: string;
56
+ /** Confirmation handler for interactive tool approval */
57
+ confirmationHandler?: { requestConfirmation: (details: any) => Promise<any> };
58
+ }
59
+
60
+ export interface AppRunResult {
61
+ /** Per-agent responses */
62
+ responses: Array<{
63
+ agentName: string;
64
+ content: string;
65
+ toolCallsCount?: number;
66
+ durationMs?: number;
67
+ }>;
68
+ /** Synthesized summary */
69
+ summary: string;
70
+ /** Total duration */
71
+ totalDurationMs: number;
72
+ /** Number of agents that reported errors */
73
+ errorCount: number;
74
+ }
75
+
76
+ // ─── Built-in app prompts ──────────────────────────────────────────
77
+
78
+ const BUILTIN_APP_TEMPLATES: Record<string, {
79
+ name: string;
80
+ description: string;
81
+ subtitle: string;
82
+ agents: Array<{
83
+ name: string;
84
+ role: string;
85
+ prompt: string;
86
+ tools?: string[];
87
+ }>;
88
+ instructions: string;
89
+ }> = {
90
+ audit: {
91
+ name: 'Code Security Auditor',
92
+ description: 'Audit the codebase for security vulnerabilities, hardcoded secrets, and unsafe patterns',
93
+ subtitle: 'Security Audit',
94
+ instructions: 'Provide a comprehensive security audit with severity ratings and remediation steps.',
95
+ agents: [
96
+ {
97
+ name: 'scanner',
98
+ role: 'Vulnerability Scanner',
99
+ tools: ['Read', 'Grep', 'Glob'],
100
+ prompt: `You are a Security Vulnerability Scanner.
101
+ Scan the codebase for: hardcoded API keys/secrets, SQL injection, XSS, unsafe eval/exec, path traversal, command injection.
102
+ Use Grep with targeted patterns to find issues. Report every finding with file path, severity (CRITICAL/HIGH/MEDIUM/LOW), and line number.`,
103
+ },
104
+ {
105
+ name: 'analyzer',
106
+ role: 'Risk Analyzer',
107
+ tools: ['Read', 'Grep', 'Glob'],
108
+ prompt: `You are a Security Risk Analyzer.
109
+ Review the dependency/package files, configuration files, and environment setup.
110
+ Check for: outdated packages with known CVEs, misconfigured CORS, permissive file permissions, weak auth.
111
+ Use Read on package.json, tsconfig, Dockerfiles, CI configs. Report risks with actionable fixes.`,
112
+ },
113
+ {
114
+ name: 'reporter',
115
+ role: 'Report Generator',
116
+ prompt: `You are a Security Report Generator. Given the scanner and analyzer findings, produce a final report.
117
+ Structure: Executive Summary, Critical Findings, High, Medium, Low, Recommendations.
118
+ Always include CVE references where applicable. Be concise and actionable.`,
119
+ },
120
+ ],
121
+ },
122
+ refactor: {
123
+ name: 'Code Refactoring Engine',
124
+ description: 'Analyze and refactor code for better structure, performance, and maintainability',
125
+ subtitle: 'Refactoring',
126
+ instructions: 'Execute the refactoring plan. Write the actual code changes.',
127
+ agents: [
128
+ {
129
+ name: 'analyzer',
130
+ role: 'Code Analyzer',
131
+ tools: ['Read', 'Grep', 'Glob'],
132
+ prompt: `You are a Code Analyzer. Analyze the codebase for refactoring opportunities.
133
+ Look for: duplicate code, long functions, complex conditionals, unused imports, circular dependencies, inconsistent patterns.
134
+ Use Grep and Read to find specific examples. Provide file paths and line numbers.`,
135
+ },
136
+ {
137
+ name: 'planner',
138
+ role: 'Refactoring Planner',
139
+ tools: ['Read'],
140
+ prompt: `You are a Refactoring Planner. Given the analyzer findings, create a step-by-step refactoring plan.
141
+ Each step should specify: which file to modify, what to change, why, and the risk level (LOW/MEDIUM/HIGH).
142
+ Order by impact (highest value first). Be concrete — include before/after code snippets.`,
143
+ },
144
+ {
145
+ name: 'implementer',
146
+ role: 'Implementation Engineer',
147
+ tools: ['Read', 'Edit', 'Write', 'Grep'],
148
+ prompt: `You are an Implementation Engineer. Execute the refactoring plan.
149
+ Make the actual code changes using Edit and Write tools.
150
+ After each change, use Read to verify the result. Keep the existing code style.`,
151
+ },
152
+ ],
153
+ },
154
+ 'test-gen': {
155
+ name: 'Test Generator',
156
+ description: 'Generate comprehensive test suites for your code',
157
+ subtitle: 'Test Generation',
158
+ instructions: 'Generate the test files. Use existing test patterns in the project.',
159
+ agents: [
160
+ {
161
+ name: 'explorer',
162
+ role: 'Code Explorer',
163
+ tools: ['Read', 'Grep', 'Glob'],
164
+ prompt: `You are a Code Explorer. Find testable units in the codebase.
165
+ For each module: list exported functions/classes, their parameters, return types, and side effects.
166
+ Check for existing test files and test patterns used in the project.
167
+ Report: which test framework is used, where tests live, existing test patterns.`,
168
+ },
169
+ {
170
+ name: 'designer',
171
+ role: 'Test Designer',
172
+ tools: ['Read'],
173
+ prompt: `You are a Test Designer. Given the explorer findings, design test cases.
174
+ For each function/module: describe the happy path, error cases, edge cases, and any setup/teardown needed.
175
+ Prioritize: critical business logic > utilities > edge cases. Be specific about assertions.`,
176
+ },
177
+ {
178
+ name: 'writer',
179
+ role: 'Test Writer',
180
+ tools: ['Read', 'Write', 'Edit', 'Grep'],
181
+ prompt: `You are a Test Writer. Generate the actual test files following the test designer's plan.
182
+ Match the project's existing test patterns (framework, naming, directory structure).
183
+ Write complete, runnable tests. Use Write to create new test files.`,
184
+ },
185
+ ],
186
+ },
187
+ };
188
+
189
+ // ─── AppBuilder ────────────────────────────────────────────────────
190
+
191
+ export class AppBuilder {
192
+ private def: Partial<AppDefinition> = {};
193
+ private agents: SubAgentConfig[] = [];
194
+ private _prompts?: {
195
+ template: string;
196
+ subTaskTemplates: Record<string, string>;
197
+ };
198
+
199
+ constructor(id: string, name: string) {
200
+ this.def.id = id;
201
+ this.def.name = name;
202
+ this.def.modelConfig = requireModelConfig;
203
+ this.def.concurrency = 4;
204
+ }
205
+
206
+ /** Set short description (shown in /help) */
207
+ describe(description: string): this {
208
+ this.def.description = description;
209
+ return this;
210
+ }
211
+
212
+ /** Set usage instructions */
213
+ use(usage: string): this {
214
+ this.def.usage = usage;
215
+ return this;
216
+ }
217
+
218
+ /** Add example usages */
219
+ examples(examples: string[]): this {
220
+ this.def.examples = examples;
221
+ return this;
222
+ }
223
+
224
+ /** Set custom model resolver */
225
+ model(resolver: () => ResolvedModelConfig): this {
226
+ this.def.modelConfig = resolver;
227
+ return this;
228
+ }
229
+
230
+ /** Set max parallelism */
231
+ concurrency(n: number): this {
232
+ this.def.concurrency = n;
233
+ return this;
234
+ }
235
+
236
+ /** Set synthesizer agent name (default: first registered) */
237
+ synthesizer(name: string): this {
238
+ this.def.synthesizer = name;
239
+ return this;
240
+ }
241
+
242
+ /**
243
+ * Register a sub-agent.
244
+ *
245
+ * @param name - Agent identifier (used in delegation)
246
+ * @param role - Human-readable role name
247
+ * @param systemPrompt - System prompt for this agent
248
+ * @param tools - Tool names this agent can use (e.g. ['Read', 'Grep'])
249
+ */
250
+ agent(
251
+ name: string,
252
+ role: string,
253
+ systemPrompt: string,
254
+ tools?: string[],
255
+ ): this {
256
+ this.agents.push({ name, role, systemPrompt, config: {} as AgentConfig, tools });
257
+ return this;
258
+ }
259
+
260
+ /**
261
+ * Load a built-in app template and customize it.
262
+ * Available: 'audit', 'refactor', 'test-gen'
263
+ */
264
+ fromTemplate(templateId: string, overrides?: {
265
+ name?: string;
266
+ description?: string;
267
+ agentPrompts?: Record<string, string>;
268
+ }): this {
269
+ const template = BUILTIN_APP_TEMPLATES[templateId];
270
+ if (!template) {
271
+ throw new Error(`Unknown app template: "${templateId}". Available: ${Object.keys(BUILTIN_APP_TEMPLATES).join(', ')}`);
272
+ }
273
+
274
+ this.def.name = overrides?.name || template.name;
275
+ this.def.description = overrides?.description || template.description;
276
+ this.def.usage = `/${this.def.id || templateId} <task>`;
277
+ this.def.examples = [
278
+ `/${this.def.id || templateId} Audit the login module`,
279
+ `/${this.def.id || templateId} Check package.json for vulnerabilities`,
280
+ ];
281
+
282
+ this._prompts = {
283
+ template: templateId,
284
+ subTaskTemplates: {},
285
+ };
286
+
287
+ for (const agent of template.agents) {
288
+ const userPrompt = overrides?.agentPrompts?.[agent.name];
289
+ this.agent(
290
+ agent.name,
291
+ agent.role,
292
+ userPrompt || agent.prompt,
293
+ agent.tools,
294
+ );
295
+ }
296
+
297
+ return this;
298
+ }
299
+
300
+ /**
301
+ * Build and register the app, returning the definition.
302
+ * This also makes the app available via the slash-command system.
303
+ */
304
+ register(): AppDefinition {
305
+ if (!this.def.id) throw new Error('AppBuilder: id is required');
306
+ if (!this.def.description) this.def.description = '';
307
+ if (this.agents.length === 0) throw new Error('AppBuilder: at least one agent required');
308
+
309
+ const definition: AppDefinition = {
310
+ id: this.def.id,
311
+ name: this.def.name || this.def.id,
312
+ description: this.def.description,
313
+ usage: this.def.usage || `/${this.def.id} <task>`,
314
+ examples: this.def.examples || [`/${this.def.id} ...`],
315
+ modelConfig: this.def.modelConfig || requireModelConfig,
316
+ agents: this.agents,
317
+ synthesizer: this.def.synthesizer || this.agents[this.agents.length - 1]?.name,
318
+ concurrency: this.def.concurrency || 4,
319
+ };
320
+
321
+ // Register globally so slash commands can find it
322
+ registeredApps.set(definition.id, definition);
323
+ return definition;
324
+ }
325
+ }
326
+
327
+ // ─── Global App Registry ──────────────────────────────────────────
328
+
329
+ /** Map of appId → AppDefinition */
330
+ const registeredApps = new Map<string, AppDefinition>();
331
+
332
+ /**
333
+ * Get all registered apps.
334
+ */
335
+ export function getRegisteredApps(): AppDefinition[] {
336
+ return Array.from(registeredApps.values());
337
+ }
338
+
339
+ /**
340
+ * Get a specific app by ID.
341
+ */
342
+ export function getApp(id: string): AppDefinition | undefined {
343
+ return registeredApps.get(id);
344
+ }
345
+
346
+ /**
347
+ * Run an app by its registered ID.
348
+ */
349
+ export async function runApp(
350
+ appId: string,
351
+ options: AppRunOptions,
352
+ ): Promise<AppRunResult> {
353
+ const app = registeredApps.get(appId);
354
+ if (!app) {
355
+ throw new Error(`App "${appId}" not found. Available: ${Array.from(registeredApps.keys()).join(', ')}`);
356
+ }
357
+
358
+ const startTime = Date.now();
359
+ const modelCfg = app.modelConfig();
360
+ const agentConfig: AgentConfig = {
361
+ apiKey: modelCfg.apiKey,
362
+ baseURL: modelCfg.baseURL,
363
+ model: modelCfg.model,
364
+ timeout: modelCfg.timeout,
365
+ };
366
+
367
+ // Resolve permission mode
368
+ let permissionMode: string = options.permissionMode || 'default';
369
+ try {
370
+ const mode = configManager.getDefaultPermissionMode();
371
+ if (mode) permissionMode = mode;
372
+ } catch { /* use default */ }
373
+
374
+ const orchestrator = new OrchestratorAgent(
375
+ `App-${appId}`,
376
+ `You are ${app.name}. ${app.description}`,
377
+ );
378
+
379
+ // Register agents with resolved config
380
+ for (const agent of app.agents) {
381
+ orchestrator.registerAgent({
382
+ ...agent,
383
+ config: { ...agentConfig, ...agent.config },
384
+ confirmationHandler: options.confirmationHandler,
385
+ permissionMode: permissionMode as any,
386
+ });
387
+ }
388
+
389
+ // Build sub-tasks
390
+ const subTasks: Record<string, string> = {};
391
+ if (options.subTasks) {
392
+ Object.assign(subTasks, options.subTasks);
393
+ } else {
394
+ // Generate default sub-tasks from agent descriptions
395
+ for (const agent of app.agents) {
396
+ subTasks[agent.name] = agent.systemPrompt.split('\n')[0];
397
+ }
398
+ }
399
+
400
+ // Run orchestration
401
+ const result = await orchestrator.orchestrate(
402
+ options.task,
403
+ subTasks,
404
+ app.synthesizer,
405
+ options.sessionId,
406
+ );
407
+
408
+ const errorCount = result.responses.filter(
409
+ r => r.content.startsWith('[Error:') || r.content.startsWith('[Fatal:')
410
+ ).length;
411
+
412
+ return {
413
+ responses: result.responses.map(r => ({
414
+ agentName: r.agentName,
415
+ content: r.content,
416
+ toolCallsCount: r.metadata?.toolCallsCount,
417
+ durationMs: r.metadata?.durationMs,
418
+ })),
419
+ summary: result.summary,
420
+ totalDurationMs: Date.now() - startTime,
421
+ errorCount,
422
+ };
423
+ }
424
+
425
+ // ─── Auto-register built-in apps ───────────────────────────────────
426
+
427
+ /** Create default built-in apps */
428
+ export function createBuiltinApps(): AppDefinition[] {
429
+ return Object.entries(BUILTIN_APP_TEMPLATES).map(([id, template]) => {
430
+ const builder = new AppBuilder(id, template.name)
431
+ .describe(template.description)
432
+ .use(`/${id} <task>`)
433
+ .examples([
434
+ `/${id} ...`,
435
+ ]);
436
+
437
+ for (const agent of template.agents) {
438
+ builder.agent(agent.name, agent.role, agent.prompt, agent.tools);
439
+ }
440
+
441
+ return builder.register();
442
+ });
443
+ }