Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .claude/hooks/stop-quality-gate.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env node
// Stop hook: warns about uncommitted changes, wrong branch, and version mismatches

import { execSync } from 'child_process';

const git = (cmd) => execSync(cmd, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });

let warnings = '';

try {
// Check if on main branch
const branch = git('git rev-parse --abbrev-ref HEAD').trim();
if (branch === 'main' || branch === 'master') {
warnings += `On ${branch} branch! Create a feature branch before committing. `;
}

// Check for uncommitted changes
let hasChanges = false;
try {
git('git diff --quiet');
} catch {
hasChanges = true;
}
try {
git('git diff --cached --quiet');
} catch {
hasChanges = true;
}
if (hasChanges) {
warnings += 'Uncommitted changes detected. ';
}

// Check for version mismatch between core and web
const coreVersion = git('node -p "require(\'./packages/core/package.json\').version"').trim();
const webVersion = git('node -p "require(\'./packages/web/package.json\').version"').trim();
if (coreVersion !== webVersion) {
warnings += `Version mismatch: core=${coreVersion} web=${webVersion}. `;
}
} catch {
// Best effort
}

if (warnings) {
console.log(
JSON.stringify({
systemMessage: `Quality gate: ${warnings}`
})
);
}

process.exit(0);
71 changes: 71 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,64 @@
{
"permissions": {
"allow": [
"Bash(pnpm *)",
"Bash(pnpm)",
"Bash(git status*)",
"Bash(git diff*)",
"Bash(git log*)",
"Bash(git branch*)",
"Bash(git checkout*)",
"Bash(git switch*)",
"Bash(git add *)",
"Bash(git commit *)",
"Bash(git push *)",
"Bash(git rebase*)",
"Bash(git stash*)",
"Bash(git rev-parse*)",
"Bash(git show *)",
"Bash(git fetch*)",
"Bash(git ls-files*)",
"Bash(git merge *)",
"Bash(git tag *)",
"Bash(git remote *)",
"Bash(gh pr *)",
"Bash(gh issue *)",
"Bash(gh api *)",
"Bash(gh run *)",
"Bash(ls *)",
"Bash(mkdir *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(wc *)",
"Bash(bash scripts/deploy.sh*)",
"Bash(docker buildx *)"
],
"deny": [
"Bash(git push --force *main*)",
"Bash(git push --force *master*)",
"Bash(git push origin main*)",
"Bash(git push origin master*)",
"Bash(git checkout main && git merge*)",
"Bash(git switch main && git merge*)",
"Bash(rm -rf /)",
"Bash(rm -rf ~*)",
"Bash(rm -rf ..*)",
"Bash(curl * | sh*)",
"Bash(curl * | bash*)",
"Bash(wget * | sh*)",
"Bash(npm install*)",
"Bash(npm i *)",
"Bash(npm ci*)",
"Bash(npm add *)",
"Bash(yarn *)",
"Write(.env)",
"Write(.env.local)",
"Edit(.env)",
"Edit(.env.local)",
"Write(pnpm-lock.yaml)",
"Edit(pnpm-lock.yaml)"
]
},
"hooks": {
"PreToolUse": [
{
Expand All @@ -23,6 +83,17 @@
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "node \"$CLAUDE_PROJECT_DIR/.claude/hooks/stop-quality-gate.mjs\""
}
]
}
]
}
}
8 changes: 8 additions & 0 deletions .claude/settings.local.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"// README": "Copy to .claude/settings.local.json and customize. This file is gitignored.",
"permissions": {
"allow": [
"Bash(cp /path/to/your/web-app-template/* /path/to/netrock-cli/templates/*)"
]
}
}
46 changes: 46 additions & 0 deletions .claude/skills/add-feature/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
description: Scaffold a new generator feature (definition, manifest, templates)
user-invocable: true
argument-hint: '<feature-id> <feature-name>'
---

# /add-feature

Scaffolds a new feature for the netrock generator following the checklist in CLAUDE.md.

## Steps

1. **Define the feature** in `packages/core/src/features/definitions.ts`:
- Add to the `featureDefinitions` array
- Set id, name, description, details, dependencies, group
- Set `required: false`, `defaultEnabled: false` unless told otherwise

2. **Create the manifest** at `packages/core/src/manifests/{feature-id}.ts`:
- Follow the pattern from existing manifests (e.g., `email.ts`, `jobs.ts`)
- Export a `register{Feature}Manifest()` function
- List all template files with correct `templated` flags

3. **Register the manifest** in `packages/core/src/manifests/index.ts`:
- Import and call the register function in `registerAllManifests()`

4. **Add template files** to `templates/`:
- Use `MyProject` as the namespace placeholder
- Add `@feature` markers in existing cross-cutting template files

5. **Update snapshots**: `pnpm --filter @netrock/core exec vitest run --update`

6. **Verify**: `pnpm test && pnpm build`

7. **Add CI matrix entry** in `.github/workflows/ci.yml` if testable independently

## Checklist

After implementation, verify:

- Feature in `featureDefinitions` with correct deps
- Manifest lists all files with correct `templated` flags
- Manifest registered in index.ts
- Template files exist in `templates/`
- No residual `@feature` markers in non-templated files
- `pnpm test` passes (snapshots updated)
- `pnpm build` passes
29 changes: 29 additions & 0 deletions .claude/skills/bump-version/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
description: Bump version in both packages and update CHANGELOG.md
user-invocable: true
argument-hint: '[major|minor|patch] [description]'
---

