@valentia-ai-skills/framework 2.0.1 → 2.0.2

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/bin/cli.js CHANGED
@@ -1217,7 +1217,6 @@ async function cmdAnalyze() {
1217
1217
  console.log(`Analyzing ${c("bold", filesChanged.length)} file(s) against ${c("bold", skillNames.length)} skill(s)...`);
1218
1218
  console.log(c("dim", `Commit: ${commitHash?.slice(0, 8)} — ${commitMessage}`));
1219
1219
  console.log(c("dim", `Branch: ${branch}\n`));
1220
-
1221
1220
  let projectName = null;
1222
1221
  try {
1223
1222
  const pkgPath = path.join(PROJECT_ROOT, "package.json");
@@ -1279,6 +1278,245 @@ async function cmdAnalyze() {
1279
1278
  }
1280
1279
  }
1281
1280
 
1281
+ // ── Upload Legacy Scan Command ──
1282
+
1283
+ const UPLOAD_LEGACY_SCAN_URL =
1284
+ process.env.AI_SKILLS_UPLOAD_LEGACY_URL ||
1285
+ "https://znshdhjquohrzvbnloki.supabase.co/functions/v1/upload-legacy-scan";
1286
+
1287
+ function fetchJSONWithAuth(url, body, token) {
1288
+ return new Promise((resolve, reject) => {
1289
+ const parsed = new URL(url);
1290
+ const mod = parsed.protocol === "https:" ? https : http;
1291
+ const postData = JSON.stringify(body);
1292
+
1293
+ const headers = {
1294
+ "Content-Type": "application/json",
1295
+ "Content-Length": Buffer.byteLength(postData),
1296
+ };
1297
+ if (token) headers["Authorization"] = `Bearer ${token}`;
1298
+
1299
+ const req = mod.request(
1300
+ { hostname: parsed.hostname, port: parsed.port, path: parsed.pathname + parsed.search, method: "POST", headers },
1301
+ (res) => {
1302
+ let data = "";
1303
+ res.on("data", (chunk) => (data += chunk));
1304
+ res.on("end", () => {
1305
+ try {
1306
+ const json = JSON.parse(data);
1307
+ if (res.statusCode >= 400) {
1308
+ reject(new Error(json.error || `HTTP ${res.statusCode}`));
1309
+ } else {
1310
+ resolve(json);
1311
+ }
1312
+ } catch {
1313
+ reject(new Error(`Invalid response: ${data.slice(0, 200)}`));
1314
+ }
1315
+ });
1316
+ }
1317
+ );
1318
+ req.on("error", reject);
1319
+ req.write(postData);
1320
+ req.end();
1321
+ });
1322
+ }
1323
+
1324
+ async function cmdUploadLegacyScan() {
1325
+ console.log(c("blue", "\n━━━ AI Skills Framework — Upload Legacy Scan ━━━\n"));
1326
+
1327
+ const args = process.argv.slice(3);
1328
+ let scanPath = null;
1329
+ let authToken = null;
1330
+ let dryRun = false;
1331
+
1332
+ for (let i = 0; i < args.length; i++) {
1333
+ if (args[i] === "--path" && args[i + 1]) { scanPath = args[++i]; }
1334
+ else if (args[i] === "--token" && args[i + 1]) { authToken = args[++i]; }
1335
+ else if (args[i] === "--dry-run") { dryRun = true; }
1336
+ }
1337
+
1338
+ if (!scanPath) {
1339
+ console.log(c("red", "✗ --path is required."));
1340
+ console.log(c("dim", " Usage: npx ai-skills upload-legacy-scan --path ./my-project-intelligence/\n"));
1341
+ process.exit(1);
1342
+ }
1343
+
1344
+ const resolvedPath = path.resolve(scanPath);
1345
+ if (!fs.existsSync(resolvedPath)) {
1346
+ console.log(c("red", `✗ Path not found: ${resolvedPath}`));
1347
+ process.exit(1);
1348
+ }
1349
+
1350
+ // ── Read and validate manifest.json ──
1351
+ const manifestPath = path.join(resolvedPath, "manifest.json");
1352
+ if (!fs.existsSync(manifestPath)) {
1353
+ console.log(c("red", `✗ manifest.json not found in ${resolvedPath}`));
1354
+ console.log(c("dim", " The intelligence folder must contain a manifest.json file.\n"));
1355
+ process.exit(1);
1356
+ }
1357
+
1358
+ let manifest;
1359
+ try {
1360
+ manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
1361
+ } catch (err) {
1362
+ console.log(c("red", `✗ Failed to parse manifest.json: ${err.message}`));
1363
+ process.exit(1);
1364
+ }
1365
+
1366
+ const missing = ["project", "scanned_at", "skills", "statistics"].filter((k) => !manifest[k]);
1367
+ if (missing.length > 0) {
1368
+ console.log(c("red", `✗ manifest.json missing required fields: ${missing.join(", ")}`));
1369
+ process.exit(1);
1370
+ }
1371
+
1372
+ const projectName = manifest.project;
1373
+ console.log(`Project: ${c("bold", projectName)}`);
1374
+ console.log(`Scanned: ${c("dim", manifest.scanned_at)}`);
1375
+ if (manifest.tech_stack) {
1376
+ const stackParts = Object.entries(manifest.tech_stack)
1377
+ .filter(([, v]) => v)
1378
+ .map(([k, v]) => `${k}: ${v}`)
1379
+ .join(", ");
1380
+ if (stackParts) console.log(`Stack: ${c("cyan", stackParts)}`);
1381
+ }
1382
+
1383
+ // ── Read skill files ──
1384
+ const skillPayload = [];
1385
+ for (const skillEntry of (manifest.skills || [])) {
1386
+ if (!skillEntry.name || !skillEntry.file) continue;
1387
+ const skillFilePath = path.join(resolvedPath, skillEntry.file);
1388
+ if (!fs.existsSync(skillFilePath)) {
1389
+ console.log(c("yellow", ` ⚠ Skill file not found: ${skillEntry.file} — skipping`));
1390
+ continue;
1391
+ }
1392
+ skillPayload.push({
1393
+ name: skillEntry.name,
1394
+ type: skillEntry.type || "module",
1395
+ content: fs.readFileSync(skillFilePath, "utf-8"),
1396
+ });
1397
+ }
1398
+ console.log(`Skills: ${c("green", skillPayload.length.toString())} module(s)`);
1399
+
1400
+ // ── Read diagram files ──
1401
+ const diagramPayload = [];
1402
+ for (const diagramEntry of (manifest.diagrams || [])) {
1403
+ if (!diagramEntry.name || !diagramEntry.file) continue;
1404
+ const diagramFilePath = path.join(resolvedPath, diagramEntry.file);
1405
+ if (!fs.existsSync(diagramFilePath)) {
1406
+ console.log(c("yellow", ` ⚠ Diagram file not found: ${diagramEntry.file} — skipping`));
1407
+ continue;
1408
+ }
1409
+ diagramPayload.push({
1410
+ name: diagramEntry.name,
1411
+ type: diagramEntry.type || "architecture",
1412
+ content: fs.readFileSync(diagramFilePath, "utf-8"),
1413
+ });
1414
+ }
1415
+ console.log(`Diagrams: ${c("green", diagramPayload.length.toString())} file(s)`);
1416
+
1417
+ // ── Read report files ──
1418
+ const reportsPayload = {};
1419
+ const reportFileMap = {
1420
+ overview: ["OVERVIEW.md", "overview.md"],
1421
+ api_registry: ["API_REGISTRY.md", "api_registry.md"],
1422
+ business_rules: ["BUSINESS_RULES.md", "business_rules.md"],
1423
+ data_models: ["DATA_MODELS.md", "data_models.md"],
1424
+ dependencies: ["DEPENDENCIES.md", "dependencies.md"],
1425
+ env_config: ["ENV_CONFIG.md", "env_config.md"],
1426
+ risk_report: ["RISK_REPORT.md", "risk_report.md"],
1427
+ glossary: ["GLOSSARY.md", "glossary.md"],
1428
+ reproduction_guide: ["REPRODUCTION_GUIDE.md", "reproduction_guide.md"],
1429
+ };
1430
+
1431
+ for (const [key, candidates] of Object.entries(reportFileMap)) {
1432
+ for (const candidate of candidates) {
1433
+ const reportPaths = [
1434
+ path.join(resolvedPath, candidate),
1435
+ path.join(resolvedPath, "reports", candidate),
1436
+ ];
1437
+ const found = reportPaths.find((p) => fs.existsSync(p));
1438
+ if (found) {
1439
+ reportsPayload[key] = fs.readFileSync(found, "utf-8");
1440
+ break;
1441
+ }
1442
+ }
1443
+ }
1444
+
1445
+ const reportCount = Object.keys(reportsPayload).length;
1446
+ console.log(`Reports: ${c("green", reportCount.toString())} file(s)\n`);
1447
+
1448
+ // ── Dry run: print summary and exit ──
1449
+ if (dryRun) {
1450
+ console.log(c("yellow", "Dry run — payload summary:"));
1451
+ const stats = manifest.statistics || {};
1452
+ console.log(` Project name: ${projectName}`);
1453
+ console.log(` Modules: ${skillPayload.length}`);
1454
+ console.log(` Diagrams: ${diagramPayload.length}`);
1455
+ console.log(` Reports: ${reportCount}`);
1456
+ if (stats.completeness_score !== undefined) {
1457
+ console.log(` Completeness: ${stats.completeness_score}%`);
1458
+ }
1459
+ console.log(c("dim", "\nNo data was uploaded. Remove --dry-run to upload.\n"));
1460
+ return;
1461
+ }
1462
+
1463
+ // ── Resolve auth ──
1464
+ let email = null;
1465
+ if (!authToken) {
1466
+ const config = loadConfig();
1467
+ if (config?.email) {
1468
+ email = config.email;
1469
+ console.log(c("dim", `Using saved email: ${email}`));
1470
+ } else {
1471
+ console.log(c("yellow", "No saved config found. Enter your email to authenticate."));
1472
+ email = await ask(`${c("bold", "Work email:")} `);
1473
+ const otpResult = await requestOtpForEmail(email);
1474
+ email = otpResult.email;
1475
+ await verifyOtp(email); // we only need the OTP verification, not the toolkit
1476
+ }
1477
+ }
1478
+
1479
+ // ── Upload ──
1480
+ console.log(c("dim", `Uploading to Valentia (${projectName})...\n`));
1481
+ process.stdout.write(` ${c("dim", "→")} Sending ${skillPayload.length} skills, ${diagramPayload.length} diagrams, ${reportCount} reports...`);
1482
+
1483
+ let result;
1484
+ try {
1485
+ result = await fetchJSONWithAuth(
1486
+ UPLOAD_LEGACY_SCAN_URL,
1487
+ {
1488
+ project_name: projectName,
1489
+ manifest,
1490
+ skills: skillPayload,
1491
+ diagrams: diagramPayload,
1492
+ reports: reportsPayload,
1493
+ email,
1494
+ },
1495
+ authToken
1496
+ );
1497
+ console.log(c("green", " done!\n"));
1498
+ } catch (err) {
1499
+ console.log(c("red", " failed!"));
1500
+ console.log(c("red", `\n✗ Upload failed: ${err.message}`));
1501
+ console.log(c("dim", " Retry with --dry-run to validate your payload without uploading.\n"));
1502
+ process.exit(1);
1503
+ }
1504
+
1505
+ console.log(c("green", "✓ Upload complete!\n"));
1506
+ console.log(` Project ID: ${c("bold", result.project_id)}`);
1507
+ console.log(` Skills created: ${c("bold", (result.skills_created || []).length.toString())}`);
1508
+ if (result.storage_urls?.diagrams?.length) {
1509
+ console.log(` Diagrams stored: ${c("dim", result.storage_urls.diagrams.length.toString())}`);
1510
+ }
1511
+ if (result.storage_urls?.reports?.length) {
1512
+ console.log(` Reports stored: ${c("dim", result.storage_urls.reports.length.toString())}`);
1513
+ }
1514
+ if (result.console_url) {
1515
+ console.log(`\n View in console: ${c("bold", result.console_url)}`);
1516
+ }
1517
+ console.log("");
1518
+ }
1519
+
1282
1520
  // ── Main ──
1283
1521
 
1284
1522
  const command = process.argv[2] || "setup";
@@ -1290,6 +1528,7 @@ switch (command) {
1290
1528
  case "list": cmdList(); break;
1291
1529
  case "doctor": cmdDoctor(); break;
1292
1530
  case "analyze": cmdAnalyze(); break;
1531
+ case "upload-legacy-scan": cmdUploadLegacyScan(); break;
1293
1532
  case "help": case "--help": case "-h":
1294
1533
  console.log(`
1295
1534
  ${c("blue", "AI Skills Framework")} — @valentia-ai-skills/framework
@@ -1300,10 +1539,14 @@ Usage:
1300
1539
  npx ai-skills status Show installed toolkit, team, and tools
1301
1540
  npx ai-skills list List locally bundled skills
1302
1541
  npx ai-skills analyze Analyze last commit against active skills
1542
+ npx ai-skills upload-legacy-scan Upload a legacy codebase intelligence package
1303
1543
  npx ai-skills doctor Health check (config + API + tools)
1304
1544
 
1305
1545
  Flags:
1306
1546
  analyze --last Analyze the most recent commit
1547
+ upload-legacy-scan --path <dir> Path to intelligence folder
1548
+ upload-legacy-scan --dry-run Validate payload without uploading
1549
+ upload-legacy-scan --token <tok> Explicit auth token
1307
1550
 
1308
1551
  Toolkit includes: skills, agents, commands, hooks, rules, MCP configs.
1309
1552
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valentia-ai-skills/framework",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
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",
@@ -3,7 +3,7 @@ name: aisupportapp/project-architecture
3
3
  description: Auto-generated project-architecture for aisupportapp. Created by project-scanner.
4
4
  version: 1.0.0
5
5
  scope: project
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---
@@ -3,7 +3,7 @@ name: aisupportapp/project-conventions
3
3
  description: Auto-generated project-conventions for aisupportapp. Created by project-scanner.
4
4
  version: 1.0.0
5
5
  scope: project
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---
@@ -3,7 +3,7 @@ name: aisupportapp/project-workflows
3
3
  description: Auto-generated project-workflows for aisupportapp. Created by project-scanner.
4
4
  version: 1.0.0
5
5
  scope: project
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---
@@ -3,7 +3,7 @@ name: aisupportapp/test-installation
3
3
  description: No description
4
4
  version: 1.0.0
5
5
  scope: project
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  # Skill Name
@@ -3,7 +3,7 @@ name: api-design
3
3
  description: No description
4
4
  version: 1.0.0
5
5
  scope: global
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---
@@ -3,7 +3,7 @@ name: appointment-oas-app
3
3
  description: No description
4
4
  version: 1.0.1
5
5
  scope: global
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---
@@ -3,7 +3,7 @@ name: code-standards
3
3
  description: No description
4
4
  version: 1.0.0
5
5
  scope: global
6
- last_reviewed: 2026-03-27
6
+ last_reviewed: 2026-03-28
7
7
  ---
8
8
 
9
9
  ---