@valentia-ai-skills/framework 1.0.8 → 1.0.9
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 +157 -2
- package/hooks/do-analysis.js +125 -0
- package/hooks/install-hook.js +75 -0
- package/hooks/post-commit-analyze.js +29 -0
- package/package.json +3 -2
package/bin/cli.js
CHANGED
|
@@ -26,6 +26,8 @@ const CONFIG_PATH = path.join(PROJECT_ROOT, ".ai-skills.json");
|
|
|
26
26
|
// UPDATE THIS with your actual Supabase project URL
|
|
27
27
|
const SUPABASE_FUNCTION_URL =
|
|
28
28
|
process.env.AI_SKILLS_API_URL || "https://znshdhjquohrzvbnloki.supabase.co/functions/v1/lookup-team";
|
|
29
|
+
const ANALYZE_FUNCTION_URL =
|
|
30
|
+
process.env.AI_SKILLS_ANALYZE_URL || "https://znshdhjquohrzvbnloki.supabase.co/functions/v1/analyze-commit";
|
|
29
31
|
|
|
30
32
|
const TOOL_CONFIGS = {
|
|
31
33
|
"claude-code": {
|
|
@@ -367,14 +369,26 @@ async function cmdSetup() {
|
|
|
367
369
|
email,
|
|
368
370
|
team: teamName,
|
|
369
371
|
source: "supabase",
|
|
372
|
+
analyzeUrl: ANALYZE_FUNCTION_URL,
|
|
370
373
|
tools,
|
|
371
374
|
skills: skills.map((s) => ({ name: s.name, scope: s.scope, version: s.version })),
|
|
372
375
|
installedAt: new Date().toISOString(),
|
|
373
376
|
};
|
|
374
377
|
saveConfig(config);
|
|
375
378
|
|
|
376
|
-
// 7.
|
|
377
|
-
|
|
379
|
+
// 7. Install post-commit analysis hook
|
|
380
|
+
try {
|
|
381
|
+
const { installHook } = require(path.join(__dirname, "..", "hooks", "install-hook.js"));
|
|
382
|
+
const hookResult = installHook(PROJECT_ROOT);
|
|
383
|
+
if (hookResult.installed) {
|
|
384
|
+
console.log(`${c("green", "✓")} Post-commit analysis hook installed`);
|
|
385
|
+
}
|
|
386
|
+
} catch {
|
|
387
|
+
// Hook installation is optional — don't fail setup
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// 8. Summary
|
|
391
|
+
console.log(c("blue", "\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"));
|
|
378
392
|
console.log(c("green", "✅ Setup complete!"));
|
|
379
393
|
console.log(` ${skills.length} skills installed for ${tools.length} tool(s)`);
|
|
380
394
|
if (teamName) console.log(` Team: ${teamName}`);
|
|
@@ -551,6 +565,142 @@ function cmdDoctor() {
|
|
|
551
565
|
}
|
|
552
566
|
}
|
|
553
567
|
|
|
568
|
+
// ── Analyze Command ──
|
|
569
|
+
|
|
570
|
+
async function cmdAnalyze() {
|
|
571
|
+
console.log(c("blue", "\n━━━ AI Skills Framework — Analyze ━━━\n"));
|
|
572
|
+
|
|
573
|
+
const config = loadConfig();
|
|
574
|
+
if (!config || !config.email) {
|
|
575
|
+
console.log(c("yellow", "No .ai-skills.json found. Run 'npx ai-skills setup' first."));
|
|
576
|
+
process.exit(1);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const skillNames = (config.skills || []).map((s) => s.name);
|
|
580
|
+
if (skillNames.length === 0) {
|
|
581
|
+
console.log(c("yellow", "No skills configured. Run 'npx ai-skills setup' first."));
|
|
582
|
+
process.exit(1);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const analyzeUrl = config.analyzeUrl || ANALYZE_FUNCTION_URL;
|
|
586
|
+
|
|
587
|
+
// Check if we're in a git repo
|
|
588
|
+
try {
|
|
589
|
+
require("child_process").execSync("git rev-parse --git-dir", { stdio: "ignore", cwd: PROJECT_ROOT });
|
|
590
|
+
} catch {
|
|
591
|
+
console.log(c("red", "Not a git repository."));
|
|
592
|
+
process.exit(1);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
const execOpt = { cwd: PROJECT_ROOT, encoding: "utf-8", timeout: 10000 };
|
|
596
|
+
|
|
597
|
+
// Collect git data
|
|
598
|
+
const useLastCommit = process.argv.includes("--last");
|
|
599
|
+
let diff, commitHash, commitMessage, branch, filesChanged;
|
|
600
|
+
|
|
601
|
+
try {
|
|
602
|
+
if (useLastCommit) {
|
|
603
|
+
diff = require("child_process").execSync("git diff HEAD~1 HEAD", execOpt).trim();
|
|
604
|
+
commitHash = require("child_process").execSync("git rev-parse HEAD", execOpt).trim();
|
|
605
|
+
commitMessage = require("child_process").execSync('git log -1 --format="%s"', execOpt).trim();
|
|
606
|
+
filesChanged = require("child_process").execSync("git diff --name-only HEAD~1 HEAD", execOpt).trim().split("\n").filter(Boolean);
|
|
607
|
+
} else {
|
|
608
|
+
// Analyze staged changes or last commit
|
|
609
|
+
diff = require("child_process").execSync("git diff --cached", execOpt).trim();
|
|
610
|
+
if (!diff) {
|
|
611
|
+
diff = require("child_process").execSync("git diff HEAD~1 HEAD", execOpt).trim();
|
|
612
|
+
commitHash = require("child_process").execSync("git rev-parse HEAD", execOpt).trim();
|
|
613
|
+
commitMessage = require("child_process").execSync('git log -1 --format="%s"', execOpt).trim();
|
|
614
|
+
filesChanged = require("child_process").execSync("git diff --name-only HEAD~1 HEAD", execOpt).trim().split("\n").filter(Boolean);
|
|
615
|
+
} else {
|
|
616
|
+
commitHash = "(staged)";
|
|
617
|
+
commitMessage = "(staged changes)";
|
|
618
|
+
filesChanged = require("child_process").execSync("git diff --cached --name-only", execOpt).trim().split("\n").filter(Boolean);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
branch = require("child_process").execSync("git branch --show-current", execOpt).trim();
|
|
622
|
+
} catch (err) {
|
|
623
|
+
console.log(c("red", `Failed to collect git data: ${err.message}`));
|
|
624
|
+
process.exit(1);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (!diff) {
|
|
628
|
+
console.log(c("yellow", "No changes to analyze."));
|
|
629
|
+
process.exit(0);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// Truncate diff if needed
|
|
633
|
+
if (diff.length > 10000) {
|
|
634
|
+
diff = diff.slice(0, 4000) + "\n\n[...truncated...]\n\n" + diff.slice(-4000);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
console.log(`Analyzing ${c("bold", filesChanged.length)} file(s) against ${c("bold", skillNames.length)} skill(s)...`);
|
|
638
|
+
console.log(c("dim", `Commit: ${commitHash?.slice(0, 8)} — ${commitMessage}`));
|
|
639
|
+
console.log(c("dim", `Branch: ${branch}\n`));
|
|
640
|
+
|
|
641
|
+
// Get project name
|
|
642
|
+
let projectName = null;
|
|
643
|
+
try {
|
|
644
|
+
const pkgPath = path.join(PROJECT_ROOT, "package.json");
|
|
645
|
+
if (fs.existsSync(pkgPath)) {
|
|
646
|
+
projectName = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name || null;
|
|
647
|
+
}
|
|
648
|
+
} catch { /* ignore */ }
|
|
649
|
+
|
|
650
|
+
try {
|
|
651
|
+
console.log(c("dim", "Sending to AI for analysis (this may take 10-30 seconds)...\n"));
|
|
652
|
+
|
|
653
|
+
const result = await fetchJSON(analyzeUrl, {
|
|
654
|
+
email: config.email,
|
|
655
|
+
commit_hash: commitHash,
|
|
656
|
+
commit_message: commitMessage,
|
|
657
|
+
branch,
|
|
658
|
+
project_name: projectName,
|
|
659
|
+
files_changed: filesChanged,
|
|
660
|
+
diff,
|
|
661
|
+
skill_names: skillNames,
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
if (result.error) {
|
|
665
|
+
throw new Error(result.error);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Display results
|
|
669
|
+
console.log(c("blue", "━━━ Analysis Results ━━━\n"));
|
|
670
|
+
const score = result.overall_score || 0;
|
|
671
|
+
const scoreColor = score >= 80 ? "green" : score >= 50 ? "yellow" : "red";
|
|
672
|
+
console.log(`Overall Score: ${c(scoreColor, `${score}/100`)}\n`);
|
|
673
|
+
|
|
674
|
+
if (result.skill_scores) {
|
|
675
|
+
for (const [skillName, data] of Object.entries(result.skill_scores)) {
|
|
676
|
+
const s = data;
|
|
677
|
+
const sColor = s.score >= 80 ? "green" : s.score >= 50 ? "yellow" : "red";
|
|
678
|
+
console.log(`${c("bold", skillName)}: ${c(sColor, `${s.score}/100`)}`);
|
|
679
|
+
if (s.passed?.length) {
|
|
680
|
+
for (const p of s.passed) console.log(` ${c("green", "✓")} ${p}`);
|
|
681
|
+
}
|
|
682
|
+
if (s.failed?.length) {
|
|
683
|
+
for (const f of s.failed) console.log(` ${c("red", "✗")} ${f}`);
|
|
684
|
+
}
|
|
685
|
+
if (s.suggestions?.length) {
|
|
686
|
+
for (const sg of s.suggestions) console.log(` ${c("yellow", "→")} ${sg}`);
|
|
687
|
+
}
|
|
688
|
+
console.log("");
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (result.summary) {
|
|
693
|
+
console.log(c("dim", `Summary: ${result.summary}`));
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
console.log(c("dim", `\nTokens used: ${result.tokens_used || "?"} | Duration: ${result.duration_ms || "?"}ms\n`));
|
|
697
|
+
|
|
698
|
+
} catch (err) {
|
|
699
|
+
console.log(c("red", `\n✗ Analysis failed: ${err.message}`));
|
|
700
|
+
process.exit(1);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
554
704
|
// ── Main ──
|
|
555
705
|
|
|
556
706
|
const command = process.argv[2] || "setup";
|
|
@@ -561,6 +711,7 @@ switch (command) {
|
|
|
561
711
|
case "status": cmdStatus(); break;
|
|
562
712
|
case "list": cmdList(); break;
|
|
563
713
|
case "doctor": cmdDoctor(); break;
|
|
714
|
+
case "analyze": cmdAnalyze(); break;
|
|
564
715
|
case "help": case "--help": case "-h":
|
|
565
716
|
console.log(`
|
|
566
717
|
${c("blue", "AI Skills Framework")} — @valentia-ai-skills/framework
|
|
@@ -570,8 +721,12 @@ Usage:
|
|
|
570
721
|
npx ai-skills update Re-fetch and update skills for your team
|
|
571
722
|
npx ai-skills status Show installed skills, team, and tools
|
|
572
723
|
npx ai-skills list List locally bundled skills
|
|
724
|
+
npx ai-skills analyze Analyze last commit against active skills
|
|
573
725
|
npx ai-skills doctor Health check (config + API + tools)
|
|
574
726
|
|
|
727
|
+
Flags:
|
|
728
|
+
analyze --last Analyze the most recent commit
|
|
729
|
+
|
|
575
730
|
Environment:
|
|
576
731
|
AI_SKILLS_API_URL Override the Supabase Edge Function URL
|
|
577
732
|
`); break;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Background commit analyzer.
|
|
5
|
+
* Collects git diff + metadata, sends to the analyze-commit Edge Function.
|
|
6
|
+
* Runs as a detached process — never shows output to the developer.
|
|
7
|
+
* Everything is wrapped in try/catch — fails silently on any error.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require("fs");
|
|
11
|
+
const path = require("path");
|
|
12
|
+
const { execSync } = require("child_process");
|
|
13
|
+
const https = require("https");
|
|
14
|
+
const http = require("http");
|
|
15
|
+
|
|
16
|
+
const PROJECT_ROOT = process.env.AI_SKILLS_CWD || process.cwd();
|
|
17
|
+
const CONFIG_PATH = path.join(PROJECT_ROOT, ".ai-skills.json");
|
|
18
|
+
|
|
19
|
+
// Default Edge Function URL (can be overridden in .ai-skills.json)
|
|
20
|
+
const DEFAULT_API_URL =
|
|
21
|
+
"https://znshdhjquohrzvbnloki.supabase.co/functions/v1/analyze-commit";
|
|
22
|
+
|
|
23
|
+
function loadConfig() {
|
|
24
|
+
try {
|
|
25
|
+
if (fs.existsSync(CONFIG_PATH)) {
|
|
26
|
+
return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// ignore
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function git(cmd) {
|
|
35
|
+
try {
|
|
36
|
+
return execSync(cmd, { cwd: PROJECT_ROOT, encoding: "utf-8", timeout: 10000 }).trim();
|
|
37
|
+
} catch {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function truncateDiff(diff, maxLen = 10000) {
|
|
43
|
+
if (diff.length <= maxLen) return diff;
|
|
44
|
+
const half = Math.floor(maxLen / 2);
|
|
45
|
+
return diff.slice(0, half) + "\n\n[...truncated...]\n\n" + diff.slice(-half);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function postJSON(url, body) {
|
|
49
|
+
return new Promise((resolve, reject) => {
|
|
50
|
+
const parsed = new URL(url);
|
|
51
|
+
const mod = parsed.protocol === "https:" ? https : http;
|
|
52
|
+
const postData = JSON.stringify(body);
|
|
53
|
+
|
|
54
|
+
const req = mod.request(
|
|
55
|
+
{
|
|
56
|
+
hostname: parsed.hostname,
|
|
57
|
+
port: parsed.port,
|
|
58
|
+
path: parsed.pathname + parsed.search,
|
|
59
|
+
method: "POST",
|
|
60
|
+
headers: {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
"Content-Length": Buffer.byteLength(postData),
|
|
63
|
+
},
|
|
64
|
+
timeout: 60000, // 60s timeout for AI analysis
|
|
65
|
+
},
|
|
66
|
+
(res) => {
|
|
67
|
+
let data = "";
|
|
68
|
+
res.on("data", (chunk) => (data += chunk));
|
|
69
|
+
res.on("end", () => resolve(data));
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
req.on("error", reject);
|
|
73
|
+
req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); });
|
|
74
|
+
req.write(postData);
|
|
75
|
+
req.end();
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function main() {
|
|
80
|
+
// 1. Read config
|
|
81
|
+
const config = loadConfig();
|
|
82
|
+
if (!config || !config.email) return; // No config = not set up, silently exit
|
|
83
|
+
|
|
84
|
+
const email = config.email;
|
|
85
|
+
const skillNames = (config.skills || []).map((s) => s.name);
|
|
86
|
+
if (skillNames.length === 0) return; // No skills to check against
|
|
87
|
+
|
|
88
|
+
const apiUrl = config.analyzeUrl || process.env.AI_SKILLS_ANALYZE_URL || DEFAULT_API_URL;
|
|
89
|
+
|
|
90
|
+
// 2. Collect git data
|
|
91
|
+
const diff = git("git diff HEAD~1 HEAD");
|
|
92
|
+
if (!diff) return; // No diff = nothing to analyze
|
|
93
|
+
|
|
94
|
+
const commitHash = git("git rev-parse HEAD");
|
|
95
|
+
const commitMessage = git('git log -1 --format="%s"');
|
|
96
|
+
const branch = git("git branch --show-current");
|
|
97
|
+
const filesChangedRaw = git("git diff --name-only HEAD~1 HEAD");
|
|
98
|
+
const filesChanged = filesChangedRaw ? filesChangedRaw.split("\n").filter(Boolean) : [];
|
|
99
|
+
|
|
100
|
+
// Try to get project name from package.json
|
|
101
|
+
let projectName = null;
|
|
102
|
+
try {
|
|
103
|
+
const pkgPath = path.join(PROJECT_ROOT, "package.json");
|
|
104
|
+
if (fs.existsSync(pkgPath)) {
|
|
105
|
+
projectName = JSON.parse(fs.readFileSync(pkgPath, "utf-8")).name || null;
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// ignore
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 3. Send to Edge Function
|
|
112
|
+
await postJSON(apiUrl, {
|
|
113
|
+
email,
|
|
114
|
+
commit_hash: commitHash,
|
|
115
|
+
commit_message: commitMessage,
|
|
116
|
+
branch,
|
|
117
|
+
project_name: projectName,
|
|
118
|
+
files_changed: filesChanged,
|
|
119
|
+
diff: truncateDiff(diff),
|
|
120
|
+
skill_names: skillNames,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Run and exit silently regardless of outcome
|
|
125
|
+
main().catch(() => {}).finally(() => process.exit(0));
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Installs the post-commit analysis hook into .git/hooks/post-commit.
|
|
5
|
+
* Called during `npx ai-skills setup`.
|
|
6
|
+
*
|
|
7
|
+
* The hook script delegates to the npm package's hooks/post-commit-analyze.js,
|
|
8
|
+
* so updates to the analysis logic are picked up automatically on npm update.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require("fs");
|
|
12
|
+
const path = require("path");
|
|
13
|
+
|
|
14
|
+
function installHook(projectRoot) {
|
|
15
|
+
const gitHooksDir = path.join(projectRoot, ".git", "hooks");
|
|
16
|
+
|
|
17
|
+
// Check if this is a git repo
|
|
18
|
+
if (!fs.existsSync(path.join(projectRoot, ".git"))) {
|
|
19
|
+
return { installed: false, reason: "Not a git repository" };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Ensure hooks directory exists
|
|
23
|
+
if (!fs.existsSync(gitHooksDir)) {
|
|
24
|
+
fs.mkdirSync(gitHooksDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const hookPath = path.join(gitHooksDir, "post-commit");
|
|
28
|
+
|
|
29
|
+
// Find the path to the hook script in the npm package
|
|
30
|
+
// Works whether running from node_modules or directly
|
|
31
|
+
const hookScript = path.join(__dirname, "post-commit-analyze.js");
|
|
32
|
+
|
|
33
|
+
// Generate the hook content — delegates to the npm package script
|
|
34
|
+
const hookContent = `#!/bin/sh
|
|
35
|
+
# AI Skills Framework — post-commit analysis hook
|
|
36
|
+
# Auto-installed by npx ai-skills setup
|
|
37
|
+
# Runs code analysis in the background after each commit (non-blocking)
|
|
38
|
+
|
|
39
|
+
node "${hookScript}" &
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
// Check if an existing post-commit hook exists
|
|
43
|
+
if (fs.existsSync(hookPath)) {
|
|
44
|
+
const existing = fs.readFileSync(hookPath, "utf-8");
|
|
45
|
+
if (existing.includes("ai-skills")) {
|
|
46
|
+
// Already installed — update it
|
|
47
|
+
fs.writeFileSync(hookPath, hookContent);
|
|
48
|
+
fs.chmodSync(hookPath, "755");
|
|
49
|
+
return { installed: true, reason: "Updated existing hook" };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// There's a different post-commit hook — append our line
|
|
53
|
+
const appendLine = `\n# AI Skills Framework — post-commit analysis\nnode "${hookScript}" &\n`;
|
|
54
|
+
fs.appendFileSync(hookPath, appendLine);
|
|
55
|
+
fs.chmodSync(hookPath, "755");
|
|
56
|
+
return { installed: true, reason: "Appended to existing hook" };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// No existing hook — create new one
|
|
60
|
+
fs.writeFileSync(hookPath, hookContent);
|
|
61
|
+
fs.chmodSync(hookPath, "755");
|
|
62
|
+
return { installed: true, reason: "Hook installed" };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// If run directly (not required as module)
|
|
66
|
+
if (require.main === module) {
|
|
67
|
+
const result = installHook(process.cwd());
|
|
68
|
+
if (result.installed) {
|
|
69
|
+
console.log(`✓ Post-commit hook: ${result.reason}`);
|
|
70
|
+
} else {
|
|
71
|
+
console.log(`⚠ Post-commit hook skipped: ${result.reason}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { installHook };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Post-commit hook entry point.
|
|
5
|
+
* Spawns the actual analysis as a detached background process so git returns immediately.
|
|
6
|
+
* This file is copied into .git/hooks/post-commit during `npx ai-skills setup`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn } = require("child_process");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// Find do-analysis.js relative to this hook's location in the npm package
|
|
14
|
+
// When installed via npm, hooks/ is inside node_modules/@valentia-ai-skills/framework/hooks/
|
|
15
|
+
const analysisScript = path.join(__dirname, "do-analysis.js");
|
|
16
|
+
|
|
17
|
+
const child = spawn("node", [analysisScript], {
|
|
18
|
+
detached: true,
|
|
19
|
+
stdio: "ignore",
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
env: { ...process.env, AI_SKILLS_CWD: process.cwd() },
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
child.unref();
|
|
25
|
+
} catch {
|
|
26
|
+
// Never block the developer — silently exit
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valentia-ai-skills/framework",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "AI development skills framework
|
|
3
|
+
"version": "1.0.9",
|
|
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",
|
|
7
7
|
"claude-code",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"src/",
|
|
35
35
|
"skills/",
|
|
36
36
|
"scripts/",
|
|
37
|
+
"hooks/",
|
|
37
38
|
"README.md"
|
|
38
39
|
],
|
|
39
40
|
"engines": {
|