# /bump-version

Bumps the version in both `packages/core/package.json` and `packages/web/package.json` (they must always match), and adds an entry to CHANGELOG.md.

## Steps

1. Read the current version from `packages/core/package.json`
2. Determine the bump type from the argument (default: patch). Follow the versioning table in CLAUDE.md.
3. Calculate the new version
4. Update `version` in both:
- `packages/core/package.json`
- `packages/web/package.json`
5. Add a new section at the top of CHANGELOG.md (after the header) with today's date
- Use the format: `## [X.Y.Z] - YYYY-MM-DD` with Added/Changed/Fixed subsections
- If the user provided a description, use it. Otherwise, review `git log` since the last tag/version and summarize.
- Focus on what users experience (see CLAUDE.md "What goes in the changelog")
6. Commit: `chore: bump to {version}`

## Rules

- Both package.json versions MUST match after the bump
- Never bump for internal refactoring, snapshot updates, CI changes, or CLAUDE.md edits
- Changelog entries focus on generated project changes and web UI changes
37 changes: 37 additions & 0 deletions .claude/skills/create-pr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
description: Create a pull request for the current branch
user-invocable: true
argument-hint: '[base branch]'
---

# /create-pr

Creates a pull request for the current branch.

## Steps

1. Check `git status` - commit any uncommitted changes first
2. Verify NOT on main
3. Review all commits on this branch: `git log main..HEAD --oneline`
4. Push: `git push -u origin $(git branch --show-current)`
5. Create PR with `gh pr create`:
- Title: Conventional Commit format, under 70 chars
- Base: argument if provided, otherwise `main`
- Body format:

```
## Summary
- Bullet points summarizing the changes

## Test plan
- [ ] `pnpm test` passes
- [ ] `pnpm build` passes
- [ ] [Additional checks relevant to the changes]
```

6. Report the PR URL

## Rules

- Squash-and-merge only
- No Co-Authored-By lines
31 changes: 31 additions & 0 deletions .claude/skills/deploy/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
description: Build and deploy the web UI to Docker Hub
user-invocable: true
---

# /deploy

Builds and pushes the Docker image, then provides the VPS update command.

## Steps

1. Verify on `main` branch (warn if not)
2. Verify no uncommitted changes
3. Verify tests pass: `pnpm test && pnpm build`
4. Run the deploy script:

```bash
bash scripts/deploy.sh
```

This builds `fpindej/netrock-web:{version}` + `:latest` and pushes to Docker Hub.

5. Report the deployed version and VPS command:
```
cd /var/apps/netrock-cli && docker compose pull && docker compose up -d
```

## Rules

- Never deploy with failing tests
- If there are generator-facing changes, version must be bumped first (use `/bump-version`)
48 changes: 48 additions & 0 deletions .claude/skills/sync-templates/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
description: Sync template files from the source netrock repo
user-invocable: true
argument-hint: '[PR number or description]'
---

# /sync-templates

Syncs template files from the source project (fpindej/netrock) into this generator's `templates/` directory.

The source repo is at `~/source/web-app-template`.

## Steps

1. **Identify what to sync**: If a PR number is given, fetch the PR diff with `gh pr view` / `gh pr diff` from `fpindej/netrock`. Otherwise, ask the user.

2. **Copy files** from source to `templates/`:
- Root files (`.gitignore`, `CLAUDE.md`, `.claude/`) map to `templates/` directly
- `src/backend/...` maps to `templates/src/backend/...`
- `src/frontend/...` maps to `templates/src/frontend/...`

3. **Preserve @feature markers**: This is critical.
- Before copying a `templated: true` file, read the existing template version
- After copying, compare: if markers were lost, restore them manually
- For non-templated files, direct copy is safe
- When in doubt, check the manifest: `grep` for the file path in `packages/core/src/manifests/`

4. **Register new files** in the relevant manifest (`packages/core/src/manifests/*.ts`):
- Set `templated: true` for files containing `@feature` markers
- Determine which manifest based on the feature the file belongs to

5. **Add @feature markers** to new files if they contain feature-specific content:
- Auth-specific code: `# @feature auth` / `# @end` or `<!-- @feature auth -->` / `<!-- @end -->`
- Frontend-specific: `@feature frontend`
- Check existing template files for patterns

6. **Update snapshots**: `pnpm --filter @netrock/core exec vitest run --update`

7. **Verify**: `pnpm test && pnpm build`

8. Commit: `feat(templates): sync {description} from netrock PR #{number}`

## Key Rules

- NEVER lose existing `@feature` markers - they are the core value of this generator
- Non-templated files can be copied directly
- Always run tests after sync - snapshot failures reveal missed markers
- `Directory.Packages.props` is `templated: true` (has @feature markers) - never direct copy
21 changes: 21 additions & 0 deletions .claude/skills/verify/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
description: Run full verification (tests, build, type-check)
user-invocable: true
---

# /verify

Run the verification pipeline. Report each step's result. Stop on first failure.

```bash
# Core tests + build
pnpm --filter @netrock/core exec vitest run && pnpm --filter @netrock/core build

# Web type-check
pnpm --filter @netrock/web check

# Full build (both packages)
pnpm build
```

Fix all failures before reporting success. Loop until green.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Thumbs.db
*.swp
*.swo

# Claude Code local settings (user-specific permission overrides)
.claude/settings.local.json

# Generated project output (pnpm generate defaults to output/)
/output/
/test-app/
Loading