@bluehawks/cli 1.0.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 (176) hide show
  1. package/.eslintrc.json +36 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +288 -0
  4. package/dist/cli/app.d.ts +12 -0
  5. package/dist/cli/app.d.ts.map +1 -0
  6. package/dist/cli/app.js +201 -0
  7. package/dist/cli/app.js.map +1 -0
  8. package/dist/cli/commands/index.d.ts +56 -0
  9. package/dist/cli/commands/index.d.ts.map +1 -0
  10. package/dist/cli/commands/index.js +201 -0
  11. package/dist/cli/commands/index.js.map +1 -0
  12. package/dist/config/constants.d.ts +32 -0
  13. package/dist/config/constants.d.ts.map +1 -0
  14. package/dist/config/constants.js +39 -0
  15. package/dist/config/constants.js.map +1 -0
  16. package/dist/config/index.d.ts +4 -0
  17. package/dist/config/index.d.ts.map +1 -0
  18. package/dist/config/index.js +4 -0
  19. package/dist/config/index.js.map +1 -0
  20. package/dist/config/schema.d.ts +56 -0
  21. package/dist/config/schema.d.ts.map +1 -0
  22. package/dist/config/schema.js +28 -0
  23. package/dist/config/schema.js.map +1 -0
  24. package/dist/config/settings.d.ts +20 -0
  25. package/dist/config/settings.d.ts.map +1 -0
  26. package/dist/config/settings.js +102 -0
  27. package/dist/config/settings.js.map +1 -0
  28. package/dist/core/agents/agent.d.ts +33 -0
  29. package/dist/core/agents/agent.d.ts.map +1 -0
  30. package/dist/core/agents/agent.js +156 -0
  31. package/dist/core/agents/agent.js.map +1 -0
  32. package/dist/core/agents/index.d.ts +3 -0
  33. package/dist/core/agents/index.d.ts.map +1 -0
  34. package/dist/core/agents/index.js +3 -0
  35. package/dist/core/agents/index.js.map +1 -0
  36. package/dist/core/agents/orchestrator.d.ts +56 -0
  37. package/dist/core/agents/orchestrator.d.ts.map +1 -0
  38. package/dist/core/agents/orchestrator.js +151 -0
  39. package/dist/core/agents/orchestrator.js.map +1 -0
  40. package/dist/core/api/client.d.ts +46 -0
  41. package/dist/core/api/client.d.ts.map +1 -0
  42. package/dist/core/api/client.js +223 -0
  43. package/dist/core/api/client.js.map +1 -0
  44. package/dist/core/api/index.d.ts +3 -0
  45. package/dist/core/api/index.d.ts.map +1 -0
  46. package/dist/core/api/index.js +3 -0
  47. package/dist/core/api/index.js.map +1 -0
  48. package/dist/core/api/types.d.ts +126 -0
  49. package/dist/core/api/types.d.ts.map +1 -0
  50. package/dist/core/api/types.js +16 -0
  51. package/dist/core/api/types.js.map +1 -0
  52. package/dist/core/hooks/index.d.ts +3 -0
  53. package/dist/core/hooks/index.d.ts.map +1 -0
  54. package/dist/core/hooks/index.js +3 -0
  55. package/dist/core/hooks/index.js.map +1 -0
  56. package/dist/core/hooks/manager.d.ts +43 -0
  57. package/dist/core/hooks/manager.d.ts.map +1 -0
  58. package/dist/core/hooks/manager.js +178 -0
  59. package/dist/core/hooks/manager.js.map +1 -0
  60. package/dist/core/hooks/types.d.ts +68 -0
  61. package/dist/core/hooks/types.d.ts.map +1 -0
  62. package/dist/core/hooks/types.js +6 -0
  63. package/dist/core/hooks/types.js.map +1 -0
  64. package/dist/core/mcp/client.d.ts +48 -0
  65. package/dist/core/mcp/client.d.ts.map +1 -0
  66. package/dist/core/mcp/client.js +139 -0
  67. package/dist/core/mcp/client.js.map +1 -0
  68. package/dist/core/mcp/index.d.ts +3 -0
  69. package/dist/core/mcp/index.d.ts.map +1 -0
  70. package/dist/core/mcp/index.js +3 -0
  71. package/dist/core/mcp/index.js.map +1 -0
  72. package/dist/core/mcp/manager.d.ts +46 -0
  73. package/dist/core/mcp/manager.d.ts.map +1 -0
  74. package/dist/core/mcp/manager.js +133 -0
  75. package/dist/core/mcp/manager.js.map +1 -0
  76. package/dist/core/plugins/index.d.ts +3 -0
  77. package/dist/core/plugins/index.d.ts.map +1 -0
  78. package/dist/core/plugins/index.js +3 -0
  79. package/dist/core/plugins/index.js.map +1 -0
  80. package/dist/core/plugins/loader.d.ts +63 -0
  81. package/dist/core/plugins/loader.d.ts.map +1 -0
  82. package/dist/core/plugins/loader.js +258 -0
  83. package/dist/core/plugins/loader.js.map +1 -0
  84. package/dist/core/plugins/types.d.ts +95 -0
  85. package/dist/core/plugins/types.d.ts.map +1 -0
  86. package/dist/core/plugins/types.js +6 -0
  87. package/dist/core/plugins/types.js.map +1 -0
  88. package/dist/core/session/index.d.ts +3 -0
  89. package/dist/core/session/index.d.ts.map +1 -0
  90. package/dist/core/session/index.js +3 -0
  91. package/dist/core/session/index.js.map +1 -0
  92. package/dist/core/session/manager.d.ts +57 -0
  93. package/dist/core/session/manager.d.ts.map +1 -0
  94. package/dist/core/session/manager.js +182 -0
  95. package/dist/core/session/manager.js.map +1 -0
  96. package/dist/core/session/storage.d.ts +42 -0
  97. package/dist/core/session/storage.d.ts.map +1 -0
  98. package/dist/core/session/storage.js +138 -0
  99. package/dist/core/session/storage.js.map +1 -0
  100. package/dist/core/tools/definitions/file.d.ts +6 -0
  101. package/dist/core/tools/definitions/file.d.ts.map +1 -0
  102. package/dist/core/tools/definitions/file.js +276 -0
  103. package/dist/core/tools/definitions/file.js.map +1 -0
  104. package/dist/core/tools/definitions/git.d.ts +6 -0
  105. package/dist/core/tools/definitions/git.d.ts.map +1 -0
  106. package/dist/core/tools/definitions/git.js +294 -0
  107. package/dist/core/tools/definitions/git.js.map +1 -0
  108. package/dist/core/tools/definitions/index.d.ts +11 -0
  109. package/dist/core/tools/definitions/index.d.ts.map +1 -0
  110. package/dist/core/tools/definitions/index.js +22 -0
  111. package/dist/core/tools/definitions/index.js.map +1 -0
  112. package/dist/core/tools/definitions/search.d.ts +6 -0
  113. package/dist/core/tools/definitions/search.d.ts.map +1 -0
  114. package/dist/core/tools/definitions/search.js +223 -0
  115. package/dist/core/tools/definitions/search.js.map +1 -0
  116. package/dist/core/tools/definitions/shell.d.ts +6 -0
  117. package/dist/core/tools/definitions/shell.d.ts.map +1 -0
  118. package/dist/core/tools/definitions/shell.js +190 -0
  119. package/dist/core/tools/definitions/shell.js.map +1 -0
  120. package/dist/core/tools/definitions/web.d.ts +6 -0
  121. package/dist/core/tools/definitions/web.d.ts.map +1 -0
  122. package/dist/core/tools/definitions/web.js +104 -0
  123. package/dist/core/tools/definitions/web.js.map +1 -0
  124. package/dist/core/tools/executor.d.ts +24 -0
  125. package/dist/core/tools/executor.d.ts.map +1 -0
  126. package/dist/core/tools/executor.js +111 -0
  127. package/dist/core/tools/executor.js.map +1 -0
  128. package/dist/core/tools/index.d.ts +4 -0
  129. package/dist/core/tools/index.d.ts.map +1 -0
  130. package/dist/core/tools/index.js +4 -0
  131. package/dist/core/tools/index.js.map +1 -0
  132. package/dist/core/tools/registry.d.ts +23 -0
  133. package/dist/core/tools/registry.d.ts.map +1 -0
  134. package/dist/core/tools/registry.js +28 -0
  135. package/dist/core/tools/registry.js.map +1 -0
  136. package/dist/index.d.ts +7 -0
  137. package/dist/index.d.ts.map +1 -0
  138. package/dist/index.js +352 -0
  139. package/dist/index.js.map +1 -0
  140. package/package.json +62 -0
  141. package/src/cli/app.tsx +319 -0
  142. package/src/cli/commands/index.ts +261 -0
  143. package/src/config/constants.ts +45 -0
  144. package/src/config/index.ts +3 -0
  145. package/src/config/schema.ts +36 -0
  146. package/src/config/settings.ts +121 -0
  147. package/src/core/agents/agent.ts +205 -0
  148. package/src/core/agents/index.ts +2 -0
  149. package/src/core/agents/orchestrator.ts +223 -0
  150. package/src/core/api/client.ts +300 -0
  151. package/src/core/api/index.ts +2 -0
  152. package/src/core/api/types.ts +149 -0
  153. package/src/core/hooks/index.ts +2 -0
  154. package/src/core/hooks/manager.ts +212 -0
  155. package/src/core/hooks/types.ts +116 -0
  156. package/src/core/mcp/client.ts +198 -0
  157. package/src/core/mcp/index.ts +2 -0
  158. package/src/core/mcp/manager.ts +153 -0
  159. package/src/core/plugins/index.ts +2 -0
  160. package/src/core/plugins/loader.ts +312 -0
  161. package/src/core/plugins/types.ts +111 -0
  162. package/src/core/session/index.ts +2 -0
  163. package/src/core/session/manager.ts +246 -0
  164. package/src/core/session/storage.ts +184 -0
  165. package/src/core/tools/definitions/file.ts +312 -0
  166. package/src/core/tools/definitions/git.ts +326 -0
  167. package/src/core/tools/definitions/index.ts +24 -0
  168. package/src/core/tools/definitions/search.ts +266 -0
  169. package/src/core/tools/definitions/shell.ts +228 -0
  170. package/src/core/tools/definitions/web.ts +113 -0
  171. package/src/core/tools/executor.ts +145 -0
  172. package/src/core/tools/index.ts +3 -0
  173. package/src/core/tools/registry.ts +44 -0
  174. package/src/index.ts +407 -0
  175. package/tsconfig.json +40 -0
  176. package/vitest.config.ts +13 -0
