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.
Files changed (52) hide show
  1. package/README.md +79 -74
  2. package/assets/code-patterns/clerk-middleware.ts +138 -0
  3. package/assets/code-patterns/prisma-schema.prisma +224 -0
  4. package/assets/code-patterns/rls-policies.sql +246 -0
  5. package/assets/code-patterns/server-actions.ts +191 -0
  6. package/assets/code-patterns/trpc-router.ts +258 -0
  7. package/assets/cursor-rules/13-ai-integration.mdc +155 -0
  8. package/assets/cursor-rules/14-server-components.mdc +81 -0
  9. package/assets/cursor-rules/15-server-actions.mdc +102 -0
  10. package/assets/cursor-rules/16-edge-middleware.mdc +105 -0
  11. package/assets/cursor-rules/17-streaming-ssr.mdc +138 -0
  12. package/bin/ultra-dex.js +50 -1
  13. package/lib/commands/agents.js +16 -13
  14. package/lib/commands/banner.js +43 -21
  15. package/lib/commands/build.js +26 -17
  16. package/lib/commands/cloud.js +780 -0
  17. package/lib/commands/doctor.js +98 -79
  18. package/lib/commands/exec.js +434 -0
  19. package/lib/commands/generate.js +19 -16
  20. package/lib/commands/github.js +475 -0
  21. package/lib/commands/init.js +52 -56
  22. package/lib/commands/scaffold.js +151 -0
  23. package/lib/commands/search.js +477 -0
  24. package/lib/commands/serve.js +15 -13
  25. package/lib/commands/state.js +43 -70
  26. package/lib/commands/swarm.js +31 -9
  27. package/lib/config/theme.js +47 -0
  28. package/lib/mcp/client.js +502 -0
  29. package/lib/providers/agent-sdk.js +630 -0
  30. package/lib/providers/anthropic-agents.js +580 -0
  31. package/lib/templates/code/clerk-middleware.ts +138 -0
  32. package/lib/templates/code/prisma-schema.prisma +224 -0
  33. package/lib/templates/code/rls-policies.sql +246 -0
  34. package/lib/templates/code/server-actions.ts +191 -0
  35. package/lib/templates/code/trpc-router.ts +258 -0
  36. package/lib/themes/doomsday.js +229 -0
  37. package/lib/ui/index.js +5 -0
  38. package/lib/ui/interface.js +241 -0
  39. package/lib/ui/spinners.js +116 -0
  40. package/lib/ui/theme.js +183 -0
  41. package/lib/utils/agents.js +32 -0
  42. package/lib/utils/browser.js +373 -0
  43. package/lib/utils/help.js +64 -0
  44. package/lib/utils/messages.js +35 -0
  45. package/lib/utils/progress.js +24 -0
  46. package/lib/utils/prompts.js +47 -0
  47. package/lib/utils/spinners.js +46 -0
  48. package/lib/utils/status.js +31 -0
  49. package/lib/utils/tables.js +41 -0
  50. package/lib/utils/theme-state.js +9 -0
  51. package/lib/utils/version-display.js +32 -0
  52. package/package.json +19 -4
