@ngocsangairvds/vsaf 3.1.17 → 3.1.19
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/assets/templates/.codex/instructions.md +143 -0
- package/assets/templates/CLAUDE.md +1 -1
- package/package.json +2 -2
- package/src/global.js +15 -14
- package/src/project.js +30 -4
- package/src/status.js +21 -8
- package/src/utils.js +26 -1
- package/src/workflow.js +8 -2
- package/tools/skills/vsaf-plan/SKILL.md +1 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Codex Instructions
|
|
2
|
+
|
|
3
|
+
This file provides guidance to OpenAI Codex CLI when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
> VSAF v3 — Agentic AI SDLC Framework. 3 integrated tools. 2-layer review.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
Node.js ≥18, Git. Run `npx vsaf init` (idempotent) to install all tools.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Architecture
|
|
16
|
+
|
|
17
|
+
VSAF is a meta-framework for AI-driven SDLC — not an application. It has no source code to compile. The 3-tool stack:
|
|
18
|
+
|
|
19
|
+
| Layer | Tools | Purpose |
|
|
20
|
+
|-------|-------|---------|
|
|
21
|
+
| Planning | BMAD Method | PRD, SRS, architecture docs, sprint stories |
|
|
22
|
+
| Code Intelligence | GitNexus | Impact analysis, call graph, blast radius |
|
|
23
|
+
| Implementation | Superpowers, Codex | Brainstorm, TDD execution, code review |
|
|
24
|
+
|
|
25
|
+
Key directories: `.codex/` (skills + instructions), `.vsaf/_bmad/` (BMAD workspace), `.vsaf/docs/` (artifacts), `.vsaf/_gitnexus/` (knowledge graph index).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx vsaf init # Install all tools (one-time, idempotent)
|
|
33
|
+
vsaf index # Re-index: gitnexus analyze
|
|
34
|
+
vsaf review # 2-layer review coordinator
|
|
35
|
+
vsaf status # Show status of all tools
|
|
36
|
+
vsaf clean # Clean GitNexus index
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Identity
|
|
42
|
+
|
|
43
|
+
This project uses the **VSAF v3 (Agentic AI SDLC Framework)**. All development
|
|
44
|
+
follows the SRS-first workflow below. No code ships without 2-layer review.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Knowledge Graph (GitNexus backbone)
|
|
49
|
+
|
|
50
|
+
- Run impact analysis before any code change: `gitnexus impact <symbol>`
|
|
51
|
+
- Query: "What breaks if I change X?" before touching cross-module code.
|
|
52
|
+
- Re-index after every merge: `gitnexus analyze`
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## SRS-First Workflow
|
|
57
|
+
|
|
58
|
+
### Step 0: Setup (one-time)
|
|
59
|
+
```bash
|
|
60
|
+
npx vsaf init
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Step 1: Onboard Project
|
|
64
|
+
- Run `gitnexus serve` for web UI exploration.
|
|
65
|
+
- Use `/vsaf-onboard` for the structured onboarding sequence.
|
|
66
|
+
- Do not modify code on day one.
|
|
67
|
+
|
|
68
|
+
### Step 2: Planning + Requirement → PRD → SRS
|
|
69
|
+
```
|
|
70
|
+
/vsaf-plan <requirement> # scope + impact + approach
|
|
71
|
+
/vsaf-doc-prd # write PRD from approved scope
|
|
72
|
+
/vsaf-doc-srs # write SRS from PRD
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Step 3: Testcase from SRS
|
|
76
|
+
```
|
|
77
|
+
/vsaf-test <path/to/srs>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 4: Impact Analysis
|
|
81
|
+
```
|
|
82
|
+
gitnexus impact <symbol> --direction upstream # Blast radius
|
|
83
|
+
```
|
|
84
|
+
Impact > 3 modules → split PRs.
|
|
85
|
+
|
|
86
|
+
### Step 5: Implement from SRS + Testcases
|
|
87
|
+
```
|
|
88
|
+
/vsaf-build <path/to/srs> <path/to/testcases>
|
|
89
|
+
```
|
|
90
|
+
TDD discipline: 1 commit per task.
|
|
91
|
+
|
|
92
|
+
### Step 6: Review + Ship
|
|
93
|
+
```
|
|
94
|
+
/bmad-code-review
|
|
95
|
+
vsaf index
|
|
96
|
+
/vsaf-ship
|
|
97
|
+
```
|
|
98
|
+
```bash
|
|
99
|
+
git push origin feature/<name>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Tool Commands — Quick Reference
|
|
105
|
+
|
|
106
|
+
| Action | Command |
|
|
107
|
+
|---|---|
|
|
108
|
+
| VSAF onboard | `/vsaf-onboard` |
|
|
109
|
+
| VSAF plan | `/vsaf-plan <requirement>` |
|
|
110
|
+
| VSAF doc PRD | `/vsaf-doc-prd` |
|
|
111
|
+
| VSAF doc SRS | `/vsaf-doc-srs` |
|
|
112
|
+
| VSAF testcase | `/vsaf-test <path/to/srs>` |
|
|
113
|
+
| VSAF implement | `/vsaf-build <srs> <testcases>` |
|
|
114
|
+
| VSAF ship | `/vsaf-ship` |
|
|
115
|
+
| GitNexus index | `gitnexus analyze` |
|
|
116
|
+
| GitNexus web | `gitnexus serve` |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Anti-Patterns
|
|
121
|
+
|
|
122
|
+
| Do Not | Instead |
|
|
123
|
+
|---|---|
|
|
124
|
+
| Write code before PRD/SRS/testcase | `/vsaf-plan` → `/vsaf-doc-prd` → `/vsaf-doc-srs` → `/vsaf-test` |
|
|
125
|
+
| Implement without impact gate | `gitnexus impact` before editing any symbol |
|
|
126
|
+
| Push without review | 2-layer: code-review + vsaf index |
|
|
127
|
+
| Forget to re-index | `vsaf index` after every merge |
|
|
128
|
+
| Create PRs > 400 lines | Split into smaller PRs |
|
|
129
|
+
| Trust AI output blindly | AI writes → review → human approves |
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Commit Discipline
|
|
134
|
+
|
|
135
|
+
- 1 commit per task from the plan.
|
|
136
|
+
- Each commit message: `<type>: <description>` (feat, fix, refactor, docs, test).
|
|
137
|
+
- Tests must pass after every commit.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Security
|
|
142
|
+
|
|
143
|
+
- Never hardcode credentials. Use environment variables.
|
|
@@ -22,7 +22,7 @@ VSAF is a meta-framework for AI-driven SDLC — not an application. It has no so
|
|
|
22
22
|
| Code Intelligence | GitNexus (MCP) | Impact analysis, call graph, blast radius |
|
|
23
23
|
| Implementation | Superpowers, Claude Code | Brainstorm, TDD execution, code review |
|
|
24
24
|
|
|
25
|
-
Key directories: `.claude/` (settings + skills), `.vsaf/_bmad/` (BMAD workspace), `.vsaf/docs/` (artifacts), `.
|
|
25
|
+
Key directories: `.claude/` (settings + skills), `.vsaf/_bmad/` (BMAD workspace), `.vsaf/docs/` (artifacts), `.vsaf/_gitnexus/` (knowledge graph index, `.gitnexus/` is a symlink here).
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngocsangairvds/vsaf",
|
|
3
|
-
"version": "3.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.1.19",
|
|
4
|
+
"description": "add method for codex",
|
|
5
5
|
"keywords": ["claude", "claude-code", "ai", "sdlc", "framework", "bmad", "gitnexus", "superpowers"],
|
|
6
6
|
"bin": {
|
|
7
7
|
"vsaf": "./bin/vsaf.js"
|
package/src/global.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { ok, info, warn, step, hasCommand, exec, copyDir, copyFile, CLAUDE_HOME } = require('./utils');
|
|
4
|
+
const { ok, info, warn, step, hasCommand, exec, copyDir, copyFile, CLAUDE_HOME, CODEX_HOME } = require('./utils');
|
|
5
5
|
|
|
6
|
-
const PKG_ROOT
|
|
7
|
-
const SKILLS_SRC
|
|
8
|
-
const SKILLS_DST
|
|
6
|
+
const PKG_ROOT = path.join(__dirname, '..');
|
|
7
|
+
const SKILLS_SRC = path.join(PKG_ROOT, 'tools', 'skills');
|
|
8
|
+
const SKILLS_DST = path.join(CLAUDE_HOME, 'skills');
|
|
9
|
+
const CODEX_SKILLS_DST = path.join(CODEX_HOME, 'skills');
|
|
9
10
|
|
|
10
11
|
async function installGlobal() {
|
|
11
12
|
console.log('\n\x1b[1m╔══════════════════════════════════════════╗\x1b[0m');
|
|
@@ -22,26 +23,26 @@ async function installGlobal() {
|
|
|
22
23
|
// ── Skills ──────────────────────────────────────────────────────────────────
|
|
23
24
|
|
|
24
25
|
function installSkills() {
|
|
25
|
-
step('Skills → ~/.claude/skills/');
|
|
26
|
+
step('Skills → ~/.claude/skills/ + ~/.codex/skills/');
|
|
26
27
|
|
|
27
28
|
if (!fs.existsSync(SKILLS_SRC)) {
|
|
28
29
|
warn('Skills directory not found in package — skipping');
|
|
29
30
|
return;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
fs.
|
|
33
|
-
|
|
33
|
+
const entries = fs.readdirSync(SKILLS_SRC, { withFileTypes: true });
|
|
34
34
|
let installed = 0;
|
|
35
35
|
|
|
36
|
-
for (const
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
for (const dst of [SKILLS_DST, CODEX_SKILLS_DST]) {
|
|
37
|
+
fs.mkdirSync(dst, { recursive: true });
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const src = path.join(SKILLS_SRC, entry.name);
|
|
40
|
+
entry.isDirectory() ? copyDir(src, path.join(dst, entry.name)) : copyFile(src, path.join(dst, entry.name));
|
|
41
|
+
}
|
|
42
|
+
installed = entries.length;
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
ok(`${installed} skill(s) installed/updated`);
|
|
45
|
+
ok(`${installed} skill(s) installed/updated → ~/.claude/skills + ~/.codex/skills`);
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
// ── Binary helpers ───────────────────────────────────────────────────────────
|
package/src/project.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { ok, info, warn, step, hasCommand, exec, copyDir, copyFile } = require('./utils');
|
|
4
|
+
const { ok, info, warn, step, hasCommand, exec, copyDir, copyFile, ensureGitnexusSymlink } = require('./utils');
|
|
5
5
|
|
|
6
6
|
const PKG_ROOT = path.join(__dirname, '..');
|
|
7
7
|
const TEMPLATES = path.join(PKG_ROOT, 'assets', 'templates');
|
|
@@ -23,7 +23,9 @@ async function installProject() {
|
|
|
23
23
|
console.log('\n Next steps:');
|
|
24
24
|
console.log(' vsaf status check all tools');
|
|
25
25
|
console.log(' vsaf index build/update knowledge graph');
|
|
26
|
-
console.log('
|
|
26
|
+
console.log('\n \x1b[1mActivate Superpowers:\x1b[0m');
|
|
27
|
+
console.log(' \x1b[36mClaude Code\x1b[0m /plugin install superpowers@claude-plugins-official');
|
|
28
|
+
console.log(' \x1b[36mCodex\x1b[0m skills auto-loaded — use /superpowers:brainstorming, /superpowers:code-review, etc.\n');
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
// ── File scaffold ────────────────────────────────────────────────────────────
|
|
@@ -32,10 +34,13 @@ function scaffoldFiles() {
|
|
|
32
34
|
step('Scaffolding project files');
|
|
33
35
|
|
|
34
36
|
const files = [
|
|
35
|
-
{ tpl: '.claude/settings.json',
|
|
36
|
-
{ tpl: '
|
|
37
|
+
{ tpl: '.claude/settings.json', dst: '.claude/settings.json' },
|
|
38
|
+
{ tpl: '.codex/instructions.md', dst: '.codex/instructions.md' },
|
|
39
|
+
{ tpl: 'CLAUDE.md', dst: 'CLAUDE.md' },
|
|
37
40
|
];
|
|
38
41
|
|
|
42
|
+
patchGitignore();
|
|
43
|
+
|
|
39
44
|
for (const { tpl, dst, chmod } of files) {
|
|
40
45
|
const src = path.join(TEMPLATES, tpl);
|
|
41
46
|
const dstAbs = path.join(CWD, dst);
|
|
@@ -55,6 +60,26 @@ function scaffoldFiles() {
|
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
62
|
|
|
63
|
+
/** Ensures .gitnexus (symlink) is ignored by git — it's a vsaf implementation detail. */
|
|
64
|
+
function patchGitignore() {
|
|
65
|
+
const gitignorePath = path.join(CWD, '.gitignore');
|
|
66
|
+
const entry = '.gitnexus';
|
|
67
|
+
|
|
68
|
+
let content = '';
|
|
69
|
+
if (fs.existsSync(gitignorePath)) {
|
|
70
|
+
content = fs.readFileSync(gitignorePath, 'utf8');
|
|
71
|
+
if (content.split('\n').some((l) => l.trim() === entry)) {
|
|
72
|
+
ok('.gitignore — .gitnexus already ignored');
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Append with a newline separator
|
|
76
|
+
content = content.endsWith('\n') ? content : content + '\n';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
fs.writeFileSync(gitignorePath, content + entry + '\n');
|
|
80
|
+
ok('.gitignore — added .gitnexus');
|
|
81
|
+
}
|
|
82
|
+
|
|
58
83
|
// ── Tool initialisation ──────────────────────────────────────────────────────
|
|
59
84
|
|
|
60
85
|
function scaffoldBmadWorkspace() {
|
|
@@ -135,6 +160,7 @@ function syncLocalBmadSkills() {
|
|
|
135
160
|
function initGitNexus() {
|
|
136
161
|
step('GitNexus');
|
|
137
162
|
if (!hasCommand('gitnexus')) { warn('gitnexus not found — run: vsaf global'); return; }
|
|
163
|
+
ensureGitnexusSymlink();
|
|
138
164
|
const analyzeCmd = 'gitnexus analyze --skip-git';
|
|
139
165
|
info('Indexing repository (gitnexus analyze)...');
|
|
140
166
|
exec(analyzeCmd, { cwd: CWD }) ? ok('Repository indexed') : warn('gitnexus analyze failed — run manually');
|
package/src/status.js
CHANGED
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
const { hasCommand, CLAUDE_HOME } = require('./utils');
|
|
4
|
+
const { hasCommand, CLAUDE_HOME, CODEX_HOME } = require('./utils');
|
|
5
5
|
|
|
6
6
|
async function showStatus() {
|
|
7
7
|
console.log('\n\x1b[1mVSAF Status\x1b[0m\n');
|
|
8
8
|
|
|
9
9
|
// ── Global ─────────────────────────────────────────────────────────────────
|
|
10
|
-
console.log('\x1b[1mGlobal (machine-wide
|
|
10
|
+
console.log('\x1b[1mGlobal (machine-wide)\x1b[0m');
|
|
11
11
|
checkSkills();
|
|
12
|
-
|
|
12
|
+
checkCodexSkills();
|
|
13
|
+
checkCmd('gitnexus', 'GitNexus');
|
|
13
14
|
|
|
14
15
|
// ── Project ────────────────────────────────────────────────────────────────
|
|
15
16
|
console.log('\n\x1b[1mProject (current repo)\x1b[0m');
|
|
16
|
-
checkPath('.claude/settings.json',
|
|
17
|
-
checkPath('
|
|
17
|
+
checkPath('.claude/settings.json', 'Claude settings');
|
|
18
|
+
checkPath('.codex/instructions.md', 'Codex instructions');
|
|
19
|
+
checkPath('CLAUDE.md', 'Workflow rules (Claude)');
|
|
20
|
+
checkPath('AGENTS.md', 'Workflow rules (Codex/Gemini)');
|
|
18
21
|
checkPath('.vsaf/_bmad', 'BMAD workspace');
|
|
19
22
|
checkPath('.vsaf/docs', 'Project artifact folder');
|
|
20
23
|
checkProjectSkillDir('.claude/skills', 'Project BMAD skills (.claude)');
|
|
21
24
|
checkProjectSkillDir('.codex/skills', 'Project BMAD skills (.codex)');
|
|
22
|
-
checkPath('.
|
|
25
|
+
checkPath('.vsaf/_gitnexus', 'GitNexus index');
|
|
23
26
|
console.log('');
|
|
24
27
|
}
|
|
25
28
|
|
|
@@ -31,11 +34,21 @@ function checkCmd(cmd, label) {
|
|
|
31
34
|
function checkSkills() {
|
|
32
35
|
const dir = path.join(CLAUDE_HOME, 'skills');
|
|
33
36
|
if (!fs.existsSync(dir)) {
|
|
34
|
-
console.log(' \x1b[31m✗\x1b[0m
|
|
37
|
+
console.log(' \x1b[31m✗\x1b[0m Claude skills (not installed)');
|
|
35
38
|
return;
|
|
36
39
|
}
|
|
37
40
|
const count = fs.readdirSync(dir).length;
|
|
38
|
-
console.log(` \x1b[32m✓\x1b[0m
|
|
41
|
+
console.log(` \x1b[32m✓\x1b[0m Claude skills (${count} in ~/.claude/skills/)`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function checkCodexSkills() {
|
|
45
|
+
const dir = path.join(CODEX_HOME, 'skills');
|
|
46
|
+
if (!fs.existsSync(dir)) {
|
|
47
|
+
console.log(' \x1b[31m✗\x1b[0m Codex skills (not installed)');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const count = fs.readdirSync(dir).length;
|
|
51
|
+
console.log(` \x1b[32m✓\x1b[0m Codex skills (${count} in ~/.codex/skills/)`);
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
function checkPath(rel, label) {
|
package/src/utils.js
CHANGED
|
@@ -5,6 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
|
|
7
7
|
const CLAUDE_HOME = path.join(os.homedir(), '.claude');
|
|
8
|
+
const CODEX_HOME = path.join(os.homedir(), '.codex');
|
|
8
9
|
|
|
9
10
|
const ok = (msg) => console.log(` \x1b[32m✓\x1b[0m ${msg}`);
|
|
10
11
|
const info = (msg) => console.log(` \x1b[36m→\x1b[0m ${msg}`);
|
|
@@ -53,9 +54,33 @@ function hasGitCommits() {
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Ensures .gitnexus is a symlink → .vsaf/_gitnexus (actual data dir).
|
|
59
|
+
* Gitnexus hardcodes .gitnexus/ so we keep it at the root as a symlink
|
|
60
|
+
* while the real data lives inside .vsaf/.
|
|
61
|
+
*/
|
|
62
|
+
function ensureGitnexusSymlink() {
|
|
63
|
+
const cwd = process.cwd();
|
|
64
|
+
const actual = path.join(cwd, '.vsaf', '_gitnexus');
|
|
65
|
+
const linkPath = path.join(cwd, '.gitnexus');
|
|
66
|
+
|
|
67
|
+
fs.mkdirSync(actual, { recursive: true });
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
const stat = fs.lstatSync(linkPath);
|
|
71
|
+
if (stat.isSymbolicLink()) return; // already a symlink — nothing to do
|
|
72
|
+
// Real directory left behind (e.g. gitnexus recreated it after clean)
|
|
73
|
+
fs.rmSync(linkPath, { recursive: true, force: true });
|
|
74
|
+
} catch {
|
|
75
|
+
// linkPath does not exist — will create below
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fs.symlinkSync(actual, linkPath);
|
|
79
|
+
}
|
|
80
|
+
|
|
56
81
|
function getPlatform() {
|
|
57
82
|
if (process.platform === 'darwin') return 'macos';
|
|
58
83
|
return 'linux';
|
|
59
84
|
}
|
|
60
85
|
|
|
61
|
-
module.exports = { ok, info, warn, step, hasCommand, exec, copyDir, copyFile, CLAUDE_HOME, getPlatform, hasGitCommits };
|
|
86
|
+
module.exports = { ok, info, warn, step, hasCommand, exec, copyDir, copyFile, CLAUDE_HOME, CODEX_HOME, getPlatform, hasGitCommits, ensureGitnexusSymlink };
|
package/src/workflow.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
-
const { ok, info, warn, step, hasCommand, exec, hasGitCommits } = require('./utils');
|
|
5
|
+
const { ok, info, warn, step, hasCommand, exec, hasGitCommits, ensureGitnexusSymlink } = require('./utils');
|
|
6
6
|
|
|
7
7
|
function preflightCheck() {
|
|
8
8
|
// Check: is this a git repo?
|
|
@@ -37,6 +37,7 @@ function runIndex() {
|
|
|
37
37
|
return false;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
ensureGitnexusSymlink();
|
|
40
41
|
info('Running gitnexus analyze...');
|
|
41
42
|
const gitnexusOk = exec('gitnexus analyze --skip-git');
|
|
42
43
|
if (gitnexusOk) {
|
|
@@ -78,7 +79,12 @@ function runClean() {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
info('Running gitnexus clean...');
|
|
81
|
-
const cleanOk = exec('gitnexus clean');
|
|
82
|
+
const cleanOk = exec('gitnexus clean --force');
|
|
83
|
+
// gitnexus clean deletes the .gitnexus symlink — clear actual data dir too
|
|
84
|
+
const actualDir = path.join(process.cwd(), '.vsaf', '_gitnexus');
|
|
85
|
+
if (fs.existsSync(actualDir)) fs.rmSync(actualDir, { recursive: true, force: true });
|
|
86
|
+
// Restore symlink pointing at the now-empty dir
|
|
87
|
+
ensureGitnexusSymlink();
|
|
82
88
|
cleanOk ? ok('GitNexus index cleaned') : warn('gitnexus clean failed — run manually');
|
|
83
89
|
return cleanOk;
|
|
84
90
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vsaf-plan
|
|
3
|
-
description: Plan a new feature/task. Use when receiving a requirement that needs scope analysis, impact assessment, and approach strategy. Dual brainstorm (Superpowers + BMAD). Example: /vsaf-plan create user management module
|
|
3
|
+
description: "Plan a new feature/task. Use when receiving a requirement that needs scope analysis, impact assessment, and approach strategy. Dual brainstorm (Superpowers + BMAD). Example: /vsaf-plan create user management module"
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# VSAF Plan
|