@valentia-ai-skills/framework 2.0.2 → 2.0.4
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 +46 -16
- package/bin/cli.js +222 -34
- package/package.json +1 -1
- package/skills/global/aisupportapp-project-architecture/SKILL.md +1 -1
- package/skills/global/aisupportapp-project-conventions/SKILL.md +1 -1
- package/skills/global/aisupportapp-project-workflows/SKILL.md +1 -1
- package/skills/global/aisupportapp-test-installation/SKILL.md +1 -1
- package/skills/global/api-design/SKILL.md +1 -1
- package/skills/global/appointment-oas-app/SKILL.md +1 -1
- package/skills/global/code-standards/SKILL.md +1 -1
- package/skills/global/codebase-legacy-intelligence/SKILL.md +1 -1
- package/skills/global/project-scanner/SKILL.md +1 -1
- package/skills/global/viteapp-core-workflows/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -65,16 +65,28 @@ npx ai-skills help # Show help
|
|
|
65
65
|
#### Legacy Codebase Intelligence Scanner
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
#
|
|
69
|
-
npx ai-skills
|
|
68
|
+
# Add / refresh a project by uploading a scan intelligence package
|
|
69
|
+
npx ai-skills legacy-projects add --path ./my-project-intelligence/
|
|
70
70
|
|
|
71
|
-
# Validate the
|
|
72
|
-
npx ai-skills
|
|
71
|
+
# Validate the payload without uploading (dry run)
|
|
72
|
+
npx ai-skills legacy-projects add --path ./my-project-intelligence/ --dry-run
|
|
73
73
|
|
|
74
74
|
# Supply an explicit auth token instead of going through OTP
|
|
75
|
-
npx ai-skills
|
|
75
|
+
npx ai-skills legacy-projects add --path ./my-project-intelligence/ --token <your-token>
|
|
76
|
+
|
|
77
|
+
# List all legacy projects for your team
|
|
78
|
+
npx ai-skills legacy-projects list
|
|
79
|
+
|
|
80
|
+
# Show detailed status + document counts for a project
|
|
81
|
+
npx ai-skills legacy-projects status "My Project"
|
|
82
|
+
|
|
83
|
+
# Delete a project and all its documents (irreversible — prompts for confirmation)
|
|
84
|
+
npx ai-skills legacy-projects remove "My Project"
|
|
76
85
|
```
|
|
77
86
|
|
|
87
|
+
> `upload-legacy-scan` is also available as a direct alias:
|
|
88
|
+
> `npx ai-skills upload-legacy-scan --path ./my-project-intelligence/`
|
|
89
|
+
|
|
78
90
|
The `--path` directory must contain a `manifest.json` file. See the [Legacy Scanner](#legacy-codebase-intelligence-scanner) section below for the required format.
|
|
79
91
|
|
|
80
92
|
### Environment Variables
|
|
@@ -85,6 +97,7 @@ The `--path` directory must contain a `manifest.json` file. See the [Legacy Scan
|
|
|
85
97
|
| `AI_SKILLS_ANALYZE_URL` | Override the analyze commit function URL |
|
|
86
98
|
| `AI_SKILLS_SCAN_URL` | Override the scan results function URL |
|
|
87
99
|
| `AI_SKILLS_UPLOAD_LEGACY_URL` | Override the upload-legacy-scan Edge Function URL |
|
|
100
|
+
| `AI_SKILLS_MANAGE_LEGACY_URL` | Override the manage-legacy-projects Edge Function URL |
|
|
88
101
|
|
|
89
102
|
---
|
|
90
103
|
|
|
@@ -276,9 +289,10 @@ The framework supports ingesting intelligence packages generated by legacy codeb
|
|
|
276
289
|
### How It Works
|
|
277
290
|
|
|
278
291
|
1. **Scan** — A compatible scanner tool analyses an existing codebase and produces an intelligence folder
|
|
279
|
-
2. **
|
|
280
|
-
3. **Review** — Tech leads review auto-generated skills,
|
|
281
|
-
4. **
|
|
292
|
+
2. **Add** — `npx ai-skills legacy-projects add --path <folder>` uploads the package, creating the project if it doesn't exist or replacing its documents if it does
|
|
293
|
+
3. **Review** — Tech leads review auto-generated skills, reports, and diagrams in the Skills Console, approving or flagging each document
|
|
294
|
+
4. **Promote** — Approved skills are promoted into the team's active toolkit and distributed on the next `npx ai-skills update`
|
|
295
|
+
5. **Rescan** — Re-running `add` on the same project name replaces all documents with the latest scan output
|
|
282
296
|
|
|
283
297
|
### Intelligence Package Format
|
|
284
298
|
|
|
@@ -318,18 +332,34 @@ my-project-intelligence/
|
|
|
318
332
|
|
|
319
333
|
### Skills Console — Legacy Scanners View
|
|
320
334
|
|
|
321
|
-
After upload, each project appears in the **Legacy Scanners** section of the Skills Console with:
|
|
335
|
+
After upload, each project appears in the **Legacy Scanners** section of the Skills Console with five tabs:
|
|
322
336
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
| Tab | Contents |
|
|
338
|
+
|-----|----------|
|
|
339
|
+
| **Overview** | Project stats, completeness score, tech stack, interactive reproduction guide |
|
|
340
|
+
| **Skills** | Per-skill approval workflow — approve or flag each extracted skill |
|
|
341
|
+
| **Reports** | Searchable reports: API registry, business rules, data models, risk report, etc. |
|
|
342
|
+
| **Architecture** | Interactive Mermaid architecture and ER diagrams |
|
|
343
|
+
| **All Files** | Full document list with category filter + content copy |
|
|
330
344
|
|
|
331
345
|
Approved skills are promoted into the team's standard toolkit and distributed on the next `npx ai-skills update`.
|
|
332
346
|
|
|
347
|
+
### Managing Projects from the CLI
|
|
348
|
+
|
|
349
|
+
```bash
|
|
350
|
+
# Add a new project (or refresh an existing one)
|
|
351
|
+
npx ai-skills legacy-projects add --path ./my-project-intelligence/
|
|
352
|
+
|
|
353
|
+
# List all projects with status, module count, and completeness score
|
|
354
|
+
npx ai-skills legacy-projects list
|
|
355
|
+
|
|
356
|
+
# Inspect a specific project — shows document counts per category
|
|
357
|
+
npx ai-skills legacy-projects status "My Project"
|
|
358
|
+
|
|
359
|
+
# Permanently delete a project and all its documents
|
|
360
|
+
npx ai-skills legacy-projects remove "My Project"
|
|
361
|
+
```
|
|
362
|
+
|
|
333
363
|
---
|
|
334
364
|
|
|
335
365
|
## Architecture
|
package/bin/cli.js
CHANGED
|
@@ -1369,6 +1369,39 @@ async function cmdUploadLegacyScan() {
|
|
|
1369
1369
|
process.exit(1);
|
|
1370
1370
|
}
|
|
1371
1371
|
|
|
1372
|
+
// ── Normalize manifest fields (handles alternate scanner output formats) ──
|
|
1373
|
+
if (!manifest.statistics) manifest.statistics = {};
|
|
1374
|
+
const mstats = manifest.statistics;
|
|
1375
|
+
// Some scanners output completionPercentage instead of completeness_score
|
|
1376
|
+
if (mstats.completeness_score === undefined) {
|
|
1377
|
+
mstats.completeness_score = mstats.completionPercentage ?? 0;
|
|
1378
|
+
}
|
|
1379
|
+
// Some scanners put module count in source.modules
|
|
1380
|
+
if (mstats.total_modules === undefined) {
|
|
1381
|
+
mstats.total_modules =
|
|
1382
|
+
manifest.source?.modules ??
|
|
1383
|
+
manifest.source?.fileCount ??
|
|
1384
|
+
(manifest.skills?.length ?? 0);
|
|
1385
|
+
}
|
|
1386
|
+
// Build tech_stack from source fields or scalar values in technologies if missing
|
|
1387
|
+
if (!manifest.tech_stack) {
|
|
1388
|
+
if (manifest.source) {
|
|
1389
|
+
const ts = {};
|
|
1390
|
+
if (manifest.source.language) ts.language = manifest.source.language;
|
|
1391
|
+
if (manifest.source.framework) ts.framework = manifest.source.framework;
|
|
1392
|
+
manifest.tech_stack = ts;
|
|
1393
|
+
} else if (manifest.technologies && typeof manifest.technologies === "object" && !Array.isArray(manifest.technologies)) {
|
|
1394
|
+
// Only use scalar leaf values to avoid [object Object] in display
|
|
1395
|
+
const ts = {};
|
|
1396
|
+
for (const [k, v] of Object.entries(manifest.technologies)) {
|
|
1397
|
+
if (typeof v === "string" || typeof v === "number") ts[k] = v;
|
|
1398
|
+
}
|
|
1399
|
+
manifest.tech_stack = ts;
|
|
1400
|
+
} else {
|
|
1401
|
+
manifest.tech_stack = {};
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1372
1405
|
const projectName = manifest.project;
|
|
1373
1406
|
console.log(`Project: ${c("bold", projectName)}`);
|
|
1374
1407
|
console.log(`Scanned: ${c("dim", manifest.scanned_at)}`);
|
|
@@ -1382,17 +1415,23 @@ async function cmdUploadLegacyScan() {
|
|
|
1382
1415
|
|
|
1383
1416
|
// ── Read skill files ──
|
|
1384
1417
|
const skillPayload = [];
|
|
1418
|
+
let modulePriority = 1;
|
|
1385
1419
|
for (const skillEntry of (manifest.skills || [])) {
|
|
1386
|
-
|
|
1387
|
-
|
|
1420
|
+
const skillFile = skillEntry.file || skillEntry.path;
|
|
1421
|
+
if (!skillEntry.name || !skillFile) continue;
|
|
1422
|
+
const skillFilePath = path.join(resolvedPath, skillFile);
|
|
1388
1423
|
if (!fs.existsSync(skillFilePath)) {
|
|
1389
|
-
console.log(c("yellow", ` ⚠ Skill file not found: ${
|
|
1424
|
+
console.log(c("yellow", ` ⚠ Skill file not found: ${skillFile} — skipping`));
|
|
1390
1425
|
continue;
|
|
1391
1426
|
}
|
|
1427
|
+
const isMaster = (skillEntry.type || "module") === "master";
|
|
1392
1428
|
skillPayload.push({
|
|
1429
|
+
category: "skill",
|
|
1430
|
+
document_type: isMaster ? "master" : "module",
|
|
1393
1431
|
name: skillEntry.name,
|
|
1394
|
-
type: skillEntry.type || "module",
|
|
1395
1432
|
content: fs.readFileSync(skillFilePath, "utf-8"),
|
|
1433
|
+
priority: isMaster ? 0 : modulePriority++,
|
|
1434
|
+
metadata: {},
|
|
1396
1435
|
});
|
|
1397
1436
|
}
|
|
1398
1437
|
console.log(`Skills: ${c("green", skillPayload.length.toString())} module(s)`);
|
|
@@ -1400,31 +1439,58 @@ async function cmdUploadLegacyScan() {
|
|
|
1400
1439
|
// ── Read diagram files ──
|
|
1401
1440
|
const diagramPayload = [];
|
|
1402
1441
|
for (const diagramEntry of (manifest.diagrams || [])) {
|
|
1403
|
-
|
|
1404
|
-
|
|
1442
|
+
const diagramFile = diagramEntry.file || diagramEntry.path;
|
|
1443
|
+
if (!diagramEntry.name || !diagramFile) continue;
|
|
1444
|
+
const diagramFilePath = path.join(resolvedPath, diagramFile);
|
|
1405
1445
|
if (!fs.existsSync(diagramFilePath)) {
|
|
1406
|
-
console.log(c("yellow", ` ⚠ Diagram file not found: ${
|
|
1446
|
+
console.log(c("yellow", ` ⚠ Diagram file not found: ${diagramFile} — skipping`));
|
|
1407
1447
|
continue;
|
|
1408
1448
|
}
|
|
1409
1449
|
diagramPayload.push({
|
|
1450
|
+
category: "diagram",
|
|
1451
|
+
document_type: diagramEntry.type || "architecture",
|
|
1410
1452
|
name: diagramEntry.name,
|
|
1411
|
-
type: diagramEntry.type || "architecture",
|
|
1412
1453
|
content: fs.readFileSync(diagramFilePath, "utf-8"),
|
|
1454
|
+
priority: 0,
|
|
1455
|
+
metadata: {},
|
|
1413
1456
|
});
|
|
1414
1457
|
}
|
|
1458
|
+
// Auto-discover .mmd/.mermaid files from diagrams/ subdirectory if manifest listed none
|
|
1459
|
+
if (diagramPayload.length === 0) {
|
|
1460
|
+
const diagramsDir = path.join(resolvedPath, "diagrams");
|
|
1461
|
+
if (fs.existsSync(diagramsDir)) {
|
|
1462
|
+
for (const file of fs.readdirSync(diagramsDir).sort()) {
|
|
1463
|
+
if (/\.(mmd|mermaid)$/i.test(file)) {
|
|
1464
|
+
const name = file.replace(/\.(mmd|mermaid)$/i, "");
|
|
1465
|
+
diagramPayload.push({
|
|
1466
|
+
category: "diagram",
|
|
1467
|
+
document_type: "architecture",
|
|
1468
|
+
name,
|
|
1469
|
+
content: fs.readFileSync(path.join(diagramsDir, file), "utf-8"),
|
|
1470
|
+
priority: 0,
|
|
1471
|
+
metadata: {},
|
|
1472
|
+
});
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
if (diagramPayload.length > 0) {
|
|
1476
|
+
console.log(c("dim", ` (auto-discovered ${diagramPayload.length} diagram(s) from diagrams/)`))
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1415
1480
|
console.log(`Diagrams: ${c("green", diagramPayload.length.toString())} file(s)`);
|
|
1416
1481
|
|
|
1417
|
-
// ── Read report files ──
|
|
1418
|
-
const
|
|
1482
|
+
// ── Read report/guide files ──
|
|
1483
|
+
const GUIDE_TYPES = new Set(["overview", "reproduction_guide"]);
|
|
1484
|
+
const reportPayload = [];
|
|
1419
1485
|
const reportFileMap = {
|
|
1420
|
-
overview:
|
|
1421
|
-
api_registry:
|
|
1422
|
-
business_rules:
|
|
1423
|
-
data_models:
|
|
1424
|
-
dependencies:
|
|
1425
|
-
env_config:
|
|
1426
|
-
risk_report:
|
|
1427
|
-
glossary:
|
|
1486
|
+
overview: ["OVERVIEW.md", "overview.md"],
|
|
1487
|
+
api_registry: ["API_REGISTRY.md", "api_registry.md"],
|
|
1488
|
+
business_rules: ["BUSINESS_RULES.md", "business_rules.md"],
|
|
1489
|
+
data_models: ["DATA_MODELS.md", "data_models.md"],
|
|
1490
|
+
dependencies: ["DEPENDENCIES.md", "dependencies.md"],
|
|
1491
|
+
env_config: ["ENV_CONFIG.md", "env_config.md"],
|
|
1492
|
+
risk_report: ["RISK_REPORT.md", "risk_report.md"],
|
|
1493
|
+
glossary: ["GLOSSARY.md", "glossary.md"],
|
|
1428
1494
|
reproduction_guide: ["REPRODUCTION_GUIDE.md", "reproduction_guide.md"],
|
|
1429
1495
|
};
|
|
1430
1496
|
|
|
@@ -1436,23 +1502,36 @@ async function cmdUploadLegacyScan() {
|
|
|
1436
1502
|
];
|
|
1437
1503
|
const found = reportPaths.find((p) => fs.existsSync(p));
|
|
1438
1504
|
if (found) {
|
|
1439
|
-
|
|
1505
|
+
const isGuide = GUIDE_TYPES.has(key);
|
|
1506
|
+
const displayName = key.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
1507
|
+
reportPayload.push({
|
|
1508
|
+
category: isGuide ? "guide" : "report",
|
|
1509
|
+
document_type: key,
|
|
1510
|
+
name: displayName,
|
|
1511
|
+
content: fs.readFileSync(found, "utf-8"),
|
|
1512
|
+
priority: 0,
|
|
1513
|
+
metadata: {},
|
|
1514
|
+
});
|
|
1440
1515
|
break;
|
|
1441
1516
|
}
|
|
1442
1517
|
}
|
|
1443
1518
|
}
|
|
1444
1519
|
|
|
1445
|
-
const reportCount =
|
|
1520
|
+
const reportCount = reportPayload.length;
|
|
1446
1521
|
console.log(`Reports: ${c("green", reportCount.toString())} file(s)\n`);
|
|
1447
1522
|
|
|
1523
|
+
// ── Build unified documents array ──
|
|
1524
|
+
const documentsPayload = [...skillPayload, ...diagramPayload, ...reportPayload];
|
|
1525
|
+
|
|
1448
1526
|
// ── Dry run: print summary and exit ──
|
|
1449
1527
|
if (dryRun) {
|
|
1450
1528
|
console.log(c("yellow", "Dry run — payload summary:"));
|
|
1451
1529
|
const stats = manifest.statistics || {};
|
|
1452
1530
|
console.log(` Project name: ${projectName}`);
|
|
1453
|
-
console.log(`
|
|
1454
|
-
console.log(`
|
|
1455
|
-
console.log(`
|
|
1531
|
+
console.log(` Documents total: ${documentsPayload.length}`);
|
|
1532
|
+
console.log(` — Skills: ${skillPayload.length}`);
|
|
1533
|
+
console.log(` — Diagrams: ${diagramPayload.length}`);
|
|
1534
|
+
console.log(` — Reports/Guides: ${reportCount}`);
|
|
1456
1535
|
if (stats.completeness_score !== undefined) {
|
|
1457
1536
|
console.log(` Completeness: ${stats.completeness_score}%`);
|
|
1458
1537
|
}
|
|
@@ -1472,13 +1551,13 @@ async function cmdUploadLegacyScan() {
|
|
|
1472
1551
|
email = await ask(`${c("bold", "Work email:")} `);
|
|
1473
1552
|
const otpResult = await requestOtpForEmail(email);
|
|
1474
1553
|
email = otpResult.email;
|
|
1475
|
-
await verifyOtp(email);
|
|
1554
|
+
await verifyOtp(email);
|
|
1476
1555
|
}
|
|
1477
1556
|
}
|
|
1478
1557
|
|
|
1479
1558
|
// ── Upload ──
|
|
1480
1559
|
console.log(c("dim", `Uploading to Valentia (${projectName})...\n`));
|
|
1481
|
-
process.stdout.write(` ${c("dim", "→")} Sending ${skillPayload.length} skills, ${diagramPayload.length} diagrams, ${reportCount} reports...`);
|
|
1560
|
+
process.stdout.write(` ${c("dim", "→")} Sending ${documentsPayload.length} documents (${skillPayload.length} skills, ${diagramPayload.length} diagrams, ${reportCount} reports)...`);
|
|
1482
1561
|
|
|
1483
1562
|
let result;
|
|
1484
1563
|
try {
|
|
@@ -1487,9 +1566,7 @@ async function cmdUploadLegacyScan() {
|
|
|
1487
1566
|
{
|
|
1488
1567
|
project_name: projectName,
|
|
1489
1568
|
manifest,
|
|
1490
|
-
|
|
1491
|
-
diagrams: diagramPayload,
|
|
1492
|
-
reports: reportsPayload,
|
|
1569
|
+
documents: documentsPayload,
|
|
1493
1570
|
email,
|
|
1494
1571
|
},
|
|
1495
1572
|
authToken
|
|
@@ -1504,12 +1581,9 @@ async function cmdUploadLegacyScan() {
|
|
|
1504
1581
|
|
|
1505
1582
|
console.log(c("green", "✓ Upload complete!\n"));
|
|
1506
1583
|
console.log(` Project ID: ${c("bold", result.project_id)}`);
|
|
1507
|
-
console.log(`
|
|
1508
|
-
if (result.
|
|
1509
|
-
console.log(`
|
|
1510
|
-
}
|
|
1511
|
-
if (result.storage_urls?.reports?.length) {
|
|
1512
|
-
console.log(` Reports stored: ${c("dim", result.storage_urls.reports.length.toString())}`);
|
|
1584
|
+
console.log(` Documents created: ${c("bold", (result.documents_created || 0).toString())}`);
|
|
1585
|
+
if (result.skills_count > 0) {
|
|
1586
|
+
console.log(` Skills: ${c("dim", result.skills_count.toString())}`);
|
|
1513
1587
|
}
|
|
1514
1588
|
if (result.console_url) {
|
|
1515
1589
|
console.log(`\n View in console: ${c("bold", result.console_url)}`);
|
|
@@ -1517,6 +1591,115 @@ async function cmdUploadLegacyScan() {
|
|
|
1517
1591
|
console.log("");
|
|
1518
1592
|
}
|
|
1519
1593
|
|
|
1594
|
+
// ── Legacy Projects Command ──
|
|
1595
|
+
|
|
1596
|
+
const MANAGE_LEGACY_PROJECTS_URL =
|
|
1597
|
+
process.env.AI_SKILLS_MANAGE_LEGACY_URL ||
|
|
1598
|
+
"https://znshdhjquohrzvbnloki.supabase.co/functions/v1/manage-legacy-projects";
|
|
1599
|
+
|
|
1600
|
+
async function cmdLegacyProjects() {
|
|
1601
|
+
const subcommand = process.argv[3] || "list";
|
|
1602
|
+
const args = process.argv.slice(4);
|
|
1603
|
+
|
|
1604
|
+
// Resolve email
|
|
1605
|
+
const config = loadConfig();
|
|
1606
|
+
let email = config?.email;
|
|
1607
|
+
if (!email) {
|
|
1608
|
+
console.log(c("yellow", "No saved config. Run 'npx ai-skills setup' first."));
|
|
1609
|
+
process.exit(1);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
if (subcommand === "list") {
|
|
1613
|
+
console.log(c("blue", "\n━━━ Legacy Projects ━━━\n"));
|
|
1614
|
+
let result;
|
|
1615
|
+
try {
|
|
1616
|
+
result = await fetchJSONWithAuth(MANAGE_LEGACY_PROJECTS_URL, { action: "list", email }, null);
|
|
1617
|
+
} catch (err) {
|
|
1618
|
+
console.log(c("red", `✗ ${err.message}`));
|
|
1619
|
+
process.exit(1);
|
|
1620
|
+
}
|
|
1621
|
+
const projects = result.projects || [];
|
|
1622
|
+
if (projects.length === 0) {
|
|
1623
|
+
console.log(c("dim", "No legacy projects found.\n"));
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
for (const p of projects) {
|
|
1627
|
+
const statusColor = p.status === "fully_approved" ? "green" : p.status === "partially_approved" ? "yellow" : "dim";
|
|
1628
|
+
const scanDate = p.last_scanned_at ? new Date(p.last_scanned_at).toLocaleDateString() : "?";
|
|
1629
|
+
console.log(` ${c("bold", p.name)}`);
|
|
1630
|
+
console.log(` Status: ${c(statusColor, p.status)} | ${p.module_count} modules | ${p.completeness_score}% | Scanned: ${scanDate}`);
|
|
1631
|
+
console.log(` ${c("dim", p.console_url)}`);
|
|
1632
|
+
console.log("");
|
|
1633
|
+
}
|
|
1634
|
+
console.log(c("dim", ` ${projects.length} project(s)\n`));
|
|
1635
|
+
|
|
1636
|
+
} else if (subcommand === "status") {
|
|
1637
|
+
const projectName = args[0];
|
|
1638
|
+
if (!projectName) {
|
|
1639
|
+
console.log(c("red", "Usage: npx ai-skills legacy-projects status <project-name>"));
|
|
1640
|
+
process.exit(1);
|
|
1641
|
+
}
|
|
1642
|
+
console.log(c("blue", `\n━━━ Legacy Project: ${projectName} ━━━\n`));
|
|
1643
|
+
let result;
|
|
1644
|
+
try {
|
|
1645
|
+
result = await fetchJSONWithAuth(MANAGE_LEGACY_PROJECTS_URL, { action: "status", email, project_name: projectName }, null);
|
|
1646
|
+
} catch (err) {
|
|
1647
|
+
console.log(c("red", `✗ ${err.message}`));
|
|
1648
|
+
process.exit(1);
|
|
1649
|
+
}
|
|
1650
|
+
const p = result.project;
|
|
1651
|
+
const docs = result.documents || {};
|
|
1652
|
+
const statusColor = p.status === "fully_approved" ? "green" : p.status === "partially_approved" ? "yellow" : "dim";
|
|
1653
|
+
console.log(` Project: ${c("bold", p.name)}`);
|
|
1654
|
+
console.log(` Status: ${c(statusColor, p.status)}`);
|
|
1655
|
+
console.log(` Completeness: ${p.completeness_score}%`);
|
|
1656
|
+
console.log(` Modules: ${p.module_count} | Endpoints: ${p.total_endpoints} | Rules: ${p.total_business_rules}`);
|
|
1657
|
+
console.log(` Scanned: ${p.last_scanned_at ? new Date(p.last_scanned_at).toLocaleDateString() : "?"}`);
|
|
1658
|
+
console.log("");
|
|
1659
|
+
if (Object.keys(docs).length > 0) {
|
|
1660
|
+
console.log(c("bold", " Documents:"));
|
|
1661
|
+
for (const [cat, counts] of Object.entries(docs)) {
|
|
1662
|
+
console.log(` ${cat.padEnd(10)} ${counts.total} total, ${counts.approved} approved, ${counts.pending} pending`);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
console.log(`\n Console: ${c("dim", p.console_url)}\n`);
|
|
1666
|
+
|
|
1667
|
+
} else if (subcommand === "add") {
|
|
1668
|
+
// Delegate to upload-legacy-scan — argv flags (--path, --dry-run, --token) are preserved
|
|
1669
|
+
await cmdUploadLegacyScan();
|
|
1670
|
+
return;
|
|
1671
|
+
|
|
1672
|
+
} else if (subcommand === "remove") {
|
|
1673
|
+
const projectName = args[0];
|
|
1674
|
+
if (!projectName) {
|
|
1675
|
+
console.log(c("red", "Usage: npx ai-skills legacy-projects remove <project-name>"));
|
|
1676
|
+
process.exit(1);
|
|
1677
|
+
}
|
|
1678
|
+
const confirm = await ask(`${c("red", `Delete "${projectName}" and all its documents? This cannot be undone. Type the project name to confirm: `)} `);
|
|
1679
|
+
if (confirm.trim() !== projectName) {
|
|
1680
|
+
console.log(c("yellow", "Cancelled.\n"));
|
|
1681
|
+
return;
|
|
1682
|
+
}
|
|
1683
|
+
let result;
|
|
1684
|
+
try {
|
|
1685
|
+
result = await fetchJSONWithAuth(MANAGE_LEGACY_PROJECTS_URL, { action: "remove", email, project_name: projectName }, null);
|
|
1686
|
+
} catch (err) {
|
|
1687
|
+
console.log(c("red", `✗ ${err.message}`));
|
|
1688
|
+
process.exit(1);
|
|
1689
|
+
}
|
|
1690
|
+
if (result.removed) {
|
|
1691
|
+
console.log(c("green", `✓ "${result.name}" deleted.\n`));
|
|
1692
|
+
} else {
|
|
1693
|
+
console.log(c("red", "Failed to delete project."));
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
} else {
|
|
1697
|
+
console.log(c("red", `Unknown subcommand: ${subcommand}`));
|
|
1698
|
+
console.log(c("dim", "Usage: npx ai-skills legacy-projects add --path <dir> | list | status <name> | remove <name>\n"));
|
|
1699
|
+
process.exit(1);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1520
1703
|
// ── Main ──
|
|
1521
1704
|
|
|
1522
1705
|
const command = process.argv[2] || "setup";
|
|
@@ -1529,6 +1712,7 @@ switch (command) {
|
|
|
1529
1712
|
case "doctor": cmdDoctor(); break;
|
|
1530
1713
|
case "analyze": cmdAnalyze(); break;
|
|
1531
1714
|
case "upload-legacy-scan": cmdUploadLegacyScan(); break;
|
|
1715
|
+
case "legacy-projects": cmdLegacyProjects(); break;
|
|
1532
1716
|
case "help": case "--help": case "-h":
|
|
1533
1717
|
console.log(`
|
|
1534
1718
|
${c("blue", "AI Skills Framework")} — @valentia-ai-skills/framework
|
|
@@ -1540,6 +1724,10 @@ Usage:
|
|
|
1540
1724
|
npx ai-skills list List locally bundled skills
|
|
1541
1725
|
npx ai-skills analyze Analyze last commit against active skills
|
|
1542
1726
|
npx ai-skills upload-legacy-scan Upload a legacy codebase intelligence package
|
|
1727
|
+
npx ai-skills legacy-projects add --path <dir> Upload a scan package and add / refresh the project
|
|
1728
|
+
npx ai-skills legacy-projects list List all legacy projects
|
|
1729
|
+
npx ai-skills legacy-projects status <name> Show project status and document counts
|
|
1730
|
+
npx ai-skills legacy-projects remove <name> Delete a project and all its documents
|
|
1543
1731
|
npx ai-skills doctor Health check (config + API + tools)
|
|
1544
1732
|
|
|
1545
1733
|
Flags:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valentia-ai-skills/framework",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.4",
|
|
4
4
|
"description": "AI development skills framework centralized coding standards, security patterns, and SOPs for AI-assisted development. Works with Claude Code, Cursor, Copilot, Windsurf, and any AI coding tool.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-skills",
|