package/src/index.ts ADDED
@@ -0,0 +1,407 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Bluehawks CLI - Entry Point
4
+ * A production-ready multi-agent AI CLI assistant
5
+ */
6
+
7
+ import { program } from 'commander';
8
+ import { render } from 'ink';
9
+ import React from 'react';
10
+ import { App } from './cli/app.js';
11
+ import { CLI_NAME, CLI_VERSION, CLI_DESCRIPTION, API_BASE_URL, DEFAULT_MODEL } from './config/constants.js';
12
+ import { APIClient } from './core/api/client.js';
13
+ import { Orchestrator } from './core/agents/orchestrator.js';
14
+ import { ToolExecutor, registerAllTools, toolRegistry } from './core/tools/index.js';
15
+ import * as fs from 'node:fs';
16
+ import * as path from 'node:path';
17
+ import * as os from 'node:os';
18
+
19
+ // Load configuration from ~/.bluehawks/.env
20
+ function loadConfig() {
21
+ const envPath = path.join(os.homedir(), '.bluehawks', '.env');
22
+ try {
23
+ const content = fs.readFileSync(envPath, 'utf-8');
24
+ for (const line of content.split('\n')) {
25
+ const match = line.match(/^([^#=]+)=(.*)$/);
26
+ if (match) {
27
+ const [, key, value] = match;
28
+ const trimmedKey = key.trim();
29
+ const trimmedValue = value.trim().replace(/^['"]|['"]$/g, '');
30
+ if (!process.env[trimmedKey]) {
31
+ process.env[trimmedKey] = trimmedValue;
32
+ }
33
+ }
34
+ }
35
+ } catch {
36
+ // No config file, that's fine
37
+ }
38
+ }
39
+
40
+ // Load config before anything else
41
+ loadConfig();
42
+
43
+ // Headless mode execution
44
+ interface HeadlessOptions {
45
+ json?: boolean;
46
+ apiKey?: string;
47
+ maxTurns?: number;
48
+ systemPrompt?: string;
49
+ appendSystemPrompt?: string;
50
+ outputFormat?: 'text' | 'json' | 'stream-json';
51
+ continueSession?: boolean;
52
+ resumeSession?: string;
53
+ }
54
+
55
+ async function runHeadless(prompt: string, options: HeadlessOptions) {
56
+ const apiClient = new APIClient({ apiKey: options.apiKey });
57
+ const toolExecutor = new ToolExecutor({ approvalMode: 'never' }); // Auto-approve in headless
58
+ registerAllTools();
59
+
60
+ const orchestrator = new Orchestrator({
61
+ projectPath: process.cwd(),
62
+ apiClient,
63
+ toolExecutor,
64
+ maxTurns: options.maxTurns,
65
+ systemPrompt: options.systemPrompt,
66
+ appendSystemPrompt: options.appendSystemPrompt,
67
+ });
68
+
69
+ await orchestrator.initialize();
70
+
71
+ // Handle session continuation
72
+ if (options.continueSession || options.resumeSession) {
73
+ const { sessionStorage } = await import('./core/session/storage.js');
74
+ const session = options.resumeSession
75
+ ? await sessionStorage.loadSession(options.resumeSession)
76
+ : await sessionStorage.loadLastSession();
77
+
78
+ if (session) {
79
+ // Restore session messages to orchestrator
80
+ // This would require extending orchestrator to accept initial messages
81
+ console.error(`šŸ“‚ Resuming session...`);
82
+ }
83
+ }
84
+
85
+
86
+ // Track if we're inside <think> tags to filter them out
87
+ let inThinkBlock = false;
88
+ let thinkBuffer = '';
89
+
90
+ try {
91
+ const response = await orchestrator.chat(prompt, [], {
92
+ onChunk: options.json ? undefined : (chunk) => {
93
+ // Filter out <think>...</think> blocks for cleaner output
94
+ const fullText = thinkBuffer + chunk;
95
+ thinkBuffer = '';
96
+
97
+ let output = '';
98
+ let i = 0;
99
+ while (i < fullText.length) {
100
+ if (!inThinkBlock) {
101
+ const thinkStart = fullText.indexOf('<think>', i);
102
+ if (thinkStart === -1) {
103
+ output += fullText.substring(i);
104
+ break;
105
+ } else {
106
+ output += fullText.substring(i, thinkStart);
107
+ inThinkBlock = true;
108
+ i = thinkStart + 7;
109
+ }
110
+ } else {
111
+ const thinkEnd = fullText.indexOf('</think>', i);
112
+ if (thinkEnd === -1) {
113
+ // Think block continues, buffer the rest
114
+ thinkBuffer = fullText.substring(i);
115
+ break;
116
+ } else {
117
+ inThinkBlock = false;
118
+ i = thinkEnd + 8;
119
+ }
120
+ }
121
+ }
122
+ if (output.trim()) {
123
+ process.stdout.write(output);
124
+ }
125
+ },
126
+ });
127
+
128
+ // Strip think blocks from final content for JSON output
129
+ const cleanContent = response.content.replace(/<think>[\s\S]*?<\/think>/g, '').trim();
130
+
131
+ if (options.json) {
132
+ console.log(JSON.stringify({
133
+ success: true,
134
+ content: cleanContent,
135
+ toolsUsed: response.toolsUsed,
136
+ iterations: response.iterations,
137
+ }, null, 2));
138
+ } else {
139
+ console.log(); // New line after streaming
140
+ }
141
+
142
+ process.exit(0);
143
+ } catch (error) {
144
+ if (options.json) {
145
+ console.log(JSON.stringify({
146
+ success: false,
147
+ error: error instanceof Error ? error.message : String(error),
148
+ }, null, 2));
149
+ } else {
150
+ console.error('Error:', error instanceof Error ? error.message : String(error));
151
+ }
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ // Configure CLI
157
+ program
158
+ .name(CLI_NAME)
159
+ .version(CLI_VERSION)
160
+ .description(CLI_DESCRIPTION);
161
+
162
+ // Main command (interactive mode)
163
+ program
164
+ .option('-p, --prompt <text>', 'Run in headless mode with the given prompt')
165
+ .option('-j, --json', 'Output response as JSON (headless mode only)')
166
+ .option('-k, --api-key <key>', 'API key for authentication')
167
+ .option('--yolo', 'Enable YOLO mode (auto-approve all tool executions)')
168
+ .option('--plan', 'Enable plan mode (create plan before execution)')
169
+ .option('-c, --continue', 'Continue the most recent session')
170
+ .option('-r, --resume <session>', 'Resume a specific named session')
171
+ .option('--max-turns <n>', 'Maximum number of agentic iterations', parseInt)
172
+ .option('--system-prompt <text>', 'Override the system prompt')
173
+ .option('--append-system-prompt <text>', 'Append to the default system prompt')
174
+ .option('--add-dir <dirs...>', 'Additional directories to include in context')
175
+ .option('--output-format <format>', 'Output format: text, json, stream-json', 'text')
176
+ .action(async (options) => {
177
+
178
+ // Headless mode
179
+ if (options.prompt) {
180
+ await runHeadless(options.prompt, {
181
+ json: options.json || options.outputFormat === 'json',
182
+ apiKey: options.apiKey,
183
+ maxTurns: options.maxTurns,
184
+ systemPrompt: options.systemPrompt,
185
+ appendSystemPrompt: options.appendSystemPrompt,
186
+ outputFormat: options.outputFormat,
187
+ continueSession: options.continue,
188
+ resumeSession: options.resume,
189
+ });
190
+ return;
191
+ }
192
+
193
+
194
+ // Interactive mode
195
+ console.log(`\nšŸ¦… ${CLI_NAME} v${CLI_VERSION}`);
196
+ console.log(` API: ${API_BASE_URL}`);
197
+ console.log(` Model: ${DEFAULT_MODEL}\n`);
198
+
199
+ const { waitUntilExit } = render(
200
+ React.createElement(App, {
201
+ apiKey: options.apiKey,
202
+ yoloMode: options.yolo,
203
+ })
204
+ );
205
+
206
+ await waitUntilExit();
207
+ });
208
+
209
+ // Config command (show only)
210
+ program
211
+ .command('config')
212
+ .description('Show current configuration')
213
+ .action(() => {
214
+ console.log('\nšŸ“‹ Current Configuration:');
215
+ console.log(` API URL: ${process.env.BLUEHAWKS_API_URL || API_BASE_URL}`);
216
+ console.log(` Model: ${process.env.BLUEHAWKS_MODEL || DEFAULT_MODEL}`);
217
+ console.log(` API Key: ${process.env.BLUEHAWKS_API_KEY ? '***set***' : 'not set'}\n`);
218
+ console.log('Environment Variables:');
219
+ console.log(' BLUEHAWKS_API_URL - Override API endpoint');
220
+ console.log(' BLUEHAWKS_API_KEY - API key for authentication');
221
+ console.log(' BLUEHAWKS_MODEL - Override model name\n');
222
+ console.log('Run `bluehawks configure` to set up your API key.\n');
223
+ });
224
+
225
+ // Configure command (interactive setup)
226
+ program
227
+ .command('configure')
228
+ .description('Interactive setup for API key and settings')
229
+ .action(async () => {
230
+ const readline = await import('node:readline');
231
+ const fs = await import('node:fs/promises');
232
+ const path = await import('node:path');
233
+ const os = await import('node:os');
234
+
235
+ const rl = readline.createInterface({
236
+ input: process.stdin,
237
+ output: process.stdout,
238
+ });
239
+
240
+ const question = (prompt: string): Promise<string> => {
241
+ return new Promise((resolve) => {
242
+ rl.question(prompt, resolve);
243
+ });
244
+ };
245
+
246
+ console.log('\nšŸ¦… Bluehawks Configuration\n');
247
+ console.log('This will save your settings to ~/.bluehawks/.env\n');
248
+
249
+ // Get current values
250
+ const currentApiKey = process.env.BLUEHAWKS_API_KEY || '';
251
+ const currentUrl = process.env.BLUEHAWKS_API_URL || API_BASE_URL;
252
+ const currentModel = process.env.BLUEHAWKS_MODEL || DEFAULT_MODEL;
253
+
254
+ // Prompt for API key
255
+ const apiKeyPrompt = currentApiKey
256
+ ? `API Key [${currentApiKey.substring(0, 8)}...]: `
257
+ : 'API Key: ';
258
+ const apiKey = await question(apiKeyPrompt) || currentApiKey;
259
+
260
+ // Prompt for API URL (optional)
261
+ const urlPrompt = `API URL [${currentUrl}]: `;
262
+ const apiUrl = await question(urlPrompt) || currentUrl;
263
+
264
+ // Prompt for Model (optional)
265
+ const modelPrompt = `Model [${currentModel}]: `;
266
+ const model = await question(modelPrompt) || currentModel;
267
+
268
+ rl.close();
269
+
270
+ // Create config directory
271
+ const configDir = path.join(os.homedir(), '.bluehawks');
272
+ await fs.mkdir(configDir, { recursive: true });
273
+
274
+ // Write .env file
275
+ const envPath = path.join(configDir, '.env');
276
+ const envContent = [
277
+ `# Bluehawks CLI Configuration`,
278
+ `BLUEHAWKS_API_KEY=${apiKey}`,
279
+ `BLUEHAWKS_API_URL=${apiUrl}`,
280
+ `BLUEHAWKS_MODEL=${model}`,
281
+ ].join('\n');
282
+
283
+ await fs.writeFile(envPath, envContent, 'utf-8');
284
+
285
+ console.log(`\nāœ… Configuration saved to ${envPath}`);
286
+ console.log('\nTo use this configuration, add this to your shell profile:');
287
+ console.log(` source ~/.bluehawks/.env\n`);
288
+ console.log('Or export variables manually:');
289
+ console.log(` export BLUEHAWKS_API_KEY="${apiKey}"\n`);
290
+ });
291
+
292
+ // Tools command
293
+ program
294
+ .command('tools')
295
+ .description('List available tools')
296
+ .action(() => {
297
+ registerAllTools();
298
+ const tools = toolRegistry.getAll();
299
+
300
+ console.log('\nšŸ”§ Available Tools:\n');
301
+ for (const tool of tools) {
302
+ const desc = tool.definition.function.description;
303
+ const safe = tool.safeToAutoRun ? 'āœ“ safe' : '⚠ requires approval';
304
+ console.log(` ${tool.name}`);
305
+ console.log(` ${desc.substring(0, 80)}${desc.length > 80 ? '...' : ''}`);
306
+ console.log(` ${safe}\n`);
307
+ }
308
+ });
309
+
310
+ // Sessions command
311
+ program
312
+ .command('sessions')
313
+ .description('List and manage saved sessions')
314
+ .option('-d, --delete <session>', 'Delete a session')
315
+ .action(async (options) => {
316
+ const { sessionStorage } = await import('./core/session/storage.js');
317
+
318
+ if (options.delete) {
319
+ const success = await sessionStorage.deleteSession(options.delete);
320
+ console.log(success ? `āœ… Deleted: ${options.delete}` : `āŒ Not found: ${options.delete}`);
321
+ return;
322
+ }
323
+
324
+ const sessions = await sessionStorage.listSessions(20);
325
+ if (sessions.length === 0) {
326
+ console.log('\nšŸ“‚ No saved sessions.\n');
327
+ return;
328
+ }
329
+
330
+ console.log('\nšŸ“‚ Saved Sessions:\n');
331
+ for (const s of sessions) {
332
+ const date = new Date(s.lastAccessTime).toLocaleDateString();
333
+ console.log(` ${s.name} (${s.messageCount} msgs) - ${date}`);
334
+ }
335
+ console.log();
336
+ });
337
+
338
+ // Plugins command
339
+ program
340
+ .command('plugins')
341
+ .description('List and manage plugins')
342
+ .option('-r, --reload', 'Reload all plugins')
343
+ .option('-i, --info <name>', 'Show details about a plugin')
344
+ .action(async (options) => {
345
+ const { pluginLoader } = await import('./core/plugins/index.js');
346
+
347
+ if (options.reload) {
348
+ pluginLoader.unloadAll();
349
+ await pluginLoader.loadAll();
350
+ console.log('āœ… Plugins reloaded');
351
+ return;
352
+ }
353
+
354
+ if (options.info) {
355
+ const plugin = pluginLoader.getPlugin(options.info);
356
+ if (!plugin) {
357
+ console.log(`āŒ Plugin not found: ${options.info}`);
358
+ return;
359
+ }
360
+ console.log(`\nšŸ“¦ ${plugin.manifest.name} v${plugin.manifest.version}`);
361
+ console.log(` ${plugin.manifest.description || ''}`);
362
+ console.log(` Path: ${plugin.path}`);
363
+ if (plugin.commands.size > 0) {
364
+ console.log(` Commands: ${Array.from(plugin.commands.keys()).join(', ')}`);
365
+ }
366
+ if (plugin.tools.size > 0) {
367
+ console.log(` Tools: ${Array.from(plugin.tools.keys()).join(', ')}`);
368
+ }
369
+ if (plugin.agents.size > 0) {
370
+ console.log(` Agents: ${Array.from(plugin.agents.keys()).join(', ')}`);
371
+ }
372
+ console.log();
373
+ return;
374
+ }
375
+
376
+ // List plugins
377
+ const plugins = pluginLoader.getPlugins();
378
+ if (plugins.length === 0) {
379
+ console.log('\nšŸ“¦ No plugins installed.\n');
380
+ console.log('To install plugins, create a directory at:');
381
+ console.log(' ~/.bluehawks/plugins/<plugin-name>/plugin.json\n');
382
+ return;
383
+ }
384
+
385
+ console.log('\nšŸ“¦ Installed Plugins:\n');
386
+ for (const plugin of plugins) {
387
+ console.log(` ${plugin.manifest.name} v${plugin.manifest.version}`);
388
+ if (plugin.manifest.description) {
389
+ console.log(` ${plugin.manifest.description}`);
390
+ }
391
+ }
392
+ console.log();
393
+ });
394
+
395
+ // Version info
396
+ program
397
+ .command('version')
398
+ .description('Show version information')
399
+ .action(() => {
400
+ console.log(`\nšŸ¦… ${CLI_NAME}`);
401
+ console.log(` Version: ${CLI_VERSION}`);
402
+ console.log(` Node.js: ${process.version}`);
403
+ console.log(` Platform: ${process.platform} ${process.arch}\n`);
404
+ });
405
+
406
+ // Parse arguments
407
+ program.parse();
package/tsconfig.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": [
7
+ "ES2022",
8
+ "DOM"
9
+ ],
10
+ "types": [
11
+ "node"
12
+ ],
13
+ "outDir": "dist",
14
+ "rootDir": "src",
15
+ "strict": true,
16
+ "esModuleInterop": true,
17
+ "skipLibCheck": true,
18
+ "forceConsistentCasingInFileNames": true,
19
+ "resolveJsonModule": true,
20
+ "declaration": true,
21
+ "declarationMap": true,
22
+ "sourceMap": true,
23
+ "jsx": "react-jsx",
24
+ "jsxImportSource": "react",
25
+ "noImplicitAny": true,
26
+ "noImplicitReturns": true,
27
+ "noUnusedLocals": true,
28
+ "noUnusedParameters": true,
29
+ "exactOptionalPropertyTypes": false,
30
+ "noFallthroughCasesInSwitch": true
31
+ },
32
+ "include": [
33
+ "src/**/*"
34
+ ],
35
+ "exclude": [
36
+ "node_modules",
37
+ "dist",
38
+ "**/*.test.ts"
39
+ ]
40
+ }
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: true,
6
+ environment: 'node',
7
+ include: ['src/**/*.test.ts'],
8
+ coverage: {
9
+ provider: 'v8',
10
+ reporter: ['text', 'json', 'html'],
11
+ },
12
+ },
13
+ });