create-universal-ai-context 2.0.0 → 2.1.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 +55 -23
- package/bin/create-ai-context.js +159 -1
- package/lib/doc-discovery.js +741 -0
- package/lib/drift-checker.js +920 -0
- package/lib/index.js +89 -7
- package/lib/placeholder.js +11 -1
- package/lib/prompts.js +55 -1
- package/lib/smart-merge.js +540 -0
- package/lib/spinner.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,36 +29,68 @@ That's it. The CLI automatically:
|
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
# Basic usage
|
|
32
|
-
npx create-ai-context # Auto-detect and generate for all tools
|
|
32
|
+
npx create-universal-ai-context # Auto-detect and generate for all tools
|
|
33
33
|
|
|
34
34
|
# Select specific AI tools
|
|
35
|
-
npx create-ai-context --ai claude # Claude Code only
|
|
36
|
-
npx create-ai-context --ai copilot # GitHub Copilot only
|
|
37
|
-
npx create-ai-context --ai cline # Cline only
|
|
38
|
-
npx create-ai-context --ai antigravity # Antigravity only
|
|
39
|
-
npx create-ai-context --ai all # All tools (default)
|
|
35
|
+
npx create-universal-ai-context --ai claude # Claude Code only
|
|
36
|
+
npx create-universal-ai-context --ai copilot # GitHub Copilot only
|
|
37
|
+
npx create-universal-ai-context --ai cline # Cline only
|
|
38
|
+
npx create-universal-ai-context --ai antigravity # Antigravity only
|
|
39
|
+
npx create-universal-ai-context --ai all # All tools (default)
|
|
40
40
|
|
|
41
41
|
# Analysis modes
|
|
42
|
-
npx create-ai-context --static # Force static analysis only
|
|
43
|
-
npx create-ai-context --force-ai # Require Claude Code session
|
|
42
|
+
npx create-universal-ai-context --static # Force static analysis only
|
|
43
|
+
npx create-universal-ai-context --force-ai # Require Claude Code session
|
|
44
44
|
|
|
45
45
|
# Other options
|
|
46
|
-
npx create-ai-context --yes # Accept all defaults
|
|
47
|
-
npx create-ai-context --dry-run # Preview without changes
|
|
48
|
-
npx create-ai-context my-project # Create in new directory
|
|
46
|
+
npx create-universal-ai-context --yes # Accept all defaults
|
|
47
|
+
npx create-universal-ai-context --dry-run # Preview without changes
|
|
48
|
+
npx create-universal-ai-context my-project # Create in new directory
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
## Subcommands
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
# Generate context for specific tools
|
|
55
|
-
npx create-ai-context generate --ai copilot
|
|
55
|
+
npx create-universal-ai-context generate --ai copilot
|
|
56
56
|
|
|
57
57
|
# Check installation status
|
|
58
|
-
npx create-ai-context status
|
|
58
|
+
npx create-universal-ai-context status
|
|
59
59
|
|
|
60
60
|
# Migrate from v1.x
|
|
61
|
-
npx create-ai-context migrate
|
|
61
|
+
npx create-universal-ai-context migrate
|
|
62
|
+
|
|
63
|
+
# Check documentation drift
|
|
64
|
+
npx create-universal-ai-context drift --all # Check all docs
|
|
65
|
+
npx create-universal-ai-context drift --file README.md # Check specific file
|
|
66
|
+
npx create-universal-ai-context drift --fix # Auto-fix issues
|
|
67
|
+
npx create-universal-ai-context drift --strict # Exit 1 on issues (CI)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Existing Documentation Detection
|
|
71
|
+
|
|
72
|
+
The CLI automatically detects existing AI context files:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx create-universal-ai-context
|
|
76
|
+
|
|
77
|
+
# Found existing documentation: Claude context (v1), README.md
|
|
78
|
+
# ? How would you like to proceed?
|
|
79
|
+
# > Merge: Use existing docs as base, add new structure (recommended)
|
|
80
|
+
# Fresh: Start fresh but import key values
|
|
81
|
+
# Overwrite: Replace everything with new templates
|
|
82
|
+
# Skip: Cancel initialization
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Merge Mode Options
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx create-universal-ai-context --mode merge # Preserve customizations (default)
|
|
89
|
+
npx create-universal-ai-context --mode fresh # New structure, keep values
|
|
90
|
+
npx create-universal-ai-context --mode overwrite # Replace everything
|
|
91
|
+
npx create-universal-ai-context --preserve-custom # Keep user customizations
|
|
92
|
+
npx create-universal-ai-context --update-refs # Auto-fix line numbers
|
|
93
|
+
npx create-universal-ai-context --backup # Create backup first
|
|
62
94
|
```
|
|
63
95
|
|
|
64
96
|
## What Gets Analyzed
|
|
@@ -104,14 +136,14 @@ your-project/
|
|
|
104
136
|
## Tech Stack Presets
|
|
105
137
|
|
|
106
138
|
```bash
|
|
107
|
-
npx create-ai-context -t python-fastapi
|
|
108
|
-
npx create-ai-context -t python-django
|
|
109
|
-
npx create-ai-context -t node-express
|
|
110
|
-
npx create-ai-context -t node-nestjs
|
|
111
|
-
npx create-ai-context -t typescript-nextjs
|
|
112
|
-
npx create-ai-context -t go-gin
|
|
113
|
-
npx create-ai-context -t rust-actix
|
|
114
|
-
npx create-ai-context -t ruby-rails
|
|
139
|
+
npx create-universal-ai-context -t python-fastapi
|
|
140
|
+
npx create-universal-ai-context -t python-django
|
|
141
|
+
npx create-universal-ai-context -t node-express
|
|
142
|
+
npx create-universal-ai-context -t node-nestjs
|
|
143
|
+
npx create-universal-ai-context -t typescript-nextjs
|
|
144
|
+
npx create-universal-ai-context -t go-gin
|
|
145
|
+
npx create-universal-ai-context -t rust-actix
|
|
146
|
+
npx create-universal-ai-context -t ruby-rails
|
|
115
147
|
```
|
|
116
148
|
|
|
117
149
|
## Features
|
|
@@ -134,7 +166,7 @@ npx create-ai-context -t ruby-rails
|
|
|
134
166
|
If you have an existing `.claude/` directory:
|
|
135
167
|
|
|
136
168
|
```bash
|
|
137
|
-
npx create-ai-context migrate
|
|
169
|
+
npx create-universal-ai-context migrate
|
|
138
170
|
```
|
|
139
171
|
|
|
140
172
|
This will:
|
package/bin/create-ai-context.js
CHANGED
|
@@ -25,6 +25,12 @@ const { migrateV1ToV2, getMigrationStatus } = require('../lib/migrate');
|
|
|
25
25
|
const { detectTechStack } = require('../lib/detector');
|
|
26
26
|
const { analyzeCodebase } = require('../lib/static-analyzer');
|
|
27
27
|
const { createSpinner } = require('../lib/spinner');
|
|
28
|
+
const {
|
|
29
|
+
findDocumentationFiles,
|
|
30
|
+
generateDriftReport,
|
|
31
|
+
checkDocumentDrift,
|
|
32
|
+
formatDriftReportConsole
|
|
33
|
+
} = require('../lib/drift-checker');
|
|
28
34
|
const packageJson = require('../package.json');
|
|
29
35
|
|
|
30
36
|
// ASCII Banner
|
|
@@ -70,6 +76,10 @@ program
|
|
|
70
76
|
.option('--analyze-only', 'Run codebase analysis without installation')
|
|
71
77
|
.option('--monorepo', 'Initialize in monorepo mode with federation support')
|
|
72
78
|
.option('--federate', 'Run federation to generate context for subprojects')
|
|
79
|
+
.option('--mode <mode>', 'How to handle existing docs: merge, overwrite, interactive', 'merge')
|
|
80
|
+
.option('--preserve-custom', 'Keep user customizations when merging (default: true)', true)
|
|
81
|
+
.option('--update-refs', 'Auto-fix drifted line references')
|
|
82
|
+
.option('--backup', 'Create backup before modifying existing files')
|
|
73
83
|
.action(async (projectName, options) => {
|
|
74
84
|
console.log(banner);
|
|
75
85
|
|
|
@@ -94,7 +104,12 @@ program
|
|
|
94
104
|
forceStatic: options.static,
|
|
95
105
|
analyzeOnly: options.analyzeOnly,
|
|
96
106
|
monorepo: options.monorepo,
|
|
97
|
-
federate: options.federate
|
|
107
|
+
federate: options.federate,
|
|
108
|
+
// Merge options
|
|
109
|
+
mode: options.mode,
|
|
110
|
+
preserveCustom: options.preserveCustom,
|
|
111
|
+
updateRefs: options.updateRefs,
|
|
112
|
+
backup: options.backup
|
|
98
113
|
});
|
|
99
114
|
} catch (error) {
|
|
100
115
|
console.error(chalk.red('\n✖ Error:'), error.message);
|
|
@@ -334,4 +349,147 @@ program
|
|
|
334
349
|
}
|
|
335
350
|
});
|
|
336
351
|
|
|
352
|
+
// Drift subcommand - check documentation drift
|
|
353
|
+
program
|
|
354
|
+
.command('drift')
|
|
355
|
+
.description('Check documentation drift against codebase')
|
|
356
|
+
.option('-f, --file <path>', 'Check specific documentation file')
|
|
357
|
+
.option('-a, --all', 'Check all documentation files')
|
|
358
|
+
.option('--fix', 'Show suggested fixes for issues')
|
|
359
|
+
.option('--strict', 'Exit with error if drift detected')
|
|
360
|
+
.option('-o, --output <format>', 'Output format: console, json, markdown', 'console')
|
|
361
|
+
.option('-t, --threshold <percent>', 'Health score threshold for --strict', '70')
|
|
362
|
+
.option('-p, --path <dir>', 'Project directory (defaults to current)', '.')
|
|
363
|
+
.option('-v, --verbose', 'Show detailed output')
|
|
364
|
+
.action(async (options) => {
|
|
365
|
+
console.log(banner);
|
|
366
|
+
|
|
367
|
+
const projectRoot = path.resolve(options.path);
|
|
368
|
+
const spinner = createSpinner();
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
// Determine which files to check
|
|
372
|
+
let filesToCheck = [];
|
|
373
|
+
|
|
374
|
+
if (options.file) {
|
|
375
|
+
// Single file mode
|
|
376
|
+
filesToCheck = [options.file];
|
|
377
|
+
} else if (options.all) {
|
|
378
|
+
// All documentation files
|
|
379
|
+
spinner.start('Finding documentation files...');
|
|
380
|
+
filesToCheck = await findDocumentationFiles(projectRoot);
|
|
381
|
+
spinner.succeed(`Found ${filesToCheck.length} documentation files`);
|
|
382
|
+
} else {
|
|
383
|
+
// Default: check main context files
|
|
384
|
+
const defaultFiles = ['CLAUDE.md', 'AI_CONTEXT.md', 'README.md'];
|
|
385
|
+
filesToCheck = defaultFiles.filter(f =>
|
|
386
|
+
fs.existsSync(path.join(projectRoot, f))
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
if (filesToCheck.length === 0) {
|
|
390
|
+
console.log(chalk.yellow('\nNo documentation files found.'));
|
|
391
|
+
console.log(chalk.gray('Use --all to scan for all markdown files, or --file to check a specific file.'));
|
|
392
|
+
process.exit(0);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Generate drift report
|
|
397
|
+
spinner.start('Checking documentation drift...');
|
|
398
|
+
const report = generateDriftReport(filesToCheck, projectRoot);
|
|
399
|
+
spinner.succeed(`Checked ${report.summary.totalDocuments} documents`);
|
|
400
|
+
|
|
401
|
+
// Output results
|
|
402
|
+
if (options.output === 'json') {
|
|
403
|
+
console.log(JSON.stringify(report, null, 2));
|
|
404
|
+
} else if (options.output === 'markdown') {
|
|
405
|
+
console.log(formatDriftReportMarkdown(report));
|
|
406
|
+
} else {
|
|
407
|
+
// Console output
|
|
408
|
+
console.log(formatDriftReportConsole(report));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Show suggested fixes if requested
|
|
412
|
+
if (options.fix && report.suggestedFixes.length > 0) {
|
|
413
|
+
console.log(chalk.bold('\nSuggested Fixes:'));
|
|
414
|
+
for (const fix of report.suggestedFixes) {
|
|
415
|
+
console.log(chalk.cyan(`\n ${fix.document}:`));
|
|
416
|
+
console.log(chalk.red(` - ${fix.original}`));
|
|
417
|
+
console.log(chalk.green(` + ${fix.suggestion}`));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Strict mode - exit with error if below threshold
|
|
422
|
+
if (options.strict) {
|
|
423
|
+
const threshold = parseInt(options.threshold, 10);
|
|
424
|
+
if (report.summary.overallHealthScore < threshold) {
|
|
425
|
+
console.log(chalk.red(`\n✖ Health score ${report.summary.overallHealthScore}% is below threshold ${threshold}%`));
|
|
426
|
+
process.exit(1);
|
|
427
|
+
} else {
|
|
428
|
+
console.log(chalk.green(`\n✓ Health score ${report.summary.overallHealthScore}% meets threshold ${threshold}%`));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
} catch (error) {
|
|
433
|
+
spinner.fail('Drift check failed');
|
|
434
|
+
console.error(chalk.red('\n✖ Error:'), error.message);
|
|
435
|
+
if (options.verbose) {
|
|
436
|
+
console.error(chalk.gray(error.stack));
|
|
437
|
+
}
|
|
438
|
+
process.exit(1);
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Format drift report as markdown
|
|
444
|
+
*/
|
|
445
|
+
function formatDriftReportMarkdown(report) {
|
|
446
|
+
const lines = [
|
|
447
|
+
'# Documentation Drift Report',
|
|
448
|
+
'',
|
|
449
|
+
`**Generated:** ${report.generatedAt}`,
|
|
450
|
+
`**Overall Health:** ${report.summary.overallHealthScore}%`,
|
|
451
|
+
'',
|
|
452
|
+
'## Summary',
|
|
453
|
+
'',
|
|
454
|
+
'| Metric | Value |',
|
|
455
|
+
'|--------|-------|',
|
|
456
|
+
`| Documents Analyzed | ${report.summary.totalDocuments} |`,
|
|
457
|
+
`| Healthy | ${report.summary.healthyDocuments} |`,
|
|
458
|
+
`| With Issues | ${report.summary.documentsWithIssues} |`,
|
|
459
|
+
`| References Valid | ${report.summary.validReferences}/${report.summary.totalReferences} |`,
|
|
460
|
+
''
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
if (report.documents.length > 0) {
|
|
464
|
+
lines.push('## Documents', '');
|
|
465
|
+
for (const doc of report.documents) {
|
|
466
|
+
const emoji = doc.status === 'healthy' ? '✓' :
|
|
467
|
+
doc.status === 'needs_update' ? '⚠' : '✗';
|
|
468
|
+
lines.push(`### ${doc.document} (${doc.healthScore}% ${emoji})`);
|
|
469
|
+
lines.push('');
|
|
470
|
+
|
|
471
|
+
if (doc.references.invalid.length > 0) {
|
|
472
|
+
lines.push('**Issues:**', '');
|
|
473
|
+
for (const issue of doc.references.invalid) {
|
|
474
|
+
lines.push(`- \`${issue.original}\` - ${issue.issue}`);
|
|
475
|
+
if (issue.suggestion) {
|
|
476
|
+
lines.push(` - Suggestion: ${issue.suggestion}`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
lines.push('');
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (report.suggestedFixes.length > 0) {
|
|
485
|
+
lines.push('## Suggested Fixes', '');
|
|
486
|
+
for (const fix of report.suggestedFixes) {
|
|
487
|
+
lines.push(`- **${fix.document}**: \`${fix.original}\``);
|
|
488
|
+
lines.push(` - → ${fix.suggestion}`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return lines.join('\n');
|
|
493
|
+
}
|
|
494
|
+
|
|
337
495
|
program.parse();
|