ultra-dex 3.1.0 → 3.3.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.
- package/README.md +79 -74
- package/assets/code-patterns/clerk-middleware.ts +138 -0
- package/assets/code-patterns/prisma-schema.prisma +224 -0
- package/assets/code-patterns/rls-policies.sql +246 -0
- package/assets/code-patterns/server-actions.ts +191 -0
- package/assets/code-patterns/trpc-router.ts +258 -0
- package/assets/cursor-rules/13-ai-integration.mdc +155 -0
- package/assets/cursor-rules/14-server-components.mdc +81 -0
- package/assets/cursor-rules/15-server-actions.mdc +102 -0
- package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
- package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
- package/bin/ultra-dex.js +50 -1
- package/lib/commands/agents.js +16 -13
- package/lib/commands/banner.js +43 -21
- package/lib/commands/build.js +26 -17
- package/lib/commands/cloud.js +780 -0
- package/lib/commands/doctor.js +98 -79
- package/lib/commands/exec.js +434 -0
- package/lib/commands/generate.js +19 -16
- package/lib/commands/github.js +475 -0
- package/lib/commands/init.js +52 -56
- package/lib/commands/scaffold.js +151 -0
- package/lib/commands/search.js +477 -0
- package/lib/commands/serve.js +15 -13
- package/lib/commands/state.js +43 -70
- package/lib/commands/swarm.js +31 -9
- package/lib/config/theme.js +47 -0
- package/lib/mcp/client.js +502 -0
- package/lib/providers/agent-sdk.js +630 -0
- package/lib/providers/anthropic-agents.js +580 -0
- package/lib/templates/code/clerk-middleware.ts +138 -0
- package/lib/templates/code/prisma-schema.prisma +224 -0
- package/lib/templates/code/rls-policies.sql +246 -0
- package/lib/templates/code/server-actions.ts +191 -0
- package/lib/templates/code/trpc-router.ts +258 -0
- package/lib/themes/doomsday.js +229 -0
- package/lib/ui/index.js +5 -0
- package/lib/ui/interface.js +241 -0
- package/lib/ui/spinners.js +116 -0
- package/lib/ui/theme.js +183 -0
- package/lib/utils/agents.js +32 -0
- package/lib/utils/browser.js +373 -0
- package/lib/utils/help.js +64 -0
- package/lib/utils/messages.js +35 -0
- package/lib/utils/progress.js +24 -0
- package/lib/utils/prompts.js +47 -0
- package/lib/utils/spinners.js +46 -0
- package/lib/utils/status.js +31 -0
- package/lib/utils/tables.js +41 -0
- package/lib/utils/theme-state.js +9 -0
- package/lib/utils/version-display.js +32 -0
- package/package.json +19 -4
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Automation Module (Playwright-based)
|
|
3
|
+
* Enables Research agent to browse the web, take screenshots, and interact with pages
|
|
4
|
+
* This is what makes Ultra-Dex truly intelligent - it can LEARN from the web
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import fs from 'fs/promises';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// BROWSER CONFIGURATION
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
const BROWSER_CONFIG = {
|
|
16
|
+
// Default browser settings
|
|
17
|
+
headless: true,
|
|
18
|
+
timeout: 30000,
|
|
19
|
+
viewport: { width: 1280, height: 720 },
|
|
20
|
+
|
|
21
|
+
// Screenshot settings
|
|
22
|
+
screenshotDir: '.ultra-dex/screenshots',
|
|
23
|
+
|
|
24
|
+
// User agent
|
|
25
|
+
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Ultra-Dex/3.2.0 Research Agent',
|
|
26
|
+
|
|
27
|
+
// Blocked resources (for faster loading)
|
|
28
|
+
blockedResources: ['image', 'stylesheet', 'font', 'media'],
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// BROWSER AUTOMATION CLASS
|
|
33
|
+
// ============================================================================
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Browser automation for Research agent
|
|
37
|
+
* Uses Playwright for reliable cross-browser automation
|
|
38
|
+
*/
|
|
39
|
+
export class BrowserAutomation {
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
this.options = { ...BROWSER_CONFIG, ...options };
|
|
42
|
+
this.browser = null;
|
|
43
|
+
this.context = null;
|
|
44
|
+
this.page = null;
|
|
45
|
+
this.playwright = null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Launch browser
|
|
50
|
+
*/
|
|
51
|
+
async launch() {
|
|
52
|
+
try {
|
|
53
|
+
// Dynamic import of playwright
|
|
54
|
+
const { chromium } = await import('playwright');
|
|
55
|
+
this.playwright = { chromium };
|
|
56
|
+
|
|
57
|
+
this.browser = await chromium.launch({
|
|
58
|
+
headless: this.options.headless,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
this.context = await this.browser.newContext({
|
|
62
|
+
userAgent: this.options.userAgent,
|
|
63
|
+
viewport: this.options.viewport,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Block unnecessary resources for faster loading
|
|
67
|
+
if (this.options.blockedResources.length > 0) {
|
|
68
|
+
await this.context.route('**/*', (route) => {
|
|
69
|
+
if (this.options.blockedResources.includes(route.request().resourceType())) {
|
|
70
|
+
route.abort();
|
|
71
|
+
} else {
|
|
72
|
+
route.continue();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.page = await this.context.newPage();
|
|
78
|
+
this.page.setDefaultTimeout(this.options.timeout);
|
|
79
|
+
|
|
80
|
+
return true;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
console.log(chalk.yellow(`Browser launch failed: ${err.message}`));
|
|
83
|
+
console.log(chalk.gray('Install Playwright: npm install playwright'));
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Close browser
|
|
90
|
+
*/
|
|
91
|
+
async close() {
|
|
92
|
+
if (this.browser) {
|
|
93
|
+
await this.browser.close();
|
|
94
|
+
this.browser = null;
|
|
95
|
+
this.context = null;
|
|
96
|
+
this.page = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Navigate to URL
|
|
102
|
+
*/
|
|
103
|
+
async navigate(url) {
|
|
104
|
+
if (!this.page) {
|
|
105
|
+
await this.launch();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await this.page.goto(url, { waitUntil: 'domcontentloaded' });
|
|
109
|
+
return { url: this.page.url(), title: await this.page.title() };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get page content (text extraction)
|
|
114
|
+
*/
|
|
115
|
+
async getPageContent(url) {
|
|
116
|
+
await this.navigate(url);
|
|
117
|
+
|
|
118
|
+
// Extract text content
|
|
119
|
+
const content = await this.page.evaluate(() => {
|
|
120
|
+
// Remove scripts and styles
|
|
121
|
+
const scripts = document.querySelectorAll('script, style, noscript');
|
|
122
|
+
scripts.forEach(el => el.remove());
|
|
123
|
+
|
|
124
|
+
// Get main content areas
|
|
125
|
+
const mainContent = document.querySelector('main, article, .content, #content, .main');
|
|
126
|
+
const target = mainContent || document.body;
|
|
127
|
+
|
|
128
|
+
// Extract text
|
|
129
|
+
const text = target.innerText || target.textContent || '';
|
|
130
|
+
|
|
131
|
+
// Clean up whitespace
|
|
132
|
+
return text
|
|
133
|
+
.replace(/\s+/g, ' ')
|
|
134
|
+
.replace(/\n\s*\n/g, '\n')
|
|
135
|
+
.trim()
|
|
136
|
+
.substring(0, 50000); // Limit content size
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Extract links
|
|
140
|
+
const links = await this.page.evaluate(() => {
|
|
141
|
+
return Array.from(document.querySelectorAll('a[href]'))
|
|
142
|
+
.slice(0, 50)
|
|
143
|
+
.map(a => ({
|
|
144
|
+
text: a.innerText?.trim().substring(0, 100),
|
|
145
|
+
href: a.href,
|
|
146
|
+
}))
|
|
147
|
+
.filter(l => l.text && l.href.startsWith('http'));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Extract headings
|
|
151
|
+
const headings = await this.page.evaluate(() => {
|
|
152
|
+
return Array.from(document.querySelectorAll('h1, h2, h3'))
|
|
153
|
+
.slice(0, 20)
|
|
154
|
+
.map(h => ({
|
|
155
|
+
level: h.tagName.toLowerCase(),
|
|
156
|
+
text: h.innerText?.trim().substring(0, 200),
|
|
157
|
+
}))
|
|
158
|
+
.filter(h => h.text);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
url: this.page.url(),
|
|
163
|
+
title: await this.page.title(),
|
|
164
|
+
content: content.substring(0, 20000), // Limit for context window
|
|
165
|
+
headings,
|
|
166
|
+
links: links.slice(0, 20),
|
|
167
|
+
wordCount: content.split(/\s+/).length,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Take screenshot
|
|
173
|
+
*/
|
|
174
|
+
async screenshot(url, options = {}) {
|
|
175
|
+
await this.navigate(url);
|
|
176
|
+
|
|
177
|
+
const { fullPage = false, path: customPath } = options;
|
|
178
|
+
|
|
179
|
+
// Ensure screenshot directory exists
|
|
180
|
+
await fs.mkdir(this.options.screenshotDir, { recursive: true });
|
|
181
|
+
|
|
182
|
+
// Generate filename
|
|
183
|
+
const timestamp = Date.now();
|
|
184
|
+
const filename = customPath || path.join(
|
|
185
|
+
this.options.screenshotDir,
|
|
186
|
+
`screenshot-${timestamp}.png`
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
await this.page.screenshot({
|
|
190
|
+
path: filename,
|
|
191
|
+
fullPage,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
path: filename,
|
|
196
|
+
url: this.page.url(),
|
|
197
|
+
title: await this.page.title(),
|
|
198
|
+
timestamp: new Date().toISOString(),
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Click an element
|
|
204
|
+
*/
|
|
205
|
+
async click(selector) {
|
|
206
|
+
await this.page.click(selector);
|
|
207
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
clicked: selector,
|
|
211
|
+
url: this.page.url(),
|
|
212
|
+
title: await this.page.title(),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Fill a form field
|
|
218
|
+
*/
|
|
219
|
+
async fill(selector, value) {
|
|
220
|
+
await this.page.fill(selector, value);
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
filled: selector,
|
|
224
|
+
value: value.substring(0, 50), // Don't expose full value
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Wait for selector
|
|
230
|
+
*/
|
|
231
|
+
async waitFor(selector, options = {}) {
|
|
232
|
+
const { timeout = 10000, state = 'visible' } = options;
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await this.page.waitForSelector(selector, { timeout, state });
|
|
236
|
+
return { success: true, selector };
|
|
237
|
+
} catch {
|
|
238
|
+
return { success: false, selector, error: 'Timeout waiting for element' };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Execute JavaScript on page
|
|
244
|
+
*/
|
|
245
|
+
async evaluate(script) {
|
|
246
|
+
const result = await this.page.evaluate(script);
|
|
247
|
+
return { result };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Get page metadata
|
|
252
|
+
*/
|
|
253
|
+
async getMetadata(url) {
|
|
254
|
+
await this.navigate(url);
|
|
255
|
+
|
|
256
|
+
const metadata = await this.page.evaluate(() => {
|
|
257
|
+
const getMeta = (name) => {
|
|
258
|
+
const el = document.querySelector(`meta[name="${name}"], meta[property="${name}"]`);
|
|
259
|
+
return el?.getAttribute('content') || null;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
title: document.title,
|
|
264
|
+
description: getMeta('description') || getMeta('og:description'),
|
|
265
|
+
keywords: getMeta('keywords'),
|
|
266
|
+
author: getMeta('author'),
|
|
267
|
+
ogImage: getMeta('og:image'),
|
|
268
|
+
ogTitle: getMeta('og:title'),
|
|
269
|
+
canonical: document.querySelector('link[rel="canonical"]')?.href,
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
return { url: this.page.url(), ...metadata };
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Search Google and get results
|
|
278
|
+
*/
|
|
279
|
+
async searchGoogle(query) {
|
|
280
|
+
const searchUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}`;
|
|
281
|
+
await this.navigate(searchUrl);
|
|
282
|
+
|
|
283
|
+
// Wait for results
|
|
284
|
+
await this.page.waitForSelector('#search', { timeout: 10000 }).catch(() => {});
|
|
285
|
+
|
|
286
|
+
const results = await this.page.evaluate(() => {
|
|
287
|
+
const items = document.querySelectorAll('#search .g');
|
|
288
|
+
return Array.from(items).slice(0, 10).map(item => {
|
|
289
|
+
const linkEl = item.querySelector('a');
|
|
290
|
+
const titleEl = item.querySelector('h3');
|
|
291
|
+
const snippetEl = item.querySelector('.VwiC3b');
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
title: titleEl?.innerText || '',
|
|
295
|
+
url: linkEl?.href || '',
|
|
296
|
+
snippet: snippetEl?.innerText || '',
|
|
297
|
+
};
|
|
298
|
+
}).filter(r => r.url && r.title);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
return { query, results };
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Fetch documentation from common sources
|
|
306
|
+
*/
|
|
307
|
+
async fetchDocs(library, topic = '') {
|
|
308
|
+
const docSources = {
|
|
309
|
+
react: 'https://react.dev/reference',
|
|
310
|
+
nextjs: 'https://nextjs.org/docs',
|
|
311
|
+
prisma: 'https://www.prisma.io/docs',
|
|
312
|
+
typescript: 'https://www.typescriptlang.org/docs',
|
|
313
|
+
tailwind: 'https://tailwindcss.com/docs',
|
|
314
|
+
node: 'https://nodejs.org/docs/latest/api',
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const baseUrl = docSources[library.toLowerCase()];
|
|
318
|
+
if (!baseUrl) {
|
|
319
|
+
// Fall back to Google search
|
|
320
|
+
return this.searchGoogle(`${library} ${topic} documentation`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const url = topic ? `${baseUrl}/${topic}` : baseUrl;
|
|
324
|
+
return this.getPageContent(url);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ============================================================================
|
|
329
|
+
// LIGHTWEIGHT FETCH (No Browser)
|
|
330
|
+
// ============================================================================
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Simple HTTP fetch for when browser is overkill
|
|
334
|
+
*/
|
|
335
|
+
export async function simpleFetch(url) {
|
|
336
|
+
const response = await fetch(url, {
|
|
337
|
+
headers: {
|
|
338
|
+
'User-Agent': BROWSER_CONFIG.userAgent,
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
const contentType = response.headers.get('content-type') || '';
|
|
343
|
+
|
|
344
|
+
if (contentType.includes('application/json')) {
|
|
345
|
+
return { type: 'json', data: await response.json() };
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const text = await response.text();
|
|
349
|
+
|
|
350
|
+
// Simple HTML to text conversion
|
|
351
|
+
if (contentType.includes('text/html')) {
|
|
352
|
+
const cleaned = text
|
|
353
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
|
354
|
+
.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '')
|
|
355
|
+
.replace(/<[^>]+>/g, ' ')
|
|
356
|
+
.replace(/\s+/g, ' ')
|
|
357
|
+
.trim();
|
|
358
|
+
|
|
359
|
+
return { type: 'html', data: cleaned.substring(0, 50000) };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return { type: 'text', data: text.substring(0, 50000) };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// ============================================================================
|
|
366
|
+
// EXPORTS
|
|
367
|
+
// ============================================================================
|
|
368
|
+
|
|
369
|
+
export default {
|
|
370
|
+
BrowserAutomation,
|
|
371
|
+
simpleFetch,
|
|
372
|
+
BROWSER_CONFIG,
|
|
373
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import gradient from 'gradient-string';
|
|
3
|
+
import { isDoomsdayMode } from './theme-state.js';
|
|
4
|
+
import { showHelp as showDoomsdayHelp } from '../themes/doomsday.js';
|
|
5
|
+
|
|
6
|
+
const ultraGradient = gradient(['#6366f1', '#8b5cf6', '#d946ef']);
|
|
7
|
+
|
|
8
|
+
export function showHelp() {
|
|
9
|
+
if (isDoomsdayMode()) {
|
|
10
|
+
return showDoomsdayHelp();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log('');
|
|
14
|
+
console.log(ultraGradient(' ═══════════════════════════════════════════════'));
|
|
15
|
+
console.log(ultraGradient(' ║ U L T R A - D E X : O R C H E S T R A T I O N'));
|
|
16
|
+
console.log(ultraGradient(' ═══════════════════════════════════════════════'));
|
|
17
|
+
console.log('');
|
|
18
|
+
|
|
19
|
+
const sections = [
|
|
20
|
+
{
|
|
21
|
+
title: '🚀 PROJECT SETUP',
|
|
22
|
+
commands: [
|
|
23
|
+
['init', 'Initialize new project'],
|
|
24
|
+
['generate', 'Generate implementation plan'],
|
|
25
|
+
['swarm', 'Run agent pipeline']
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
title: '🛡️ QUALITY & DEFENSE',
|
|
30
|
+
commands: [
|
|
31
|
+
['review', 'Run code review'],
|
|
32
|
+
['validate', 'Check project integrity'],
|
|
33
|
+
['hooks', 'Install git hooks']
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: '⚡ ACTIVE KERNEL',
|
|
38
|
+
commands: [
|
|
39
|
+
['serve', 'Start MCP server & dashboard'],
|
|
40
|
+
['dashboard', 'Open web dashboard'],
|
|
41
|
+
['agents', 'List available agents']
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
title: '📦 DEPLOYMENT',
|
|
46
|
+
commands: [
|
|
47
|
+
['build', 'Execute next task'],
|
|
48
|
+
['deploy', 'Deploy application'],
|
|
49
|
+
['doctor', 'System diagnostics']
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
sections.forEach(section => {
|
|
55
|
+
console.log(` ${chalk.hex('#8b5cf6').bold(section.title)}`);
|
|
56
|
+
section.commands.forEach(([cmd, desc]) => {
|
|
57
|
+
console.log(` ${chalk.hex('#6366f1')(cmd.padEnd(16))} ${chalk.dim(desc)}`);
|
|
58
|
+
});
|
|
59
|
+
console.log('');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log(chalk.dim(' "AI Orchestration Meta-Layer for Professional SaaS Development"'));
|
|
63
|
+
console.log('');
|
|
64
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// cli/lib/utils/messages.js
|
|
2
|
+
export const professionalMessages = {
|
|
3
|
+
start: [
|
|
4
|
+
"AI Orchestration initialized. Ready for mission.",
|
|
5
|
+
"Analyzing project graph for optimal path...",
|
|
6
|
+
"System check complete. Starting task execution.",
|
|
7
|
+
"Leveraging 16 specialized agents for development."
|
|
8
|
+
],
|
|
9
|
+
|
|
10
|
+
success: [
|
|
11
|
+
"✓ Task completed successfully. Alignment verified.",
|
|
12
|
+
"✓ System integrity confirmed. Code merged.",
|
|
13
|
+
"✓ Orchestration successful. Results saved.",
|
|
14
|
+
"✓ Professional SaaS standards achieved."
|
|
15
|
+
],
|
|
16
|
+
|
|
17
|
+
error: [
|
|
18
|
+
"✕ Task failed. Analyzing logs for recovery...",
|
|
19
|
+
"✕ System anomaly detected. Diagnostic required.",
|
|
20
|
+
"✕ Orchestration interrupted. Please check configuration.",
|
|
21
|
+
"✕ Quality gate failed. Refactoring recommended."
|
|
22
|
+
],
|
|
23
|
+
|
|
24
|
+
loading: [
|
|
25
|
+
"Initializing agent pipeline...",
|
|
26
|
+
"Scanning project context...",
|
|
27
|
+
"Optimizing orchestration logic...",
|
|
28
|
+
"Verifying system state..."
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export function getRandomMessage(type) {
|
|
33
|
+
const messages = professionalMessages[type];
|
|
34
|
+
return messages[Math.floor(Math.random() * messages.length)];
|
|
35
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
|
|
4
|
+
export function showProgress(tasks) {
|
|
5
|
+
const total = tasks.length;
|
|
6
|
+
console.log('');
|
|
7
|
+
console.log(chalk.hex('#8b5cf6').bold(' ⚡ EXECUTING TASKS...'));
|
|
8
|
+
console.log('');
|
|
9
|
+
|
|
10
|
+
tasks.forEach((task, idx) => {
|
|
11
|
+
// Simple vertical list for now
|
|
12
|
+
console.log(` ${chalk.hex('#d946ef')('►')} ${task}`);
|
|
13
|
+
});
|
|
14
|
+
console.log('');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function progressBar(current, total, width = 40) {
|
|
18
|
+
const percentage = Math.round((current / total) * 100);
|
|
19
|
+
const filled = Math.round((current / total) * width);
|
|
20
|
+
const empty = width - filled;
|
|
21
|
+
|
|
22
|
+
const bar = chalk.hex('#6366f1')('█'.repeat(filled)) + chalk.dim('░'.repeat(empty));
|
|
23
|
+
return `${bar} ${chalk.hex('#d946ef')(percentage + '%')}`;
|
|
24
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import gradient from 'gradient-string';
|
|
4
|
+
|
|
5
|
+
export async function selectAgent() {
|
|
6
|
+
const agents = [
|
|
7
|
+
{ name: '🏛️ CTO - Architecture decisions', value: 'cto' },
|
|
8
|
+
{ name: '📋 Planner - Task breakdown', value: 'planner' },
|
|
9
|
+
{ name: '🔧 Backend - API & server', value: 'backend' },
|
|
10
|
+
{ name: '🎨 Frontend - UI components', value: 'frontend' },
|
|
11
|
+
{ name: '💾 Database - Schema & queries', value: 'database' },
|
|
12
|
+
{ name: '🔐 Auth - Authentication', value: 'auth' },
|
|
13
|
+
{ name: '🛡️ Security - Security review', value: 'security' },
|
|
14
|
+
{ name: '📝 Testing - Write tests', value: 'testing' },
|
|
15
|
+
{ name: '📖 Docs - Documentation', value: 'documentation' },
|
|
16
|
+
{ name: '👀 Reviewer - Code review', value: 'reviewer' }
|
|
17
|
+
];
|
|
18
|
+
const { agent } = await inquirer.prompt([{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'agent',
|
|
21
|
+
message: gradient(['#6366f1', '#8b5cf6'])('Select an agent:'),
|
|
22
|
+
choices: agents,
|
|
23
|
+
pageSize: 12
|
|
24
|
+
}]);
|
|
25
|
+
|
|
26
|
+
return agent;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function confirmAction(message) {
|
|
30
|
+
const { confirm } = await inquirer.prompt([{
|
|
31
|
+
type: 'confirm',
|
|
32
|
+
name: 'confirm',
|
|
33
|
+
message: chalk.yellow(message),
|
|
34
|
+
default: false
|
|
35
|
+
}]);
|
|
36
|
+
return confirm;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function inputText(message, defaultValue = '') {
|
|
40
|
+
const { value } = await inquirer.prompt([{
|
|
41
|
+
type: 'input',
|
|
42
|
+
name: 'value',
|
|
43
|
+
message: chalk.cyan(message),
|
|
44
|
+
default: defaultValue
|
|
45
|
+
}]);
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import ora from 'ora';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
const spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
5
|
+
|
|
6
|
+
export function createSpinner(text) {
|
|
7
|
+
return ora({
|
|
8
|
+
text: chalk.cyan(text),
|
|
9
|
+
spinner: {
|
|
10
|
+
interval: 80,
|
|
11
|
+
frames: spinnerFrames
|
|
12
|
+
},
|
|
13
|
+
color: 'magenta'
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function success(text) {
|
|
18
|
+
return ora().succeed(chalk.green(text));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function fail(text) {
|
|
22
|
+
return ora().fail(chalk.red(text));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function info(text) {
|
|
26
|
+
return ora().info(chalk.blue(text));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function warn(text) {
|
|
30
|
+
return ora().warn(chalk.yellow(text));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Task list with progress
|
|
34
|
+
export async function runTasks(tasks) {
|
|
35
|
+
for (const task of tasks) {
|
|
36
|
+
const spinner = createSpinner(task.title);
|
|
37
|
+
spinner.start();
|
|
38
|
+
try {
|
|
39
|
+
await task.fn();
|
|
40
|
+
spinner.succeed(chalk.green(task.title));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
spinner.fail(chalk.red(`${task.title}: ${error.message}`));
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import figures from 'figures';
|
|
3
|
+
|
|
4
|
+
export const icons = {
|
|
5
|
+
success: chalk.hex('#22c55e')(figures.tick),
|
|
6
|
+
error: chalk.hex('#ef4444')(figures.cross),
|
|
7
|
+
warning: chalk.hex('#f59e0b')(figures.warning),
|
|
8
|
+
info: chalk.hex('#6366f1')(figures.info),
|
|
9
|
+
pending: chalk.hex('#6b7280')(figures.circle),
|
|
10
|
+
running: chalk.hex('#d946ef')(figures.play),
|
|
11
|
+
pointer: chalk.hex('#8b5cf6')(figures.pointer),
|
|
12
|
+
bullet: chalk.dim(figures.bullet)
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export function showInfinityStatus() {
|
|
16
|
+
// Deprecated function, kept for compatibility if called elsewhere but showing nothing or simple status
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function statusLine(icon, text) {
|
|
20
|
+
console.log(` ${icon} ${text}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function header(text) {
|
|
24
|
+
console.log('');
|
|
25
|
+
console.log(chalk.bold.hex('#8b5cf6')(` ${text}`));
|
|
26
|
+
console.log(chalk.dim(' ' + '─'.repeat(50)));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function separator() {
|
|
30
|
+
console.log('');
|
|
31
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import Table from 'cli-table3';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import gradient from 'gradient-string';
|
|
4
|
+
|
|
5
|
+
export function createTable(headers, rows) {
|
|
6
|
+
const table = new Table({
|
|
7
|
+
head: headers.map(h => gradient(['#6366f1', '#8b5cf6'])(h)),
|
|
8
|
+
chars: {
|
|
9
|
+
'top': '─', 'top-mid': '┬', 'top-left': '╭', 'top-right': '╮',
|
|
10
|
+
'bottom': '─', 'bottom-mid': '┴', 'bottom-left': '╰', 'bottom-right': '╯',
|
|
11
|
+
'left': '│', 'left-mid': '├', 'mid': '─', 'mid-mid': '┼',
|
|
12
|
+
'right': '│', 'right-mid': '┤', 'middle': '│'
|
|
13
|
+
},
|
|
14
|
+
style: {
|
|
15
|
+
head: ['magenta'],
|
|
16
|
+
border: ['dim']
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
rows.forEach(row => table.push(row));
|
|
21
|
+
return table.toString();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function showAgentsTable(agents) {
|
|
25
|
+
const headers = ['Tier', 'Agent', 'Status'];
|
|
26
|
+
const rows = agents.map(a => [
|
|
27
|
+
chalk.dim(a.tier || 'N/A'),
|
|
28
|
+
chalk.cyan(a.name),
|
|
29
|
+
a.status === 'ready' ? chalk.green('●') : chalk.yellow('○')
|
|
30
|
+
]);
|
|
31
|
+
console.log(createTable(headers, rows));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function showCommandsTable(commands) {
|
|
35
|
+
const headers = ['Command', 'Description'];
|
|
36
|
+
const rows = commands.map(c => [
|
|
37
|
+
chalk.cyan(c.name),
|
|
38
|
+
chalk.dim(c.description)
|
|
39
|
+
]);
|
|
40
|
+
console.log(createTable(headers, rows));
|
|
41
|
+
}
|