@@ -0,0 +1,477 @@
1
+ /**
2
+ * ultra-dex search command
3
+ * Semantic code search using vector embeddings
4
+ * This enables AI to UNDERSTAND your codebase, not just pattern match
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import ora from 'ora';
9
+ import fs from 'fs/promises';
10
+ import path from 'path';
11
+ import { glob } from 'glob';
12
+ import { createProvider, getDefaultProvider, checkConfiguredProviders } from '../providers/index.js';
13
+
14
+ // ============================================================================
15
+ // VECTOR STORE CONFIGURATION
16
+ // ============================================================================
17
+
18
+ const EMBEDDINGS_CONFIG = {
19
+ // File patterns to index
20
+ includePatterns: [
21
+ '**/*.js', '**/*.ts', '**/*.tsx', '**/*.jsx',
22
+ '**/*.py', '**/*.go', '**/*.rs', '**/*.rb',
23
+ '**/*.md', '**/*.json', '**/*.yaml', '**/*.yml',
24
+ '**/*.prisma', '**/*.sql', '**/*.graphql',
25
+ ],
26
+
27
+ // Directories to exclude
28
+ excludeDirs: [
29
+ 'node_modules', '.git', 'dist', 'build', '.next',
30
+ 'coverage', '__pycache__', '.venv', 'vendor',
31
+ '.ultra-dex', '.ultra',
32
+ ],
33
+
34
+ // Chunk settings
35
+ chunkSize: 1000, // characters per chunk
36
+ chunkOverlap: 200,
37
+
38
+ // Index file location
39
+ indexPath: '.ultra-dex/embeddings.json',
40
+ };
41
+
42
+ // ============================================================================
43
+ // SIMPLE VECTOR STORE (In-Memory + File Persistence)
44
+ // ============================================================================
45
+
46
+ class VectorStore {
47
+ constructor() {
48
+ this.documents = []; // { id, path, content, embedding, chunk }
49
+ this.metadata = {
50
+ createdAt: null,
51
+ updatedAt: null,
52
+ fileCount: 0,
53
+ chunkCount: 0,
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Cosine similarity between two vectors
59
+ */
60
+ cosineSimilarity(a, b) {
61
+ if (!a || !b || a.length !== b.length) return 0;
62
+
63
+ let dotProduct = 0;
64
+ let normA = 0;
65
+ let normB = 0;
66
+
67
+ for (let i = 0; i < a.length; i++) {
68
+ dotProduct += a[i] * b[i];
69
+ normA += a[i] * a[i];
70
+ normB += b[i] * b[i];
71
+ }
72
+
73
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
74
+ }
75
+
76
+ /**
77
+ * Add document with embedding
78
+ */
79
+ addDocument(doc) {
80
+ this.documents.push(doc);
81
+ this.metadata.chunkCount = this.documents.length;
82
+ this.metadata.updatedAt = new Date().toISOString();
83
+ }
84
+
85
+ /**
86
+ * Search for similar documents
87
+ */
88
+ search(queryEmbedding, topK = 5) {
89
+ const results = this.documents.map(doc => ({
90
+ ...doc,
91
+ score: this.cosineSimilarity(queryEmbedding, doc.embedding),
92
+ }));
93
+
94
+ return results
95
+ .sort((a, b) => b.score - a.score)
96
+ .slice(0, topK);
97
+ }
98
+
99
+ /**
100
+ * Save to disk
101
+ */
102
+ async save(filepath) {
103
+ await fs.mkdir(path.dirname(filepath), { recursive: true });
104
+ await fs.writeFile(filepath, JSON.stringify({
105
+ metadata: this.metadata,
106
+ documents: this.documents,
107
+ }, null, 2));
108
+ }
109
+
110
+ /**
111
+ * Load from disk
112
+ */
113
+ async load(filepath) {
114
+ try {
115
+ const data = JSON.parse(await fs.readFile(filepath, 'utf8'));
116
+ this.metadata = data.metadata;
117
+ this.documents = data.documents;
118
+ return true;
119
+ } catch {
120
+ return false;
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Clear the store
126
+ */
127
+ clear() {
128
+ this.documents = [];
129
+ this.metadata = {
130
+ createdAt: null,
131
+ updatedAt: null,
132
+ fileCount: 0,
133
+ chunkCount: 0,
134
+ };
135
+ }
136
+ }
137
+
138
+ // Global store instance
139
+ const vectorStore = new VectorStore();
140
+
141
+ // ============================================================================
142
+ // TEXT CHUNKING
143
+ // ============================================================================
144
+
145
+ /**
146
+ * Split text into overlapping chunks
147
+ */
148
+ function chunkText(text, filepath) {
149
+ const chunks = [];
150
+ const { chunkSize, chunkOverlap } = EMBEDDINGS_CONFIG;
151
+
152
+ // If text is small enough, use as single chunk
153
+ if (text.length <= chunkSize) {
154
+ return [{
155
+ content: text,
156
+ path: filepath,
157
+ chunk: 0,
158
+ total: 1,
159
+ }];
160
+ }
161
+
162
+ let start = 0;
163
+ let chunkIndex = 0;
164
+
165
+ while (start < text.length) {
166
+ const end = Math.min(start + chunkSize, text.length);
167
+ const chunk = text.slice(start, end);
168
+
169
+ chunks.push({
170
+ content: chunk,
171
+ path: filepath,
172
+ chunk: chunkIndex,
173
+ total: Math.ceil(text.length / (chunkSize - chunkOverlap)),
174
+ });
175
+
176
+ start += chunkSize - chunkOverlap;
177
+ chunkIndex++;
178
+ }
179
+
180
+ return chunks;
181
+ }
182
+
183
+ // ============================================================================
184
+ // EMBEDDING GENERATION
185
+ // ============================================================================
186
+
187
+ /**
188
+ * Generate embeddings using AI provider
189
+ * Falls back to simple TF-IDF-like approach if no API key
190
+ */
191
+ async function generateEmbedding(text, provider = null) {
192
+ // If we have an OpenAI-compatible provider, use their embeddings API
193
+ if (provider && provider.getEmbedding) {
194
+ try {
195
+ return await provider.getEmbedding(text);
196
+ } catch (err) {
197
+ console.log(chalk.yellow(`Embedding API failed, using local fallback: ${err.message}`));
198
+ }
199
+ }
200
+
201
+ // Fallback: Simple bag-of-words embedding
202
+ // This is a basic implementation - real embeddings would be much better
203
+ return generateLocalEmbedding(text);
204
+ }
205
+
206
+ /**
207
+ * Simple local embedding using TF-IDF-like approach
208
+ * This is a fallback when no API is available
209
+ */
210
+ function generateLocalEmbedding(text, dimensions = 384) {
211
+ const words = text.toLowerCase()
212
+ .replace(/[^a-z0-9\s]/g, ' ')
213
+ .split(/\s+/)
214
+ .filter(w => w.length > 2);
215
+
216
+ // Create a simple hash-based embedding
217
+ const embedding = new Array(dimensions).fill(0);
218
+
219
+ for (const word of words) {
220
+ // Hash the word to get consistent positions
221
+ let hash = 0;
222
+ for (let i = 0; i < word.length; i++) {
223
+ hash = ((hash << 5) - hash) + word.charCodeAt(i);
224
+ hash = hash & hash; // Convert to 32bit integer
225
+ }
226
+
227
+ // Use hash to update multiple positions
228
+ for (let i = 0; i < 3; i++) {
229
+ const pos = Math.abs((hash + i * 127) % dimensions);
230
+ embedding[pos] += 1;
231
+ }
232
+ }
233
+
234
+ // Normalize
235
+ const magnitude = Math.sqrt(embedding.reduce((sum, val) => sum + val * val, 0));
236
+ if (magnitude > 0) {
237
+ for (let i = 0; i < dimensions; i++) {
238
+ embedding[i] /= magnitude;
239
+ }
240
+ }
241
+
242
+ return embedding;
243
+ }
244
+
245
+ // ============================================================================
246
+ // INDEXING
247
+ // ============================================================================
248
+
249
+ /**
250
+ * Index the codebase
251
+ */
252
+ export async function indexCodebase(workdir = process.cwd(), options = {}) {
253
+ const { force = false, verbose = false } = options;
254
+ const indexPath = path.join(workdir, EMBEDDINGS_CONFIG.indexPath);
255
+
256
+ // Check if index exists and is recent
257
+ if (!force) {
258
+ const loaded = await vectorStore.load(indexPath);
259
+ if (loaded) {
260
+ const indexAge = Date.now() - new Date(vectorStore.metadata.updatedAt).getTime();
261
+ const oneHour = 60 * 60 * 1000;
262
+
263
+ if (indexAge < oneHour) {
264
+ return {
265
+ cached: true,
266
+ files: vectorStore.metadata.fileCount,
267
+ chunks: vectorStore.metadata.chunkCount,
268
+ };
269
+ }
270
+ }
271
+ }
272
+
273
+ // Clear and rebuild
274
+ vectorStore.clear();
275
+ vectorStore.metadata.createdAt = new Date().toISOString();
276
+
277
+ // Find all files to index
278
+ const excludePattern = EMBEDDINGS_CONFIG.excludeDirs.map(d => `**/${d}/**`);
279
+ const files = [];
280
+
281
+ for (const pattern of EMBEDDINGS_CONFIG.includePatterns) {
282
+ const matches = await glob(pattern, {
283
+ cwd: workdir,
284
+ ignore: excludePattern,
285
+ nodir: true,
286
+ });
287
+ files.push(...matches);
288
+ }
289
+
290
+ // Deduplicate
291
+ const uniqueFiles = [...new Set(files)];
292
+ vectorStore.metadata.fileCount = uniqueFiles.length;
293
+
294
+ if (verbose) {
295
+ console.log(chalk.gray(`Found ${uniqueFiles.length} files to index`));
296
+ }
297
+
298
+ // Index each file
299
+ let chunkCount = 0;
300
+ for (const file of uniqueFiles) {
301
+ try {
302
+ const filepath = path.join(workdir, file);
303
+ const content = await fs.readFile(filepath, 'utf8');
304
+
305
+ // Skip very large files
306
+ if (content.length > 100000) {
307
+ if (verbose) console.log(chalk.gray(`Skipping large file: ${file}`));
308
+ continue;
309
+ }
310
+
311
+ // Chunk the content
312
+ const chunks = chunkText(content, file);
313
+
314
+ // Generate embeddings for each chunk
315
+ for (const chunk of chunks) {
316
+ const embedding = await generateEmbedding(chunk.content);
317
+
318
+ vectorStore.addDocument({
319
+ id: `${file}:${chunk.chunk}`,
320
+ path: chunk.path,
321
+ content: chunk.content,
322
+ embedding,
323
+ chunk: chunk.chunk,
324
+ total: chunk.total,
325
+ });
326
+
327
+ chunkCount++;
328
+ }
329
+ } catch (err) {
330
+ if (verbose) {
331
+ console.log(chalk.yellow(`Failed to index ${file}: ${err.message}`));
332
+ }
333
+ }
334
+ }
335
+
336
+ // Save index
337
+ await vectorStore.save(indexPath);
338
+
339
+ return {
340
+ cached: false,
341
+ files: uniqueFiles.length,
342
+ chunks: chunkCount,
343
+ };
344
+ }
345
+
346
+ /**
347
+ * Search the indexed codebase
348
+ */
349
+ export async function searchCodebase(query, options = {}) {
350
+ const { workdir = process.cwd(), topK = 10 } = options;
351
+ const indexPath = path.join(workdir, EMBEDDINGS_CONFIG.indexPath);
352
+
353
+ // Ensure index is loaded
354
+ if (vectorStore.documents.length === 0) {
355
+ const loaded = await vectorStore.load(indexPath);
356
+ if (!loaded) {
357
+ throw new Error('No index found. Run `ultra-dex search --index` first.');
358
+ }
359
+ }
360
+
361
+ // Generate query embedding
362
+ const queryEmbedding = await generateEmbedding(query);
363
+
364
+ // Search
365
+ const results = vectorStore.search(queryEmbedding, topK);
366
+
367
+ return results.map(r => ({
368
+ path: r.path,
369
+ chunk: r.chunk,
370
+ score: r.score,
371
+ preview: r.content.slice(0, 200) + (r.content.length > 200 ? '...' : ''),
372
+ }));
373
+ }
374
+
375
+ // ============================================================================
376
+ // CLI COMMAND
377
+ // ============================================================================
378
+
379
+ export function registerSearchCommand(program) {
380
+ program
381
+ .command('search [query]')
382
+ .description('Semantic search across your codebase using embeddings')
383
+ .option('--index', 'Rebuild the search index')
384
+ .option('--force', 'Force full re-index')
385
+ .option('-k, --top <n>', 'Number of results', '10')
386
+ .option('-v, --verbose', 'Show detailed output')
387
+ .option('--stats', 'Show index statistics')
388
+ .action(async (query, options) => {
389
+ console.log(chalk.cyan('\nšŸ” Ultra-Dex Semantic Search\n'));
390
+
391
+ const workdir = process.cwd();
392
+ const indexPath = path.join(workdir, EMBEDDINGS_CONFIG.indexPath);
393
+
394
+ if (options.stats) {
395
+ // Show index stats
396
+ const loaded = await vectorStore.load(indexPath);
397
+ if (!loaded) {
398
+ console.log(chalk.yellow('No index found.'));
399
+ return;
400
+ }
401
+
402
+ console.log(chalk.bold('Index Statistics:'));
403
+ console.log(` Created: ${vectorStore.metadata.createdAt}`);
404
+ console.log(` Updated: ${vectorStore.metadata.updatedAt}`);
405
+ console.log(` Files: ${vectorStore.metadata.fileCount}`);
406
+ console.log(` Chunks: ${vectorStore.metadata.chunkCount}`);
407
+ return;
408
+ }
409
+
410
+ if (options.index || !query) {
411
+ // Build/rebuild index
412
+ const spinner = ora('Indexing codebase...').start();
413
+
414
+ try {
415
+ const result = await indexCodebase(workdir, {
416
+ force: options.force,
417
+ verbose: options.verbose,
418
+ });
419
+
420
+ if (result.cached) {
421
+ spinner.succeed(`Using cached index (${result.files} files, ${result.chunks} chunks)`);
422
+ } else {
423
+ spinner.succeed(`Indexed ${result.files} files into ${result.chunks} chunks`);
424
+ }
425
+ } catch (err) {
426
+ spinner.fail(`Indexing failed: ${err.message}`);
427
+ return;
428
+ }
429
+
430
+ if (!query) {
431
+ console.log(chalk.gray('\nIndex ready. Use `ultra-dex search "your query"` to search.'));
432
+ return;
433
+ }
434
+ }
435
+
436
+ // Search
437
+ const spinner = ora(`Searching for: "${query}"`).start();
438
+
439
+ try {
440
+ const results = await searchCodebase(query, {
441
+ workdir,
442
+ topK: parseInt(options.top, 10),
443
+ });
444
+
445
+ spinner.succeed(`Found ${results.length} results\n`);
446
+
447
+ if (results.length === 0) {
448
+ console.log(chalk.yellow('No matches found. Try different keywords or rebuild the index.'));
449
+ return;
450
+ }
451
+
452
+ // Display results
453
+ for (let i = 0; i < results.length; i++) {
454
+ const r = results[i];
455
+ const scoreColor = r.score > 0.7 ? chalk.green : r.score > 0.4 ? chalk.yellow : chalk.gray;
456
+
457
+ console.log(chalk.bold(`${i + 1}. ${r.path}`) + chalk.gray(` (chunk ${r.chunk})`));
458
+ console.log(` Score: ${scoreColor(r.score.toFixed(3))}`);
459
+ console.log(chalk.gray(` ${r.preview.replace(/\n/g, ' ')}`));
460
+ console.log();
461
+ }
462
+
463
+ // Hint
464
+ console.log(chalk.gray('Tip: Use --index --force to rebuild embeddings if results seem stale.'));
465
+
466
+ } catch (err) {
467
+ spinner.fail(`Search failed: ${err.message}`);
468
+ }
469
+ });
470
+ }
471
+
472
+ export default {
473
+ registerSearchCommand,
474
+ indexCodebase,
475
+ searchCodebase,
476
+ vectorStore,
477
+ };
@@ -9,11 +9,12 @@ import { UltraDexSocket } from '../mcp/websocket.js';
9
9
  import { swarmCommand } from './swarm.js';
10
10
  import { glob } from 'glob';
11
11
  import { execSync, spawn } from 'child_process';
12
+ import { getRandomMessage } from '../utils/messages.js';
12
13
 
13
14
  export function registerServeCommand(program) {
14
15
  program
15
16
  .command('serve')
16
- .description('Start the Ultra-Dex Active Kernel (MCP + Dashboard + API)')
17
+ .description('Open the Multiverse Portal (Active Kernel)')
17
18
  .option('-p, --port <port>', 'Port to listen on', '3001')
18
19
  .option('--stdio', 'Run in Stdio mode (MCP Standard Only)', false)
19
20
  .action(async (options) => {
@@ -57,15 +58,16 @@ async function getDashboardHTML() {
57
58
  async function startUnifiedKernel(portStr) {
58
59
  const port = Number.parseInt(portStr, 10);
59
60
 
60
- console.log(chalk.bold.cyan('\nšŸš€ Ultra-Dex Active Kernel Starting (GOD MODE)...\n'));
61
+ console.log(chalk.bold.hex('#7c3aed')('\nšŸš€ Opening Multiverse Portal (Infinity Kernel)...\n'));
62
+ console.log(chalk.italic(chalk.gray(`"${getRandomMessage('loading')}"`)));
61
63
 
62
64
  // Initialize Graph
63
- console.log(chalk.gray('🧠 Initializing Neural Link (Code Graph)...'));
65
+ console.log(chalk.gray('🧠 Linking Neural Interface (Code Graph)...'));
64
66
  try {
65
67
  await projectGraph.scan();
66
- console.log(chalk.green(`āœ… Graph loaded: ${projectGraph.nodes.size} nodes`));
68
+ console.log(chalk.green(`āœ… Graph stabilized: ${projectGraph.nodes.size} nodes`));
67
69
  } catch (e) {
68
- console.log(chalk.yellow(`āš ļø Graph init failed: ${e.message}`));
70
+ console.log(chalk.yellow(`āš ļø Graph alignment failed: ${e.message}`));
69
71
  }
70
72
 
71
73
  const server = http.createServer(async (req, res) => {
@@ -96,8 +98,8 @@ async function startUnifiedKernel(portStr) {
96
98
  if (pathname === '/api/info') {
97
99
  res.writeHead(200, { 'Content-Type': 'application/json' });
98
100
  res.end(JSON.stringify({
99
- name: 'Ultra-Dex Active Kernel',
100
- version: '2.4.1',
101
+ name: 'Ultra-Dex Multiverse Kernel',
102
+ version: '3.1.0',
101
103
  status: 'online',
102
104
  endpoints: ['/api/state', '/api/plan', '/api/context', '/api/graph', '/api/swarm']
103
105
  }, null, 2));
@@ -134,7 +136,7 @@ async function startUnifiedKernel(portStr) {
134
136
  swarmCommand(objective, { parallel, dryRun: false }).catch(err => console.error(err));
135
137
 
136
138
  res.writeHead(202, { 'Content-Type': 'application/json' });
137
- res.end(JSON.stringify({ status: 'accepted', message: 'Swarm started' }));
139
+ res.end(JSON.stringify({ status: 'accepted', message: 'Swarm initiated' }));
138
140
  } catch (e) {
139
141
  res.writeHead(400, { 'Content-Type': 'application/json' });
140
142
  res.end(JSON.stringify({ error: e.message }));
@@ -159,13 +161,13 @@ async function startUnifiedKernel(portStr) {
159
161
  'Cache-Control': 'no-cache',
160
162
  'Connection': 'keep-alive'
161
163
  });
162
- res.write(`data: ${JSON.stringify({ type: 'log', message: 'Connected to Active Kernel' })}\n\n`);
164
+ res.write(`data: ${JSON.stringify({ type: 'log', message: 'Connected to Multiverse Kernel' })}\n\n`);
163
165
  // We'd need to manage clients here if we wanted to push updates
164
166
  return;
165
167
  }
166
168
 
167
169
  res.writeHead(404, { 'Content-Type': 'application/json' });
168
- res.end(JSON.stringify({ error: 'Not found' }));
170
+ res.end(JSON.stringify({ error: 'Not found in this timeline' }));
169
171
 
170
172
  } catch (error) {
171
173
  res.writeHead(500, { 'Content-Type': 'application/json' });
@@ -176,11 +178,11 @@ async function startUnifiedKernel(portStr) {
176
178
  const wss = new UltraDexSocket(server);
177
179
 
178
180
  server.listen(port, () => {
179
- console.log(chalk.green(`āœ… Unified Kernel active at http://localhost:${port}`));
181
+ console.log(chalk.green(`āœ… Portal Stabilized at http://localhost:${port}`));
180
182
  console.log(chalk.gray(` • Dashboard: http://localhost:${port}/`));
181
183
  console.log(chalk.gray(` • MCP API: http://localhost:${port}/api/info`));
182
184
 
183
- console.log(chalk.bold.magenta('\nšŸ”Œ AI Tool Integration:'));
185
+ console.log(chalk.bold.hex('#dc2626')('\nšŸ”Œ Weapon Integration (IDE):'));
184
186
  console.log(chalk.white(' Cursor IDE: '));
185
187
  console.log(chalk.cyan(` URL: http://localhost:${port}/api/info`));
186
188
  console.log(chalk.white(' Claude Desktop:'));
@@ -190,7 +192,7 @@ async function startUnifiedKernel(portStr) {
190
192
  fs.watch(process.cwd(), { recursive: true }, async (eventType, filename) => {
191
193
  if (!filename || filename.includes('node_modules') || filename.includes('.git') || filename.includes('IMPLEMENTATION-PLAN.md')) return;
192
194
 
193
- console.log(chalk.gray(`\nšŸ”„ Change in ${filename}. Synchronizing...`));
195
+ console.log(chalk.gray(`\nšŸ”„ Timeline Shift detected in ${filename}. Synchronizing...`));
194
196
  try {
195
197
  const state = await loadState();
196
198
  if (state) {