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.
Files changed (209) hide show
  1. package/bin/aegis.js +165 -0
  2. package/package.json +18 -86
  3. package/LICENSE +0 -21
  4. package/README.md +0 -394
  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
package/src/auth/login.ts DELETED
@@ -1,383 +0,0 @@
1
- /**
2
- * aegis login — browser-based OAuth flow
3
- *
4
- * 1. Start a one-shot HTTP server on a random local port
5
- * 2. Open the browser to aegiscloud.org/login?redirect_uri=...
6
- * 3. Wait for the callback carrying ?token=...
7
- * 4. Persist the token in ~/.aegiscode/config.json
8
- * 5. Resolve (caller prints success) or reject with a readable error
9
- */
10
-
11
- import * as http from 'node:http';
12
- import * as fs from 'node:fs';
13
- import * as path from 'node:path';
14
- import * as os from 'node:os';
15
- import { spawn } from 'node:child_process';
16
-
17
- const CONFIG_FILE = path.join(os.homedir(), '.aegiscode', 'config.json');
18
- const AEGISCLOUD_BASE = 'https://aegiscloud.org';
19
- const LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
20
-
21
- // ── Colors ──────────────────────────────────────────────────────────────────
22
- const C = {
23
- primary: '\x1b[38;2;0;229;192m',
24
- muted: '\x1b[2m',
25
- reset: '\x1b[0m',
26
- bold: '\x1b[1m',
27
- green: '\x1b[32m',
28
- };
29
-
30
- // ── Open browser ─────────────────────────────────────────────────────────────
31
- function openBrowser(url: string): void {
32
- // Linux: xdg-open; macOS: open; Windows: start
33
- const cmd =
34
- process.platform === 'darwin' ? 'open' :
35
- process.platform === 'win32' ? 'cmd' : 'xdg-open';
36
- const args = process.platform === 'win32' ? ['/c', 'start', url] : [url];
37
- spawn(cmd, args, { detached: true, stdio: 'ignore' }).unref();
38
- }
39
-
40
- // ── Persist token ────────────────────────────────────────────────────────────
41
- function saveToken(token: string): void {
42
- let cfg: Record<string, any> = {};
43
- try { cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch {}
44
-
45
- cfg.aegiscloud = { ...(cfg.aegiscloud ?? {}), api_key: token };
46
-
47
- const dir = path.dirname(CONFIG_FILE);
48
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
49
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2));
50
- }
51
-
52
- // ── Success page served to the browser ──────────────────────────────────────
53
- const SUCCESS_HTML = `<!DOCTYPE html>
54
- <html>
55
- <head>
56
- <meta charset="utf-8">
57
- <title>ÆGIS</title>
58
- <style>
59
- body { font-family: monospace; background: #0d1117; color: #00e5c0;
60
- display: flex; align-items: center; justify-content: center;
61
- height: 100vh; margin: 0; }
62
- .card { text-align: center; }
63
- h2 { font-size: 1.6rem; margin-bottom: .5rem; }
64
- p { color: #888; }
65
- </style>
66
- </head>
67
- <body>
68
- <div class="card">
69
- <h2>◆ Logged in</h2>
70
- <p>You can close this tab and return to the terminal.</p>
71
- </div>
72
- </body>
73
- </html>`;
74
-
75
- const ERROR_HTML = (msg: string) => `<!DOCTYPE html>
76
- <html>
77
- <head><meta charset="utf-8"><title>ÆGIS</title>
78
- <style>body{font-family:monospace;background:#0d1117;color:#ff5555;
79
- display:flex;align-items:center;justify-content:center;height:100vh;margin:0;}</style>
80
- </head>
81
- <body><h2>✗ ${msg}</h2></body>
82
- </html>`;
83
-
84
- // ── Main export ──────────────────────────────────────────────────────────────
85
- export async function runLogin(): Promise<{ token: string }> {
86
- return new Promise((resolve, reject) => {
87
- const server = http.createServer();
88
-
89
- server.listen(0, '127.0.0.1', () => {
90
- const { port } = server.address() as { port: number };
91
- const callbackUrl = `http://127.0.0.1:${port}`;
92
- const loginUrl = `${AEGISCLOUD_BASE}/auth/google?callback=${encodeURIComponent(callbackUrl)}`;
93
-
94
- let settled = false;
95
-
96
- const done = (err?: Error) => {
97
- if (settled) return;
98
- settled = true;
99
- server.close();
100
- if (err) reject(err);
101
- };
102
-
103
- const timer = setTimeout(
104
- () => done(new Error('Login timed out after 5 minutes. Please try again.')),
105
- LOGIN_TIMEOUT_MS,
106
- );
107
-
108
- server.on('request', (req, res) => {
109
- try {
110
- const url = new URL(req.url ?? '/', `http://127.0.0.1:${port}`);
111
-
112
- const token =
113
- url.searchParams.get('token') ??
114
- url.searchParams.get('api_key') ??
115
- url.searchParams.get('access_token');
116
-
117
- if (!token) {
118
- res.writeHead(400, { 'Content-Type': 'text/html' })
119
- .end(ERROR_HTML('No token received — please try again.'));
120
- done(new Error('No token in callback URL'));
121
- return;
122
- }
123
-
124
- res.writeHead(200, { 'Content-Type': 'text/html' }).end(SUCCESS_HTML);
125
-
126
- clearTimeout(timer);
127
- try {
128
- saveToken(token);
129
- done();
130
- resolve({ token });
131
- } catch (e) {
132
- done(e as Error);
133
- }
134
- } catch (e) {
135
- res.writeHead(500).end();
136
- done(e as Error);
137
- }
138
- });
139
-
140
- // ── Print prompt ───────────────────────────────────────────────────────
141
- process.stdout.write(
142
- `\n${C.primary}◆ ÆGIS — Login with Google${C.reset}\n\n` +
143
- ` Opening browser...\n\n` +
144
- ` ${C.muted}${loginUrl}${C.reset}\n\n` +
145
- ` ${C.muted}Paste this URL manually if the browser doesn't open.${C.reset}\n\n` +
146
- ` ${C.muted}Waiting for Google authentication… (Ctrl+Z to cancel)${C.reset}\n`,
147
- );
148
-
149
- openBrowser(loginUrl);
150
- });
151
-
152
- server.on('error', (err) => {
153
- reject(new Error(`Could not start local server: ${err.message}`));
154
- });
155
- });
156
- }
157
-
158
- // ── Username / password login ────────────────────────────────────────────────
159
- export async function runLoginPassword(): Promise<void> {
160
- const { createInterface } = await import('node:readline');
161
-
162
- const ask = (prompt: string): Promise<string> =>
163
- new Promise(resolve => {
164
- process.stdout.write(prompt);
165
- const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: false });
166
- rl.once('line', line => { rl.close(); resolve(line.trim()); });
167
- });
168
-
169
- const askHidden = (prompt: string): Promise<string> =>
170
- new Promise(resolve => {
171
- process.stdout.write(prompt);
172
- // Hide input by disabling echo
173
- if (process.stdin.isTTY) (process.stdin as any).setRawMode?.(true);
174
- let buf = '';
175
- const onData = (chunk: Buffer) => {
176
- for (const b of chunk) {
177
- if (b === 13 || b === 10) { // Enter
178
- process.stdout.write('\n');
179
- if (process.stdin.isTTY) (process.stdin as any).setRawMode?.(false);
180
- process.stdin.off('data', onData);
181
- process.stdin.pause();
182
- resolve(buf);
183
- return;
184
- } else if (b === 127 || b === 8) { // Backspace
185
- buf = buf.slice(0, -1);
186
- } else if (b >= 32) {
187
- buf += String.fromCharCode(b);
188
- }
189
- }
190
- };
191
- process.stdin.resume();
192
- process.stdin.on('data', onData);
193
- });
194
-
195
- process.stdout.write(`\n${C.primary}◆ ÆGIS — Login${C.reset}\n\n`);
196
-
197
- const username = await ask(' Username: ');
198
- if (!username) throw new Error('Username cannot be empty');
199
-
200
- const password = await askHidden(' Password: ');
201
- if (!password) throw new Error('Password cannot be empty');
202
-
203
- process.stdout.write(`\n ${C.muted}Signing in…${C.reset}\n`);
204
-
205
- const controller = new AbortController();
206
- const timer = setTimeout(() => controller.abort(), 10_000);
207
- try {
208
- const res = await fetch(`${AEGISCLOUD_BASE}/login`, {
209
- method: 'POST',
210
- headers: { 'Content-Type': 'application/json' },
211
- body: JSON.stringify({ username, password }),
212
- signal: controller.signal,
213
- });
214
- clearTimeout(timer);
215
- const data = await res.json() as any;
216
- if (!data.success) throw new Error(data.error || 'Invalid credentials');
217
- if (data.api_key) saveToken(data.api_key);
218
- } catch (e: any) {
219
- clearTimeout(timer);
220
- if (e.name === 'AbortError') throw new Error('Request timed out — check your connection');
221
- throw e;
222
- }
223
- }
224
-
225
- // ── Claude Code Pro/Max subscription login ──────────────────────────────────
226
- // Stores the OAuth token from `claude setup-token` (or pasted manually) into
227
- // ~/.aegiscode/.env as CLAUDE_CODE_OAUTH_TOKEN, which ConfigManager picks up
228
- // as an alternative credential for the currently configured Anthropic model —
229
- // it does not change which model is selected.
230
- const ENV_FILE = path.join(os.homedir(), '.aegiscode', '.env');
231
-
232
- function saveClaudeCodeOAuthToken(token: string): void {
233
- let lines: string[] = [];
234
- try { lines = fs.readFileSync(ENV_FILE, 'utf8').split('\n'); } catch {}
235
-
236
- const filtered = lines.filter(l => !l.startsWith('CLAUDE_CODE_OAUTH_TOKEN='));
237
- filtered.push(`CLAUDE_CODE_OAUTH_TOKEN=${token}`);
238
-
239
- const dir = path.dirname(ENV_FILE);
240
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
241
- fs.writeFileSync(ENV_FILE, filtered.filter(l => l.trim()).join('\n') + '\n');
242
- }
243
-
244
- // spawn('claude', ...)/`which claude` relies on PATH — same check ClaudeCliChatService
245
- // uses, duplicated here (rather than imported) to keep this auth module's only
246
- // dependency on node:child_process for the existing OAuth browser flow above.
247
- function isClaudeCliInstalled(): boolean {
248
- const home = os.homedir();
249
- const candidates = [
250
- ...(process.env.PATH || '').split(':').map(dir => path.join(dir, 'claude')),
251
- path.join(home, '.local', 'bin', 'claude'),
252
- path.join(home, '.npm-global', 'bin', 'claude'),
253
- '/usr/local/bin/claude',
254
- '/opt/homebrew/bin/claude',
255
- ];
256
- return candidates.some(p => p && fs.existsSync(p));
257
- }
258
-
259
- export async function runLoginClaudePro(): Promise<void> {
260
- if (!isClaudeCliInstalled()) {
261
- process.stdout.write(
262
- `\n${C.primary}◆ ÆGIS — Login with Claude Code Pro / Max${C.reset}\n\n` +
263
- ` The claude CLI isn't installed yet — it's required for this login\n` +
264
- ` method (your subscription auth lives in its credential store).\n\n` +
265
- ` Install it, then run this command again:\n` +
266
- ` ${C.bold}npm install -g @anthropic-ai/claude-code${C.reset}\n\n`,
267
- );
268
- return;
269
- }
270
-
271
- process.stdout.write(
272
- `\n${C.primary}◆ ÆGIS — Login with Claude Code Pro / Max${C.reset}\n\n` +
273
- ` This uses your claude.ai subscription instead of a pay-per-token API key.\n` +
274
- ` Generate a token with: ${C.bold}claude setup-token${C.reset}\n\n`,
275
- );
276
-
277
- const { createInterface } = await import('node:readline');
278
- const token = await new Promise<string>(resolve => {
279
- process.stdout.write(' Paste the token here: ');
280
- const rl = createInterface({ input: process.stdin, output: process.stdout, terminal: false });
281
- rl.once('line', line => { rl.close(); resolve(line.trim()); });
282
- });
283
-
284
- if (!token) throw new Error('No token provided');
285
- if (!token.startsWith('sk-ant-oat')) {
286
- throw new Error('That doesn\'t look like a Claude Code OAuth token (expected it to start with "sk-ant-oat").');
287
- }
288
-
289
- saveClaudeCodeOAuthToken(token);
290
- process.stdout.write(`\n ${C.green}✓ Saved.${C.reset} aegiscode will use your Claude Pro/Max subscription.\n\n`);
291
- }
292
-
293
- // ── Periodic account re-verification ─────────────────────────────────────────
294
- // A stored api_key never expires on the client, so a revoked/deleted account
295
- // would otherwise stay "logged in" forever. Re-check against the server at
296
- // most once per cache window — frequent enough to catch revocation, rare
297
- // enough that it doesn't add a network round trip to every single run.
298
- const ACCOUNT_VERIFY_CACHE_MS = 24 * 60 * 60 * 1000; // 24 hours
299
-
300
- /** Calls /api/me with the stored api_key. Clears the key and returns invalid on a 401. */
301
- export async function verifyAccount(): Promise<{ valid: boolean; username?: string }> {
302
- let cfg: Record<string, any> = {};
303
- try { cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch {}
304
-
305
- const apiKey = cfg?.aegiscloud?.api_key;
306
- if (!apiKey) return { valid: false };
307
-
308
- const controller = new AbortController();
309
- const timer = setTimeout(() => controller.abort(), 8000);
310
- try {
311
- const res = await fetch(`${AEGISCLOUD_BASE}/api/me`, {
312
- headers: { Authorization: `Bearer ${apiKey}` },
313
- signal: controller.signal,
314
- });
315
- clearTimeout(timer);
316
-
317
- if (res.status === 401) {
318
- delete cfg.aegiscloud.api_key;
319
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2));
320
- return { valid: false };
321
- }
322
- if (!res.ok) return { valid: true }; // server hiccup — fail open, don't lock the user out
323
-
324
- const data = await res.json() as { username?: string };
325
- cfg.aegiscloud = { ...cfg.aegiscloud, lastVerified: new Date().toISOString() };
326
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2));
327
- return { valid: true, username: data.username };
328
- } catch {
329
- clearTimeout(timer);
330
- // Network error — fail open so a flaky/offline connection doesn't force a re-login.
331
- return { valid: true };
332
- }
333
- }
334
-
335
- /**
336
- * True if there's a stored api_key and it's either freshly verified (within
337
- * the cache window) or just passed a live re-check. False only when the
338
- * server explicitly rejected the key (revoked/deleted account).
339
- */
340
- export async function ensureAccountValid(): Promise<boolean> {
341
- let cfg: Record<string, any> = {};
342
- try { cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch {}
343
- if (!cfg?.aegiscloud?.api_key) return false;
344
-
345
- const lv = cfg?.aegiscloud?.lastVerified;
346
- if (lv && Date.now() - new Date(lv).getTime() < ACCOUNT_VERIFY_CACHE_MS) return true;
347
-
348
- const { valid } = await verifyAccount();
349
- return valid;
350
- }
351
-
352
- // ── Logout helper ─────────────────────────────────────────────────────────────
353
- export function runLogout(): void {
354
- let cfg: Record<string, any> = {};
355
- try { cfg = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); } catch {}
356
-
357
- let hadOAuthToken = false;
358
- try {
359
- const lines = fs.readFileSync(ENV_FILE, 'utf8').split('\n');
360
- hadOAuthToken = lines.some(l => l.startsWith('CLAUDE_CODE_OAUTH_TOKEN='));
361
- const filtered = lines.filter(l => !l.startsWith('CLAUDE_CODE_OAUTH_TOKEN='));
362
- fs.writeFileSync(ENV_FILE, filtered.filter(l => l.trim()).join('\n') + (filtered.some(l => l.trim()) ? '\n' : ''));
363
- } catch {}
364
-
365
- const hadKey = !!(cfg.aegiscloud?.api_key) || hadOAuthToken;
366
-
367
- if (cfg.aegiscloud) {
368
- delete cfg.aegiscloud.api_key;
369
- cfg.aegiscloud.syncConversations = false;
370
- }
371
-
372
- try {
373
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2));
374
- process.stdout.write(
375
- hadKey
376
- ? `\n${C.green}✓ Logged out.${C.reset}\n\n`
377
- : `\n${C.muted}(no active session)${C.reset}\n\n`,
378
- );
379
- } catch (e) {
380
- process.stderr.write(`Failed to update config: ${(e as Error).message}\n`);
381
- process.exit(1);
382
- }
383
- }
package/src/cli/config.ts DELETED
@@ -1,189 +0,0 @@
1
- /**
2
- * CLI 配置 - yargs 选项定义
3
- */
4
-
5
- import type { Options } from 'yargs';
6
- import fs from 'fs';
7
- import path from 'path';
8
- import { fileURLToPath } from 'url';
9
-
10
- /**
11
- *
12
- *
13
- *
14
- *
15
- *
16
- */
17
- function readVersionSync(): string {
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = path.dirname(__filename);
20
-
21
- const possiblePaths = [
22
- path.resolve(__dirname, '../package.json'), // 打包
23
- path.resolve(__dirname, '../../package.json'), // 开发环
24
- ];
25
-
26
- for (const pkgPath of possiblePaths) {
27
- try {
28
- const content = fs.readFileSync(pkgPath, 'utf-8');
29
- const pkg = JSON.parse(content) as { name?: string; version?: string };
30
- if (pkg.version && (pkg.name === 'aegis' || pkg.name === 'aegis-cli' || pkg.name === 'aegiscode')) {
31
- return pkg.version;
32
- }
33
- } catch {
34
- // 继续尝试下一个路
35
- }
36
- }
37
-
38
- return '0.1.0';
39
- }
40
-
41
- const version = readVersionSync();
42
-
43
- /**
44
- * CLI 基础配置
45
- */
46
- export const cliConfig = {
47
- scriptName: 'aegis',
48
- usage: '$0 [message] [options]',
49
- version,
50
- };
51
-
52
- /**
53
- *
54
- *
55
- *
56
- * - Debug Options: 调试相关
57
- * - AI Options: 模型和 AI 相关
58
- * - Security Options: 权限和安全相关
59
- * - Session Options: 会话管理相关
60
- * - Output Options: 输出格式相关
61
- */
62
- export const globalOptions = {
63
- // ========== Debug Options ==========
64
- debug: {
65
- alias: 'd',
66
- type: 'boolean',
67
- describe: 'Enable debug mode',
68
- default: false,
69
- group: 'Debug Options:',
70
- },
71
-
72
- // ========== AI Options ==========
73
- 'api-key': {
74
- type: 'string',
75
- describe: 'API key for the LLM service',
76
- group: 'AI Options:',
77
- },
78
-
79
- 'base-url': {
80
- type: 'string',
81
- describe: 'Base URL for the API (for OpenAI-compatible services)',
82
- group: 'AI Options:',
83
- },
84
-
85
- model: {
86
- alias: 'm',
87
- type: 'string',
88
- describe: 'Model to use for the current session',
89
- group: 'AI Options:',
90
- },
91
-
92
- 'max-turns': {
93
- type: 'number',
94
- describe: 'Maximum conversation turns (-1 = unlimited, default: -1)',
95
- group: 'AI Options:',
96
- },
97
-
98
- router: {
99
- type: 'boolean',
100
- describe: 'Start with the auto-router on — picks a model per message based on task complexity',
101
- default: false,
102
- group: 'AI Options:',
103
- },
104
-
105
- // ========== Security Options ==========
106
- 'permission-mode': {
107
- type: 'string',
108
- choices: ['default', 'autoEdit', 'yolo'] as const,
109
- describe: 'Permission mode for tool execution',
110
- group: 'Security Options:',
111
- },
112
-
113
- yolo: {
114
- type: 'boolean',
115
- describe: 'Auto-approve all tool executions (alias for --permission-mode=yolo)',
116
- default: false,
117
- group: 'Security Options:',
118
- },
119
-
120
- 'allowed-tools': {
121
- type: 'array',
122
- string: true,
123
- describe: 'List of tool names to allow',
124
- group: 'Security Options:',
125
- },
126
-
127
- 'disallowed-tools': {
128
- type: 'array',
129
- string: true,
130
- describe: 'List of tool names to disallow',
131
- group: 'Security Options:',
132
- },
133
-
134
- // ========== Session Options ==========
135
- continue: {
136
- alias: 'c',
137
- type: 'boolean',
138
- describe: 'Continue the most recent conversation',
139
- default: false,
140
- group: 'Session Options:',
141
- },
142
-
143
- resume: {
144
- alias: 'r',
145
- type: 'string',
146
- describe: 'Resume a specific conversation by ID',
147
- group: 'Session Options:',
148
- },
149
-
150
- // ========== Output Options ==========
151
- print: {
152
- alias: 'p',
153
- type: 'boolean',
154
- describe: 'Print response and exit (non-interactive mode)',
155
- default: false,
156
- group: 'Output Options:',
157
- },
158
-
159
- 'output-format': {
160
- type: 'string',
161
- choices: ['text', 'json'] as const,
162
- describe: 'Output format (only with --print)',
163
- default: 'text',
164
- group: 'Output Options:',
165
- },
166
-
167
- // ========== UI Options ==========
168
- theme: {
169
- alias: 't',
170
- type: 'string',
171
- choices: ['default', 'light', 'dark', 'ocean', 'forest', 'sunset'] as const,
172
- describe: 'Color theme for the UI (overrides saved preference)',
173
- group: 'UI Options:',
174
- },
175
- 'plain': {
176
- type: 'boolean',
177
- describe: 'Plain text mode (disable Ink rendering, for non-TTY terminals)',
178
- default: false,
179
- group: 'UI Options:',
180
- },
181
-
182
- // ========== Config Options ==========
183
- init: {
184
- type: 'boolean',
185
- describe: 'Create default configuration file',
186
- default: false,
187
- group: 'Config Options:',
188
- },
189
- } satisfies Record<string, Options>;
package/src/cli/index.ts DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * CLI 模块导出
3
- */
4
-
5
- export { cliConfig, globalOptions } from './config.js';
6
- export {
7
- validatePermissions,
8
- loadConfiguration,
9
- validateOutput,
10
- middlewareChain,
11
- } from './middleware.js';
12
- export type {
13
- CliArguments,
14
- MiddlewareFunction,
15
- PermissionMode,
16
- AppProps,
17
- } from './types.js';