@zachjxyz/jvn 0.1.0
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/LICENSE +21 -0
- package/README.md +136 -0
- package/bin/jvn.mjs +403 -0
- package/package.json +32 -0
- package/template/.claude/agents/architect.md +37 -0
- package/template/.claude/agents/code-reviewer.md +28 -0
- package/template/.claude/agents/constitutional-validator.md +53 -0
- package/template/.claude/agents/product-manager.md +26 -0
- package/template/.claude/agents/ux-designer.md +25 -0
- package/template/.claude/commands/build.md +147 -0
- package/template/.claude/commands/design.md +92 -0
- package/template/.claude/commands/report-fix.md +98 -0
- package/template/.claude/commands/report.md +86 -0
- package/template/.claude/commands/spec.md +79 -0
- package/template/.claude/dot-gitignore +1 -0
- package/template/.claude/settings.json +27 -0
- package/template/.claude/skills/constitution-reference/SKILL.md +32 -0
- package/template/.claude/skills/review-checklist/SKILL.md +49 -0
- package/template/.claude/skills/stack-knowledge/SKILL.md +49 -0
- package/template/CLAUDE.md +61 -0
- package/template/constitution.md +51 -0
- package/template/dot-gitignore-root +29 -0
- package/template/dot-mcp.json +3 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zach J
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# jvn
|
|
2
|
+
|
|
3
|
+
Spec-driven development with Claude Code.
|
|
4
|
+
|
|
5
|
+
Named after **John von Neumann** — the man who wrote the spec that defined computing.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd my-project
|
|
11
|
+
npx jvn
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
That's it. Then:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
claude
|
|
18
|
+
/spec "what you want to build"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## What it does
|
|
22
|
+
|
|
23
|
+
`jvn` sets up spec-driven development in any project:
|
|
24
|
+
|
|
25
|
+
1. Installs 18 curated skills globally (Neon, React, Better Auth, TDD, and more)
|
|
26
|
+
2. Initializes [GitHub Spec-Kit](https://github.com/github/spec-kit) with Claude Code integration
|
|
27
|
+
3. Pre-configures a project constitution with engineering best practices
|
|
28
|
+
4. Adds 5 specialized agents and 5 workflow commands
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
After setup, open `claude` and use:
|
|
33
|
+
|
|
34
|
+
| Command | What it does |
|
|
35
|
+
|---------|-------------|
|
|
36
|
+
| `/spec "feature"` | Describe what you want to build. Creates a rich specification with product, UX, and technical considerations. |
|
|
37
|
+
| `/design` | Create the technical plan. Architecture review and constitutional validation included. |
|
|
38
|
+
| `/build` | Build it phase by phase. TDD enforced, tests run, code reviewed, your approval required at every gate. |
|
|
39
|
+
| `/report` | Analyze the project — tech stack, routes, SWOT analysis. Generates a timestamped report. |
|
|
40
|
+
| `/report-fix @latest` | Systematically fix issues from the most recent report. |
|
|
41
|
+
|
|
42
|
+
Flow: `/spec` → `/design` → `/build`
|
|
43
|
+
|
|
44
|
+
## CLI Flags
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
jvn # Set up spec-driven dev
|
|
48
|
+
jvn --dry-run # Preview what would happen
|
|
49
|
+
jvn --force # Overwrite existing files
|
|
50
|
+
jvn --skip-skills # Skip skill installation
|
|
51
|
+
jvn --skip-speckit # Skip Spec-Kit init
|
|
52
|
+
jvn --report # Generate project report
|
|
53
|
+
jvn --report-fix @latest # Fix issues from latest report
|
|
54
|
+
jvn --report-fix report-030626 # Fix issues from specific report
|
|
55
|
+
jvn --version # Print version
|
|
56
|
+
jvn --help # Print help
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## What Gets Installed
|
|
60
|
+
|
|
61
|
+
### Skills (18)
|
|
62
|
+
|
|
63
|
+
| Skill | Source | Category |
|
|
64
|
+
|-------|--------|----------|
|
|
65
|
+
| Neon Postgres | neondatabase/agent-skills | Database |
|
|
66
|
+
| Better Auth | better-auth/skills | Auth |
|
|
67
|
+
| React Best Practices | vercel-labs/agent-skills | Frontend |
|
|
68
|
+
| Composition Patterns | vercel-labs/agent-skills | Frontend |
|
|
69
|
+
| Frontend Design | anthropics/skills | Design |
|
|
70
|
+
| Web Design Guidelines | vercel-labs/agent-skills | Design |
|
|
71
|
+
| API Design | wshobson/agents | API |
|
|
72
|
+
| Webapp Testing | anthropics/skills | Testing |
|
|
73
|
+
| Test-Driven Development | obra/superpowers | Testing |
|
|
74
|
+
| Dogfood QA | vercel-labs/agent-browser | QA |
|
|
75
|
+
| MCP Builder | anthropics/skills | Tools |
|
|
76
|
+
| Doc Coauthoring | anthropics/skills | Docs |
|
|
77
|
+
| PDF | anthropics/skills | Docs |
|
|
78
|
+
| DOCX | anthropics/skills | Docs |
|
|
79
|
+
| Resend Email | resend/resend-skills | Email |
|
|
80
|
+
| Skill Creator | anthropics/skills | Meta |
|
|
81
|
+
| Find Skills | vercel-labs/skills | Meta |
|
|
82
|
+
| Git Commit | github/awesome-copilot | Git |
|
|
83
|
+
|
|
84
|
+
### Agents (5)
|
|
85
|
+
|
|
86
|
+
| Agent | Model | Role |
|
|
87
|
+
|-------|-------|------|
|
|
88
|
+
| architect | opus | System design, data modeling, API contracts |
|
|
89
|
+
| product-manager | sonnet | User stories, acceptance criteria, scope |
|
|
90
|
+
| ux-designer | sonnet | User flows, states, accessibility |
|
|
91
|
+
| code-reviewer | sonnet | Correctness, TDD enforcement, security |
|
|
92
|
+
| constitutional-validator | opus | Constitution compliance gate |
|
|
93
|
+
|
|
94
|
+
## Architecture
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
/spec → /design → /build
|
|
98
|
+
│ │ │
|
|
99
|
+
│ │ ├── speckit-implement (code generation, TDD)
|
|
100
|
+
│ │ ├── webapp-testing (Playwright validation)
|
|
101
|
+
│ │ ├── code-reviewer agent (TDD + checklist)
|
|
102
|
+
│ │ ├── user validation gate (your approval)
|
|
103
|
+
│ │ └── dogfood (final QA exploration)
|
|
104
|
+
│ │
|
|
105
|
+
│ ├── speckit-plan (base plan)
|
|
106
|
+
│ ├── architect agent (review)
|
|
107
|
+
│ ├── constitutional-validator agent (gate)
|
|
108
|
+
│ └── speckit-tasks (task breakdown)
|
|
109
|
+
│
|
|
110
|
+
├── speckit-specify (base spec)
|
|
111
|
+
├── product-manager agent (enrichment)
|
|
112
|
+
└── ux-designer agent (UX brief)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Default Stack
|
|
116
|
+
|
|
117
|
+
- **Next.js** (App Router) on Vercel
|
|
118
|
+
- **Neon Postgres** via Drizzle ORM
|
|
119
|
+
- **Better Auth** with Drizzle adapter
|
|
120
|
+
- **Tailwind CSS**
|
|
121
|
+
|
|
122
|
+
The constitution and stack knowledge are pre-configured for this stack. To customize:
|
|
123
|
+
|
|
124
|
+
1. Edit `CLAUDE.md` — uncomment the Stack Override section
|
|
125
|
+
2. Edit `.specify/memory/constitution.md` — update Stack Principles
|
|
126
|
+
3. Edit `.claude/skills/stack-knowledge/SKILL.md` — update patterns
|
|
127
|
+
|
|
128
|
+
## Prerequisites
|
|
129
|
+
|
|
130
|
+
- [Node.js](https://nodejs.org) 18+
|
|
131
|
+
- [Claude Code](https://claude.ai/code)
|
|
132
|
+
- [GitHub Spec-Kit](https://github.com/github/spec-kit) (`pipx install specify-cli`)
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
MIT
|
package/bin/jvn.mjs
ADDED
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { execSync, spawn } from 'node:child_process';
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
5
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { platform, homedir } from 'node:os';
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
12
|
+
const TEMPLATE_DIR = join(PKG_ROOT, 'template');
|
|
13
|
+
const VERSION = JSON.parse(readFileSync(join(PKG_ROOT, 'package.json'), 'utf8')).version;
|
|
14
|
+
|
|
15
|
+
// ── Formatting ──────────────────────────────
|
|
16
|
+
|
|
17
|
+
const BOLD = '\x1b[1m';
|
|
18
|
+
const DIM = '\x1b[2m';
|
|
19
|
+
const GREEN = '\x1b[32m';
|
|
20
|
+
const RED = '\x1b[31m';
|
|
21
|
+
const YELLOW = '\x1b[33m';
|
|
22
|
+
const RESET = '\x1b[0m';
|
|
23
|
+
|
|
24
|
+
const header = (msg) => console.log(`\n${BOLD}${msg}${RESET}`);
|
|
25
|
+
const ok = (msg) => console.log(` ${GREEN}✓${RESET} ${msg}`);
|
|
26
|
+
const warn = (msg) => console.log(` ${YELLOW}!${RESET} ${msg}`);
|
|
27
|
+
const fail = (msg) => { console.log(` ${RED}✗${RESET} ${msg}`); process.exit(1); };
|
|
28
|
+
const info = (msg) => console.log(` ${DIM}${msg}${RESET}`);
|
|
29
|
+
|
|
30
|
+
// ── Skill Manifest ──────────────────────────
|
|
31
|
+
|
|
32
|
+
const SKILLS = [
|
|
33
|
+
{ name: 'neon-postgres', source: 'neondatabase/agent-skills@neon-postgres', label: 'Neon Postgres' },
|
|
34
|
+
{ name: 'better-auth-best-practices', source: 'better-auth/skills@better-auth-best-practices', label: 'Better Auth' },
|
|
35
|
+
{ name: 'vercel-react-best-practices', source: 'vercel-labs/agent-skills@vercel-react-best-practices', label: 'React Best Practices' },
|
|
36
|
+
{ name: 'vercel-composition-patterns', source: 'vercel-labs/agent-skills@vercel-composition-patterns', label: 'Composition Patterns' },
|
|
37
|
+
{ name: 'frontend-design', source: 'anthropics/skills@frontend-design', label: 'Frontend Design' },
|
|
38
|
+
{ name: 'web-design-guidelines', source: 'vercel-labs/agent-skills@web-design-guidelines', label: 'Web Design Guidelines' },
|
|
39
|
+
{ name: 'api-design-principles', source: 'wshobson/agents@api-design-principles', label: 'API Design' },
|
|
40
|
+
{ name: 'webapp-testing', source: 'anthropics/skills@webapp-testing', label: 'Webapp Testing' },
|
|
41
|
+
{ name: 'mcp-builder', source: 'anthropics/skills@mcp-builder', label: 'MCP Builder' },
|
|
42
|
+
{ name: 'doc-coauthoring', source: 'anthropics/skills@doc-coauthoring', label: 'Doc Coauthoring' },
|
|
43
|
+
{ name: 'pdf', source: 'anthropics/skills@pdf', label: 'PDF' },
|
|
44
|
+
{ name: 'docx', source: 'anthropics/skills@docx', label: 'DOCX' },
|
|
45
|
+
{ name: 'resend', source: 'resend/resend-skills@resend', label: 'Resend Email' },
|
|
46
|
+
{ name: 'skill-creator', source: 'anthropics/skills@skill-creator', label: 'Skill Creator' },
|
|
47
|
+
{ name: 'find-skills', source: 'vercel-labs/skills@find-skills', label: 'Find Skills' },
|
|
48
|
+
{ name: 'git-commit', source: 'github/awesome-copilot@git-commit', label: 'Git Commit' },
|
|
49
|
+
{ name: 'test-driven-development', source: 'obra/superpowers@test-driven-development', label: 'Test-Driven Development' },
|
|
50
|
+
{ name: 'dogfood', source: 'vercel-labs/agent-browser@dogfood', label: 'Dogfood QA' },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
// ── Dotfile Rename Map ──────────────────────
|
|
54
|
+
|
|
55
|
+
const RENAME_MAP = {
|
|
56
|
+
'dot-gitignore': '.gitignore',
|
|
57
|
+
'dot-gitignore-root': '.gitignore',
|
|
58
|
+
'dot-mcp.json': '.mcp.json',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// ── Utilities ───────────────────────────────
|
|
62
|
+
|
|
63
|
+
function commandExists(cmd) {
|
|
64
|
+
try {
|
|
65
|
+
execSync(`command -v ${cmd}`, { stdio: 'ignore' });
|
|
66
|
+
return true;
|
|
67
|
+
} catch {
|
|
68
|
+
// Windows fallback
|
|
69
|
+
try {
|
|
70
|
+
execSync(`where ${cmd}`, { stdio: 'ignore' });
|
|
71
|
+
return true;
|
|
72
|
+
} catch {
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function claudeExists() {
|
|
79
|
+
if (commandExists('claude')) return true;
|
|
80
|
+
const localPath = join(homedir(), '.claude', 'local', 'claude');
|
|
81
|
+
return existsSync(localPath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function specifyCmd() {
|
|
85
|
+
if (commandExists('specify')) return 'specify';
|
|
86
|
+
const localPath = join(homedir(), '.local', 'bin', 'specify');
|
|
87
|
+
if (existsSync(localPath)) return localPath;
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function skillInstalled(name) {
|
|
92
|
+
const skillDir = join(homedir(), '.claude', 'skills', name);
|
|
93
|
+
return existsSync(skillDir);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function copyDirRecursive(src, dest, { force = false, dryRun = false } = {}) {
|
|
97
|
+
let copied = 0;
|
|
98
|
+
let skipped = 0;
|
|
99
|
+
|
|
100
|
+
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
|
101
|
+
const srcPath = join(src, entry.name);
|
|
102
|
+
const destName = RENAME_MAP[entry.name] || entry.name;
|
|
103
|
+
const destPath = join(dest, destName);
|
|
104
|
+
|
|
105
|
+
if (entry.isDirectory()) {
|
|
106
|
+
if (!dryRun) mkdirSync(destPath, { recursive: true });
|
|
107
|
+
const sub = copyDirRecursive(srcPath, destPath, { force, dryRun });
|
|
108
|
+
copied += sub.copied;
|
|
109
|
+
skipped += sub.skipped;
|
|
110
|
+
} else {
|
|
111
|
+
if (existsSync(destPath) && !force) {
|
|
112
|
+
skipped++;
|
|
113
|
+
if (dryRun) info(` skip: ${destPath} (exists)`);
|
|
114
|
+
} else {
|
|
115
|
+
copied++;
|
|
116
|
+
if (dryRun) {
|
|
117
|
+
info(` copy: ${destPath}`);
|
|
118
|
+
} else {
|
|
119
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
120
|
+
cpSync(srcPath, destPath);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return { copied, skipped };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// ── Commands ────────────────────────────────
|
|
130
|
+
|
|
131
|
+
function printHelp() {
|
|
132
|
+
console.log(`
|
|
133
|
+
${BOLD}jvn${RESET} — Spec-driven development with Claude Code
|
|
134
|
+
Named after John von Neumann, who wrote the spec that defined computing.
|
|
135
|
+
|
|
136
|
+
${BOLD}Usage:${RESET}
|
|
137
|
+
jvn Set up spec-driven dev in current directory
|
|
138
|
+
jvn --dry-run Show what would happen without doing anything
|
|
139
|
+
jvn --report Generate a project analysis report
|
|
140
|
+
jvn --report-fix <id> Fix issues from a report (@latest or report-MMDDyy-HHmmss)
|
|
141
|
+
|
|
142
|
+
${BOLD}Setup flags:${RESET}
|
|
143
|
+
--force Overwrite existing files (default: skip)
|
|
144
|
+
--skip-skills Skip skill installation
|
|
145
|
+
--skip-speckit Skip Spec-Kit initialization
|
|
146
|
+
|
|
147
|
+
${BOLD}Info:${RESET}
|
|
148
|
+
--version, -v Print version
|
|
149
|
+
--help, -h Print this help
|
|
150
|
+
|
|
151
|
+
${BOLD}After setup:${RESET}
|
|
152
|
+
claude Start Claude Code, then:
|
|
153
|
+
/spec "feature" Describe what you want to build
|
|
154
|
+
/design Create the technical plan
|
|
155
|
+
/build Implement it phase by phase
|
|
156
|
+
`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function printVersion() {
|
|
160
|
+
console.log(`jvn v${VERSION}`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function runSetup({ dryRun = false, force = false, skipSkills = false, skipSpeckit = false } = {}) {
|
|
164
|
+
console.log('');
|
|
165
|
+
console.log(`${BOLD} jvn${RESET}${DIM} — John von Neumann${RESET}`);
|
|
166
|
+
console.log('─────────────────────────────────────────────');
|
|
167
|
+
|
|
168
|
+
if (dryRun) {
|
|
169
|
+
console.log(`${YELLOW} DRY RUN — no changes will be made${RESET}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ── Prerequisites ───────────────────────
|
|
173
|
+
|
|
174
|
+
header('Checking prerequisites...');
|
|
175
|
+
|
|
176
|
+
if (!commandExists('node')) fail('Node.js not found. Install from https://nodejs.org');
|
|
177
|
+
if (!dryRun) ok(`Node.js found (${process.version})`);
|
|
178
|
+
else info(`Node.js found (${process.version})`);
|
|
179
|
+
|
|
180
|
+
if (!commandExists('npx')) fail('npx not found. Comes with Node.js');
|
|
181
|
+
if (!dryRun) ok('npx available');
|
|
182
|
+
else info('npx available');
|
|
183
|
+
|
|
184
|
+
if (!claudeExists()) fail('Claude Code not found. Install: npm install -g @anthropic-ai/claude-code');
|
|
185
|
+
if (!dryRun) ok('Claude Code found');
|
|
186
|
+
else info('Claude Code found');
|
|
187
|
+
|
|
188
|
+
const specify = specifyCmd();
|
|
189
|
+
if (!specify) fail('Spec-Kit not found. Install: pipx install specify-cli');
|
|
190
|
+
if (!dryRun) ok('Spec-Kit (specify) found');
|
|
191
|
+
else info('Spec-Kit (specify) found');
|
|
192
|
+
|
|
193
|
+
// ── Copy Template ──────────────────────
|
|
194
|
+
|
|
195
|
+
header('Copying template files...');
|
|
196
|
+
|
|
197
|
+
const { copied, skipped } = copyDirRecursive(TEMPLATE_DIR, process.cwd(), { force, dryRun });
|
|
198
|
+
|
|
199
|
+
if (!dryRun) {
|
|
200
|
+
ok(`Copied ${copied} files (skipped ${skipped} existing)`);
|
|
201
|
+
} else {
|
|
202
|
+
info(`Would copy ${copied} files (skip ${skipped} existing)`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ── Install Skills ─────────────────────
|
|
206
|
+
|
|
207
|
+
if (!skipSkills) {
|
|
208
|
+
header('Installing required skills...');
|
|
209
|
+
|
|
210
|
+
let installed = 0;
|
|
211
|
+
let skillsSkipped = 0;
|
|
212
|
+
|
|
213
|
+
for (const skill of SKILLS) {
|
|
214
|
+
if (skillInstalled(skill.name)) {
|
|
215
|
+
skillsSkipped++;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (dryRun) {
|
|
220
|
+
info(`Would install: ${skill.label} (${skill.source})`);
|
|
221
|
+
installed++;
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const label = skill.label.padEnd(40);
|
|
226
|
+
process.stdout.write(` ↓ ${label}`);
|
|
227
|
+
try {
|
|
228
|
+
execSync(`npx skills add ${skill.source} -g -y`, { stdio: 'ignore' });
|
|
229
|
+
console.log(` ${GREEN}✓${RESET}`);
|
|
230
|
+
installed++;
|
|
231
|
+
} catch {
|
|
232
|
+
console.log(` ${RED}✗${RESET}`);
|
|
233
|
+
warn(`Failed to install ${skill.name}. Run manually: npx skills add ${skill.source} -g -y`);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (!dryRun) ok(`Installed ${installed} skills (skipped ${skillsSkipped} already installed)`);
|
|
238
|
+
else info(`Would install ${installed} skills (skip ${skillsSkipped} already installed)`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// ── Spec-Kit ───────────────────────────
|
|
242
|
+
|
|
243
|
+
if (!skipSpeckit) {
|
|
244
|
+
header('Setting up Spec-Kit...');
|
|
245
|
+
|
|
246
|
+
const scriptType = platform() === 'win32' ? 'ps' : 'sh';
|
|
247
|
+
const cmd = `${specify} init --here --ai claude --ai-skills --script ${scriptType} --force --no-git`;
|
|
248
|
+
|
|
249
|
+
if (dryRun) {
|
|
250
|
+
info(`Would run: ${cmd}`);
|
|
251
|
+
} else {
|
|
252
|
+
try {
|
|
253
|
+
execSync(cmd, { stdio: 'ignore' });
|
|
254
|
+
ok('Spec-Kit initialized (9 workflow skills added)');
|
|
255
|
+
} catch {
|
|
256
|
+
warn('Spec-Kit init had issues. You may need to run it manually.');
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ── Constitution ───────────────────────
|
|
262
|
+
|
|
263
|
+
header('Configuring constitution...');
|
|
264
|
+
|
|
265
|
+
const constitutionLocal = join(process.cwd(), 'constitution.md');
|
|
266
|
+
const constitutionTemplate = join(TEMPLATE_DIR, 'constitution.md');
|
|
267
|
+
const constitutionSrc = existsSync(constitutionLocal) ? constitutionLocal : constitutionTemplate;
|
|
268
|
+
const constitutionDst = join(process.cwd(), '.specify', 'memory', 'constitution.md');
|
|
269
|
+
|
|
270
|
+
if (existsSync(constitutionSrc)) {
|
|
271
|
+
if (dryRun) {
|
|
272
|
+
info(`Would install constitution at .specify/memory/constitution.md`);
|
|
273
|
+
} else {
|
|
274
|
+
mkdirSync(dirname(constitutionDst), { recursive: true });
|
|
275
|
+
cpSync(constitutionSrc, constitutionDst);
|
|
276
|
+
ok(`Constitution installed at .specify/memory/constitution.md`);
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
warn('constitution.md not found. Skipping.');
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ── Git Init ───────────────────────────
|
|
283
|
+
|
|
284
|
+
header('Initializing git...');
|
|
285
|
+
|
|
286
|
+
if (dryRun) {
|
|
287
|
+
info('Would initialize fresh git repository');
|
|
288
|
+
} else {
|
|
289
|
+
if (!existsSync(join(process.cwd(), '.git'))) {
|
|
290
|
+
try {
|
|
291
|
+
execSync('git init -q', { stdio: 'ignore' });
|
|
292
|
+
ok('Fresh repository initialized');
|
|
293
|
+
} catch {
|
|
294
|
+
warn('Git init failed. Initialize manually with: git init');
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
ok('Git repository already exists');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// ── Done ───────────────────────────────
|
|
302
|
+
|
|
303
|
+
console.log('');
|
|
304
|
+
if (dryRun) {
|
|
305
|
+
console.log(`${BOLD} Dry run complete.${RESET} No changes were made.`);
|
|
306
|
+
console.log(` Run ${BOLD}jvn${RESET} (without --dry-run) to execute.`);
|
|
307
|
+
} else {
|
|
308
|
+
console.log(`${BOLD} Ready!${RESET}`);
|
|
309
|
+
console.log(" Run 'claude' to start, then:");
|
|
310
|
+
console.log('');
|
|
311
|
+
console.log(' /spec "what you want to build" → create a feature spec');
|
|
312
|
+
console.log(' /design → create the technical plan');
|
|
313
|
+
console.log(' /build → implement it');
|
|
314
|
+
console.log('');
|
|
315
|
+
console.log(' Constitution is pre-configured.');
|
|
316
|
+
console.log(' Edit .specify/memory/constitution.md to customize.');
|
|
317
|
+
}
|
|
318
|
+
console.log('─────────────────────────────────────────────');
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function runReport() {
|
|
322
|
+
header('Generating project report...');
|
|
323
|
+
|
|
324
|
+
mkdirSync(join(process.cwd(), 'reports'), { recursive: true });
|
|
325
|
+
|
|
326
|
+
const child = spawn('claude', ['--print', '/report'], {
|
|
327
|
+
stdio: 'inherit',
|
|
328
|
+
cwd: process.cwd(),
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
child.on('error', () => {
|
|
332
|
+
fail('Could not launch Claude Code. Is it installed?');
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
child.on('exit', (code) => {
|
|
336
|
+
process.exit(code ?? 0);
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function runReportFix(reportId) {
|
|
341
|
+
if (!reportId) {
|
|
342
|
+
fail('Usage: jvn --report-fix <@latest or report-MMDDyy-HHmmss>');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Resolve @latest
|
|
346
|
+
let resolvedId = reportId;
|
|
347
|
+
if (reportId === '@latest') {
|
|
348
|
+
const reportsDir = join(process.cwd(), 'reports');
|
|
349
|
+
if (!existsSync(reportsDir)) fail('No reports/ directory found. Run jvn --report first.');
|
|
350
|
+
|
|
351
|
+
const reports = readdirSync(reportsDir)
|
|
352
|
+
.filter(f => f.startsWith('report-') && f.endsWith('.md'))
|
|
353
|
+
.sort()
|
|
354
|
+
.reverse();
|
|
355
|
+
|
|
356
|
+
if (reports.length === 0) fail('No reports found. Run jvn --report first.');
|
|
357
|
+
resolvedId = reports[0].replace('.md', '');
|
|
358
|
+
info(`Resolved @latest → ${resolvedId}`);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
header(`Fixing issues from ${resolvedId}...`);
|
|
362
|
+
|
|
363
|
+
const child = spawn('claude', ['--print', `/report-fix ${resolvedId}`], {
|
|
364
|
+
stdio: 'inherit',
|
|
365
|
+
cwd: process.cwd(),
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
child.on('error', () => {
|
|
369
|
+
fail('Could not launch Claude Code. Is it installed?');
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
child.on('exit', (code) => {
|
|
373
|
+
process.exit(code ?? 0);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ── Argument Parsing ────────────────────────
|
|
378
|
+
|
|
379
|
+
const args = process.argv.slice(2);
|
|
380
|
+
|
|
381
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
382
|
+
printHelp();
|
|
383
|
+
process.exit(0);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
387
|
+
printVersion();
|
|
388
|
+
process.exit(0);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (args.includes('--report-fix')) {
|
|
392
|
+
const idx = args.indexOf('--report-fix');
|
|
393
|
+
runReportFix(args[idx + 1]);
|
|
394
|
+
} else if (args.includes('--report')) {
|
|
395
|
+
runReport();
|
|
396
|
+
} else {
|
|
397
|
+
runSetup({
|
|
398
|
+
dryRun: args.includes('--dry-run'),
|
|
399
|
+
force: args.includes('--force'),
|
|
400
|
+
skipSkills: args.includes('--skip-skills'),
|
|
401
|
+
skipSpeckit: args.includes('--skip-speckit'),
|
|
402
|
+
});
|
|
403
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zachjxyz/jvn",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Spec-driven development with Claude Code. /spec, /design, /build.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"jvn": "bin/jvn.mjs"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"files": [
|
|
10
|
+
"bin/",
|
|
11
|
+
"template/"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"claude-code",
|
|
15
|
+
"spec-driven-development",
|
|
16
|
+
"spec-kit",
|
|
17
|
+
"ai",
|
|
18
|
+
"agents",
|
|
19
|
+
"von-neumann",
|
|
20
|
+
"tdd",
|
|
21
|
+
"ai-engineering"
|
|
22
|
+
],
|
|
23
|
+
"author": "Zach J",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/zachj/jvn.git"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: architect
|
|
3
|
+
description: Technical architecture decisions — system design, data modeling, API contracts, technology selection. Use for architectural review during planning phases.
|
|
4
|
+
model: opus
|
|
5
|
+
color: blue
|
|
6
|
+
skills:
|
|
7
|
+
- stack-knowledge
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
You are the project architect. Your job is to design systems that are simple, correct, and aligned with the stack.
|
|
11
|
+
|
|
12
|
+
## Operating Principles
|
|
13
|
+
|
|
14
|
+
- Match complexity to requirements — never apply platform-level architecture to simple products
|
|
15
|
+
- Modular design with clear boundaries between components
|
|
16
|
+
- API-first — define contracts before implementation
|
|
17
|
+
- Prefer framework conventions over custom abstractions
|
|
18
|
+
- Honor the project constitution (read `.specify/memory/constitution.md` before every review)
|
|
19
|
+
|
|
20
|
+
## Architectural Review Process
|
|
21
|
+
|
|
22
|
+
1. Read the specification and any existing plan artifacts
|
|
23
|
+
2. Evaluate against stack constraints (from your preloaded `stack-knowledge` skill)
|
|
24
|
+
3. Design: component structure, data model, API contracts
|
|
25
|
+
4. Assess risks: scalability, security, maintainability, integration points
|
|
26
|
+
5. If constitution exists, validate architecture against it
|
|
27
|
+
|
|
28
|
+
## Deliverable Format
|
|
29
|
+
|
|
30
|
+
Append an `## Architectural Review` section to plan.md containing:
|
|
31
|
+
|
|
32
|
+
- **Component Architecture**: Text diagram of components and their relationships
|
|
33
|
+
- **Data Model**: Entities, relationships, key fields
|
|
34
|
+
- **API Contracts**: Endpoints, request/response shapes
|
|
35
|
+
- **Technology Decisions**: What and why (with alternatives considered)
|
|
36
|
+
- **Risks**: Identified risks with severity and mitigation
|
|
37
|
+
- **Constitution Compliance**: How this architecture aligns with stated principles
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-reviewer
|
|
3
|
+
description: Reviews implementation for correctness, security, maintainability, and project conventions.
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: yellow
|
|
6
|
+
skills:
|
|
7
|
+
- review-checklist
|
|
8
|
+
- test-driven-development
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
You are the code reviewer. Meticulous, constructive, focused on what matters.
|
|
12
|
+
|
|
13
|
+
## Review Focus
|
|
14
|
+
|
|
15
|
+
- **Correctness** — Does the code do what the spec says? Edge cases handled?
|
|
16
|
+
- **TDD Compliance** — Was every piece of production code preceded by a failing test? (enforced by your preloaded `test-driven-development` skill)
|
|
17
|
+
- **Security** — No secrets in code, auth on protected routes, input validation, parameterized queries
|
|
18
|
+
- **Performance** — No N+1 queries, indexes on filtered columns, parallel data fetching
|
|
19
|
+
- **Maintainability** — Single responsibility, descriptive naming, early returns, no dead code
|
|
20
|
+
- **Accessibility** — Semantic HTML, ARIA labels, keyboard navigation
|
|
21
|
+
|
|
22
|
+
## Verdict Format
|
|
23
|
+
|
|
24
|
+
**APPROVED** — Ship it.
|
|
25
|
+
**APPROVED WITH SUGGESTIONS** — Ship it, but consider these improvements.
|
|
26
|
+
**NEEDS REVISION** — Must fix before proceeding.
|
|
27
|
+
|
|
28
|
+
For each finding: file:line, severity (blocker/high/medium), description, suggested fix.
|