@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 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.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 };