@ngocsangairvds/vsaf 3.0.0 → 3.0.1
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/vsaf.js +1 -0
- package/package.json +1 -1
- package/src/project.js +47 -0
- package/src/status.js +17 -0
package/bin/vsaf.js
CHANGED
|
@@ -18,6 +18,7 @@ GLOBAL (once per machine → ~/.claude/)
|
|
|
18
18
|
|
|
19
19
|
PER PROJECT (per repo, run inside the repo root)
|
|
20
20
|
.claude/settings.json Hooks: secret detection, protected files
|
|
21
|
+
.claude/skills + .codex/skills BMAD skills synced for local clients
|
|
21
22
|
CLAUDE.md 10-step workflow rules
|
|
22
23
|
Makefile index, verify, review, archive, mine, status
|
|
23
24
|
scripts/ Session-end check hook
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngocsangairvds/vsaf",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "VSAF — Agentic AI SDLC Framework. Spec-driven development, 3-layer review, 7 integrated tools.",
|
|
5
5
|
"keywords": ["claude", "claude-code", "ai", "sdlc", "framework", "bmad", "openspec"],
|
|
6
6
|
"bin": {
|
package/src/project.js
CHANGED
|
@@ -5,6 +5,7 @@ const { ok, info, warn, step, hasCommand, exec, copyDir, copyFile } = require('.
|
|
|
5
5
|
|
|
6
6
|
const PKG_ROOT = path.join(__dirname, '..');
|
|
7
7
|
const TEMPLATES = path.join(PKG_ROOT, 'assets', 'templates');
|
|
8
|
+
const SKILLS_SRC = path.join(PKG_ROOT, '.claude', 'skills');
|
|
8
9
|
const CWD = process.cwd();
|
|
9
10
|
|
|
10
11
|
async function installProject() {
|
|
@@ -13,6 +14,7 @@ async function installProject() {
|
|
|
13
14
|
console.log( '\x1b[1m╚══════════════════════════════════════════╝\x1b[0m');
|
|
14
15
|
|
|
15
16
|
scaffoldFiles();
|
|
17
|
+
syncLocalBmadSkills();
|
|
16
18
|
initOpenSpec();
|
|
17
19
|
initGitNexus();
|
|
18
20
|
initMemPalace();
|
|
@@ -58,6 +60,51 @@ function scaffoldFiles() {
|
|
|
58
60
|
|
|
59
61
|
// ── Tool initialisation ──────────────────────────────────────────────────────
|
|
60
62
|
|
|
63
|
+
function syncLocalBmadSkills() {
|
|
64
|
+
step('Local BMAD skills');
|
|
65
|
+
|
|
66
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
67
|
+
warn('Packaged skills not found — skipping local BMAD sync');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const entries = fs
|
|
72
|
+
.readdirSync(SKILLS_SRC, { withFileTypes: true })
|
|
73
|
+
.filter((entry) => entry.name.startsWith('bmad-'));
|
|
74
|
+
|
|
75
|
+
if (entries.length === 0) {
|
|
76
|
+
warn('No BMAD skills found in package — skipping');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const targets = [
|
|
81
|
+
path.join(CWD, '.claude', 'skills'),
|
|
82
|
+
path.join(CWD, '.codex', 'skills'),
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
let installed = 0;
|
|
86
|
+
let skipped = 0;
|
|
87
|
+
|
|
88
|
+
for (const targetRoot of targets) {
|
|
89
|
+
fs.mkdirSync(targetRoot, { recursive: true });
|
|
90
|
+
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
const src = path.join(SKILLS_SRC, entry.name);
|
|
93
|
+
const dst = path.join(targetRoot, entry.name);
|
|
94
|
+
|
|
95
|
+
if (fs.existsSync(dst)) {
|
|
96
|
+
skipped++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
entry.isDirectory() ? copyDir(src, dst) : copyFile(src, dst);
|
|
101
|
+
installed++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
ok(`${installed} BMAD skill copy(ies), ${skipped} already present`);
|
|
106
|
+
}
|
|
107
|
+
|
|
61
108
|
function initOpenSpec() {
|
|
62
109
|
step('OpenSpec');
|
|
63
110
|
if (!hasCommand('openspec')) { warn('openspec not found — run: vsaf global'); return; }
|
package/src/status.js
CHANGED
|
@@ -21,6 +21,8 @@ async function showStatus() {
|
|
|
21
21
|
checkPath('CLAUDE.md', 'Workflow rules');
|
|
22
22
|
checkPath('Makefile', 'Makefile');
|
|
23
23
|
checkPath('scripts/session-end-check.sh', 'Session-end hook');
|
|
24
|
+
checkProjectSkillDir('.claude/skills', 'Project BMAD skills (.claude)');
|
|
25
|
+
checkProjectSkillDir('.codex/skills', 'Project BMAD skills (.codex)');
|
|
24
26
|
checkPath('.gitnexus', 'GitNexus index');
|
|
25
27
|
checkPath('openspec', 'OpenSpec');
|
|
26
28
|
checkPath('mempalace.yaml', 'MemPalace');
|
|
@@ -48,4 +50,19 @@ function checkPath(rel, label) {
|
|
|
48
50
|
console.log(` ${exists ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m'} ${label}`);
|
|
49
51
|
}
|
|
50
52
|
|
|
53
|
+
function checkProjectSkillDir(rel, label) {
|
|
54
|
+
const dir = path.join(process.cwd(), rel);
|
|
55
|
+
if (!fs.existsSync(dir)) {
|
|
56
|
+
console.log(` \x1b[31m✗\x1b[0m ${label}`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const count = fs.readdirSync(dir).filter((name) => name.startsWith('bmad-')).length;
|
|
61
|
+
if (count > 0) {
|
|
62
|
+
console.log(` \x1b[32m✓\x1b[0m ${label} (${count})`);
|
|
63
|
+
} else {
|
|
64
|
+
console.log(` \x1b[31m✗\x1b[0m ${label} (0)`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
51
68
|
module.exports = { showStatus };
|