opus version correction
This commit is contained in:
parent
fa50c0f402
commit
f8811fab37
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
# ── claude-config repo ignores ──
|
||||
|
||||
# Symlink created by link.sh (GStack submodule target)
|
||||
skills/gstack
|
||||
|
||||
# Install logs
|
||||
install-*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
||||
# Editors
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.idea/
|
||||
.vscode/
|
||||
31
CHANGELOG.md
Normal file
31
CHANGELOG.md
Normal file
@ -0,0 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to claude-config will be documented in this file.
|
||||
|
||||
Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [1.0.0] — 2025-04-03
|
||||
|
||||
### Added
|
||||
- 6 custom agents: analyzer, interviewer, plugin-advisor, readme-updater, refactorer, scaffolder
|
||||
- 6 custom skills: analyze, init-project, plugin-check, readme, refactor, ship-feature
|
||||
- 2 orchestrators with validation gates: init-project (13 steps), ship-feature (8 steps)
|
||||
- Multi-OS install script (apt/dnf/pacman/brew)
|
||||
- GStack as git submodule at skills-external/gstack
|
||||
- Session start hook with plugin toggle status and health check
|
||||
- Global settings.json with deny/ask/allow permission tiers
|
||||
- Per-project templates: settings.json, settings.local.json, .claudeignore, project-CLAUDE.md
|
||||
- Settings reference (SETTINGS.md)
|
||||
- doctor.sh — full setup diagnostic
|
||||
- update-all.sh — one-command update for all components
|
||||
- plugins.lock.json — version pinning for non-marketplace dependencies
|
||||
- /health skill — run doctor.sh from within Claude Code
|
||||
- Makefile — unified entry point for install/link/doctor/update
|
||||
|
||||
### Security
|
||||
- deny rules cover: destructive commands, secrets access, privilege escalation,
|
||||
code injection (eval, bash -c, xargs), pipe-to-shell, and secrets via bash (cat .env)
|
||||
- disableBypassPermissionsMode enforced globally
|
||||
- .claudeignore template with comprehensive exclusions
|
||||
@ -135,6 +135,9 @@ When working on code:
|
||||
|
||||
## STRICT MODE
|
||||
|
||||
These rules are always active in orchestrator skills (/init-project,
|
||||
/ship-feature) and during code review. They apply automatically.
|
||||
|
||||
These rules override all other instructions.
|
||||
|
||||
- Never skip workflow steps
|
||||
@ -145,6 +148,8 @@ These rules override all other instructions.
|
||||
|
||||
## FAIL FAST MODE
|
||||
|
||||
These rules are always active in every interaction. They apply automatically.
|
||||
|
||||
These rules override all other instructions.
|
||||
|
||||
- Stop immediately if requirements are unclear
|
||||
|
||||
16
Makefile
Normal file
16
Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
.PHONY: help install link doctor update
|
||||
|
||||
help: ## Show available commands
|
||||
@grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf " make %-12s %s\n", $$1, $$2}'
|
||||
|
||||
install: link ## Full install: symlinks + prerequisites + plugins
|
||||
bash install-plugins.sh
|
||||
|
||||
link: ## Create symlinks into ~/.claude/
|
||||
bash link.sh
|
||||
|
||||
doctor: ## Run setup diagnostic
|
||||
bash doctor.sh
|
||||
|
||||
update: ## Update config, submodules, plugins, and verify
|
||||
bash update-all.sh
|
||||
655
README.md
655
README.md
@ -10,77 +10,88 @@ This repo is your personal Claude Code setup, versioned and reproducible across
|
||||
|
||||
```
|
||||
claude-config/
|
||||
├── CLAUDE.md # Global coding preferences (style, rules, workflow)
|
||||
├── settings.json # Global permissions + SessionStart hook
|
||||
├── install-plugins.sh # One-shot installer: prerequisites + all plugins
|
||||
├── link.sh # Symlinks this repo into ~/.claude/
|
||||
├── .gitmodules # Submodule declaration (GStack)
|
||||
├── CLAUDE.md # Global coding preferences (style, rules, workflow)
|
||||
├── settings.json # Global permissions (77 deny / 16 ask / 57 allow rules)
|
||||
├── install-plugins.sh # One-shot installer: prerequisites + all plugins (reads plugins.lock.json)
|
||||
├── link.sh # Symlinks this repo into ~/.claude/
|
||||
├── doctor.sh # Setup diagnostic — checks symlinks, plugins, permissions, token budget
|
||||
├── update-all.sh # One-command update for all components
|
||||
├── Makefile # Unified entry point: make install / doctor / update
|
||||
├── plugins.lock.json # Version pinning for non-marketplace dependencies (RTK, GSD)
|
||||
├── version.txt # Semver version of this config
|
||||
├── CHANGELOG.md # Release history
|
||||
├── lib/
|
||||
│ └── detect-plugins.sh # Shared plugin detection — sourced by all scripts
|
||||
├── hooks/
|
||||
│ └── session-start.sh # Shows toggle plugin status at every session start
|
||||
│ └── session-start.sh # Health check + toggle plugin status at session start
|
||||
├── skills-external/
|
||||
│ └── gstack/ # Git submodule — garrytan/gstack
|
||||
│ (symlinked → ~/.claude/skills/gstack)
|
||||
│ └── gstack/ # Git submodule — garrytan/gstack (symlinked to ~/.claude/skills/gstack)
|
||||
├── .gitmodules # Submodule declaration
|
||||
├── agents/
|
||||
│ ├── analyzer.md # Factual codebase analysis (read-only)
|
||||
│ ├── git-workflow.md # Branch setup, commits, PR creation, conflict resolution
|
||||
│ ├── interviewer.md # Project questionnaire → PROJECT BRIEF
|
||||
│ ├── plugin-advisor.md # Detect plugin mismatches, recommend actions
|
||||
│ ├── readme-updater.md # CREATE / SYNC / AUDIT README (3 modes)
|
||||
│ ├── refactorer.md # Surgical refactoring with norm enforcement
|
||||
│ └── scaffolder.md # Project skeleton (CLAUDE.md, settings, structure)
|
||||
│ ├── analyzer.md # Factual codebase analysis (read-only)
|
||||
│ ├── interviewer.md # Project questionnaire → PROJECT BRIEF
|
||||
│ ├── plugin-advisor.md # Plugin check: detect mismatches, block if Superpowers missing
|
||||
│ ├── readme-updater.md # Update README from git history + codebase
|
||||
│ ├── refactorer.md # Surgical refactoring with norm enforcement
|
||||
│ └── scaffolder.md # Full project generation (CLAUDE.md, README, code)
|
||||
├── skills/
|
||||
│ ├── analyze/ # /analyze — deep factual analysis
|
||||
│ ├── git-pr/ # /git-pr — commit, push, open draft PR/MR
|
||||
│ ├── init-project/ # /init-project — full project initialization
|
||||
│ ├── plugin-check/ # /plugin-check — check plugin config vs project needs
|
||||
│ ├── readme/ # /readme — full README audit + update
|
||||
│ ├── refactor/ # /refactor — improve code without changing behavior
|
||||
│ └── ship-feature/ # /ship-feature — ship a feature end-to-end
|
||||
│ ├── analyze/ # /analyze — deep factual analysis
|
||||
│ ├── health/ # /health — run setup diagnostic
|
||||
│ ├── init-project/ # /init-project — full project initialization
|
||||
│ ├── plugin-check/ # /plugin-check — check plugin config vs project needs
|
||||
│ ├── readme/ # /readme — update README from current state
|
||||
│ ├── refactor/ # /refactor — improve code without changing behavior
|
||||
│ └── ship-feature/ # /ship-feature — ship a feature end-to-end
|
||||
└── templates/
|
||||
├── project-CLAUDE.md # Template for per-project CLAUDE.md
|
||||
├── project-CLAUDE.md # Template for per-project CLAUDE.md
|
||||
└── settings/
|
||||
├── home-settings.json # Template for ~/.claude/settings.json
|
||||
├── settings.json # Template for project .claude/settings.json
|
||||
├── settings.local.json# Template for personal .claude/settings.local.json
|
||||
├── .claudeignore # Template for project .claudeignore
|
||||
└── SETTINGS.md # Full settings reference
|
||||
├── settings.json # Template for project .claude/settings.json
|
||||
├── settings.local.json # Template for personal .claude/settings.local.json
|
||||
├── .claudeignore # Template for project .claudeignore
|
||||
└── SETTINGS.md # Full settings reference
|
||||
```
|
||||
|
||||
**Architecture:**
|
||||
**Architecture principle:**
|
||||
- `skills/` = entry points you invoke via `/skill-name`
|
||||
- `agents/` = execution units called by skills (never invoked directly)
|
||||
- Custom skills use **Superpowers** agents for implementation phases
|
||||
- **Plugins** (Superpowers, GStack, GSD, etc.) install separately via `install-plugins.sh`
|
||||
- `agents/` = execution units called by skills (never invoked directly by user)
|
||||
- `lib/` = shared shell functions sourced by scripts (plugin detection)
|
||||
- Custom skills use **Superpowers** agents for implementation phases (required — auto-detected)
|
||||
- **Plugins** (Superpowers, GStack, GSD, etc.) install separately and complement custom skills
|
||||
|
||||
---
|
||||
|
||||
## Fresh install (new machine)
|
||||
|
||||
```bash
|
||||
# 1. Clone with submodules (GStack is a git submodule)
|
||||
git clone --recurse-submodules git@github.com:youruser/claude-config.git ~/claude-config
|
||||
# 1. Clone with submodules — choose any location
|
||||
git clone --recurse-submodules git@github.com:youruser/claude-config.git
|
||||
cd claude-config
|
||||
|
||||
# 2. Symlink into ~/.claude/
|
||||
cd ~/claude-config && bash link.sh
|
||||
bash link.sh
|
||||
|
||||
# 3. Install prerequisites + all plugins
|
||||
# Handles: git, Node.js 22, Rust/Cargo, Python 3, gh CLI, glab CLI,
|
||||
# RTK, GStack (submodule), GSD, all marketplace plugins
|
||||
bash ~/claude-config/install-plugins.sh
|
||||
# 3. Install prerequisites + all plugins (detects OS, reads pinned versions from plugins.lock.json)
|
||||
bash install-plugins.sh
|
||||
|
||||
# 4. Authenticate git provider CLIs (for /git-pr)
|
||||
gh auth login # GitHub
|
||||
glab auth login # GitLab
|
||||
# Gogs/Gitea: see "Git setup" section below
|
||||
|
||||
# 5. Add Context7 API key (free at context7.com)
|
||||
# 4. Add Context7 API key (free at context7.com) — manual step
|
||||
claude mcp add --scope user context7 -- npx -y @upstash/context7-mcp --api-key YOUR_KEY
|
||||
|
||||
# 6. Restart Claude Code → /reload-plugins
|
||||
# 5. Verify setup
|
||||
bash doctor.sh
|
||||
|
||||
# 6. Restart Claude Code then run /reload-plugins
|
||||
```
|
||||
|
||||
All `claude plugin install` calls use `--scope user` — always installs
|
||||
to `~/.claude/plugins/` regardless of working directory.
|
||||
All scripts use their own location to find the repo — run them from anywhere or from the repo directory.
|
||||
Symlinks point to the repo's actual path, so renaming or moving the repo requires re-running `bash link.sh`.
|
||||
|
||||
The install script handles: git, Node.js 22, Rust/Cargo, Python 3, RTK, GStack (submodule), GSD,
|
||||
and all marketplace plugins on Linux (apt/dnf/pacman) and macOS (brew).
|
||||
|
||||
RTK and GSD versions are pinned in `plugins.lock.json`. The install script reads those
|
||||
versions automatically. Marketplace plugins install to `~/.claude/plugins/` (user scope).
|
||||
|
||||
Install output is logged to `install-YYYYMMDD-HHMMSS.log` in the repo directory for post-mortem debugging.
|
||||
|
||||
---
|
||||
|
||||
@ -94,12 +105,15 @@ to `~/.claude/plugins/` regardless of working directory.
|
||||
| `/refactor` | Improve code quality without changing behavior (strict norms) |
|
||||
| `/readme` | Full README audit — diff vs codebase, mandatory stop, surgical updates |
|
||||
| `/plugin-check` | Check active plugins vs project needs — recommend enable/disable |
|
||||
| `/git-pr` | Commit all changes, push, open draft PR/MR (GitHub/GitLab/Gogs/Gitea) |
|
||||
| `/init-project` | Initialize a complete project from scratch (full orchestrator) |
|
||||
| `/ship-feature` | Ship a feature end-to-end with validation gates (full orchestrator) |
|
||||
| `/health` | Run setup diagnostic — check symlinks, plugins, permissions, token budget |
|
||||
|
||||
### Superpowers skills (auto-invoked or explicit)
|
||||
|
||||
> **Required dependency.** Superpowers must be active for `/init-project` and `/ship-feature`.
|
||||
> The plugin-advisor (STEP 0) blocks and shows install instructions if Superpowers is missing.
|
||||
|
||||
| Command | When it auto-activates |
|
||||
|---|---|
|
||||
| `/superpowers:brainstorm` | When you describe something to build |
|
||||
@ -109,11 +123,10 @@ to `~/.claude/plugins/` regardless of working directory.
|
||||
| `test-driven-development` | Auto — when implementing |
|
||||
| `requesting-code-review` | Auto — after a feature step |
|
||||
|
||||
### GStack skills (full-product projects only)
|
||||
### GStack skills (Garry Tan — full-product projects only)
|
||||
|
||||
> Submodule at `skills-external/gstack/`, symlinked to `~/.claude/skills/gstack/`.
|
||||
> **Use when:** project has UI + design + deploy + browser QA.
|
||||
> Skip for backend-only, libs, CLI, scripts.
|
||||
> Installed as a git submodule at `skills-external/gstack/`, symlinked to `~/.claude/skills/gstack/`.
|
||||
> **Use when:** project has UI + design + deploy + browser QA. Skip for backend/lib/CLI projects.
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
@ -130,12 +143,12 @@ to `~/.claude/plugins/` regardless of working directory.
|
||||
| `/careful` | Activate safety guardrails |
|
||||
| `/freeze` | Lock edits to current directory |
|
||||
| `/retro` | Engineering retrospective |
|
||||
| `/gstack-upgrade` | Self-update GStack to latest |
|
||||
| `/gstack-upgrade` | Self-update GStack |
|
||||
|
||||
### GSD skills (multi-session large features)
|
||||
### GSD skills (glittercowboy — multi-session large features)
|
||||
|
||||
> Installed globally via `npx get-shit-done-cc --claude --global` (done by install-plugins.sh).
|
||||
> **Use when:** feature spans multiple days/sessions.
|
||||
> Install: `npx get-shit-done-cc --claude --global`
|
||||
> **Use when:** feature spans multiple days/sessions. Each session starts fresh with full context from previous phases.
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
@ -159,320 +172,135 @@ to `~/.claude/plugins/` regardless of working directory.
|
||||
### `/init-project`
|
||||
|
||||
Same rigor as `/ship-feature`. Two validation gates. Full TDD subagent pipeline for v1 features.
|
||||
Scaffolder creates only the skeleton. readme-updater handles README in two passes (CREATE + SYNC).
|
||||
Always works on a feature branch — never on main/master.
|
||||
The Scaffolder only creates the skeleton (no features, no README).
|
||||
readme-updater handles the README in two passes: CREATE then SYNC.
|
||||
|
||||
STEP 0 blocks if Superpowers is not installed (required for steps 3, 6, 8, 10, 11).
|
||||
|
||||
```
|
||||
/init-project <project idea>
|
||||
│
|
||||
├── STEP 0a: BRANCH SETUP (git-workflow) ← create feature branch from main
|
||||
│ or sync existing branch
|
||||
├── STEP 0b: PLUGIN CHECK (plugin-advisor) ← blocks if wrong plugins
|
||||
├── STEP 0: PLUGIN CHECK (plugin-advisor) ← blocks if Superpowers missing or wrong plugins
|
||||
├── STEP 1: INTERVIEWER (custom) → PROJECT BRIEF
|
||||
├── STEP 2: ANALYZER (custom) → ANALYSIS REPORT
|
||||
├── STEP 3: superpowers:brainstorming → VALIDATED DESIGN
|
||||
├── STEP 4: VALIDATION GATE #1 → approve architecture
|
||||
├── STEP 5: SCAFFOLDER (custom) → skeleton (CLAUDE.md + settings +
|
||||
│ structure + empty entry points,
|
||||
│ NO features, NO README)
|
||||
├── STEP 5b: README-UPDATER create mode → CREATE README from CLAUDE.md
|
||||
├── STEP 5: SCAFFOLDER (custom) → skeleton only (CLAUDE.md +
|
||||
│ settings + structure +
|
||||
│ empty entry points, NO features,
|
||||
│ NO README)
|
||||
├── STEP 5b: README-UPDATER create mode (custom) → CREATE README from CLAUDE.md
|
||||
├── STEP 6: superpowers:writing-plans → decompose v1 features into tasks
|
||||
├── STEP 7: VALIDATION GATE #2 → approve task plan
|
||||
├── STEP 8: superpowers:subagent-driven (TDD) → implement each feature
|
||||
├── STEP 8: superpowers:subagent-driven (TDD) → implement each feature (isolated)
|
||||
├── STEP 9: ANALYZER (custom) → regression + deviation check
|
||||
├── STEP 10: superpowers:requesting-review → full code review
|
||||
├── STEP 11: superpowers:finishing-branch → cleanup + build + tests
|
||||
└── STEP 12: README-UPDATER sync mode → sync README with implementation
|
||||
└── STEP 12: README-UPDATER sync mode (custom) → sync README with implementation
|
||||
```
|
||||
|
||||
### `/ship-feature`
|
||||
|
||||
STEP 0 blocks if Superpowers is not installed (required for steps 1, 2, 4, 6, 7).
|
||||
|
||||
```
|
||||
/ship-feature <feature description>
|
||||
│
|
||||
├── STEP 0a: BRANCH SETUP (git-workflow) ← create/sync feature branch
|
||||
├── STEP 0b: PLUGIN CHECK (plugin-advisor) ← blocks if wrong plugins
|
||||
├── STEP 1: superpowers:brainstorming → VALIDATED DESIGN
|
||||
├── STEP 2: superpowers:writing-plans → task plan
|
||||
├── STEP 3: VALIDATION GATE → user approval required
|
||||
├── STEP 4: superpowers:subagent-driven (TDD) → implementation
|
||||
├── STEP 5: ANALYZER (custom) → regression / deviation check
|
||||
├── STEP 6: superpowers:requesting-review → code review
|
||||
├── STEP 7: superpowers:finishing-branch → cleanup
|
||||
├── STEP 8: README-UPDATER sync mode → update README
|
||||
└── STEP 9: CREATE PR (optional gate) → /git-pr if user approves
|
||||
├── STEP 0: PLUGIN CHECK (plugin-advisor) ← blocks if Superpowers missing or wrong plugins
|
||||
├── STEP 1: superpowers:brainstorming → VALIDATED DESIGN
|
||||
├── STEP 2: superpowers:writing-plans → task plan
|
||||
├── STEP 3: VALIDATION GATE → user approval required
|
||||
├── STEP 4: superpowers:subagent-driven → implementation (TDD)
|
||||
├── STEP 5: ANALYZER (custom) → regression / deviation check
|
||||
├── STEP 6: superpowers:requesting-review → code review
|
||||
├── STEP 7: superpowers:finishing-branch → cleanup
|
||||
└── STEP 8: README-UPDATER sync mode → sync README with new feature
|
||||
```
|
||||
|
||||
### `/git-pr`
|
||||
|
||||
Works on any provider. Retroactive — `git diff <base>...HEAD` sees ALL changes since
|
||||
branch creation, regardless of session count. Creates a **draft PR** — you control the merge.
|
||||
|
||||
```
|
||||
/git-pr [optional title]
|
||||
│
|
||||
├── PHASE 0: Detect provider (GitHub/GitLab/Gogs/Gitea)
|
||||
│ Check CLI: gh / glab / API fallback
|
||||
├── PHASE 1: Analyze branch (retroactive)
|
||||
│ git diff <base>...HEAD — ALL changes since branch start
|
||||
│ Categorize: config / model / core / api / ui / test / docs / infra
|
||||
├── PHASE 2: Propose commit plan (conventional commits)
|
||||
│ [VALIDATION GATE] — user approves before any commit
|
||||
├── PHASE 3: Execute commits (staged per logical group)
|
||||
├── PHASE 4: Push (with conflict-safe rebase if rejected)
|
||||
└── PHASE 5: Create draft PR/MR
|
||||
GitHub → gh pr create --draft (or API)
|
||||
GitLab → glab mr create --draft (or API)
|
||||
Gogs → POST /api/v1/repos/{owner}/{repo}/pulls
|
||||
Gitea → same API format as Gogs
|
||||
```
|
||||
|
||||
**Branch → base mapping:**
|
||||
| Branch prefix | Default base | Commit type |
|
||||
|---|---|---|
|
||||
| `feature/*`, `feat/*` | `develop` or `main` | `feat:` |
|
||||
| `bugfix/*`, `fix/*` | `develop` | `fix:` |
|
||||
| `hotfix/*` | `main` | `fix:` |
|
||||
| `release/*` | `main` | `chore(release):` |
|
||||
|
||||
### `/plugin-check`
|
||||
|
||||
Standalone — run before any significant work. Also auto-runs as STEP 0b
|
||||
in `/init-project` and `/ship-feature`.
|
||||
Standalone command you can run at any time to audit your plugin config
|
||||
against what you're about to do. Also embedded as STEP 0 in both orchestrators.
|
||||
|
||||
Blocks if Superpowers is not active (required by orchestrators).
|
||||
Blocks if critical project-specific plugins are missing (frontend tools, Context7, GStack).
|
||||
|
||||
```
|
||||
/plugin-check "React + FastAPI SaaS with auth"
|
||||
/plugin-check "I want to build a React + FastAPI SaaS"
|
||||
|
||||
→ Detects active plugins
|
||||
→ Analyzes signals: frontend? design? QA? multi-session? fast-evolving libs?
|
||||
→ Produces recommendation table
|
||||
→ Blocks if critical plugins missing, or confirms "proceed"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Git setup for `/git-pr`
|
||||
|
||||
`/git-pr` auto-detects your provider from the remote URL and uses the best available
|
||||
authentication method. Here is how to set up each provider.
|
||||
|
||||
---
|
||||
|
||||
### GitHub
|
||||
|
||||
**Option A — gh CLI (recommended)**
|
||||
|
||||
```bash
|
||||
# Install (done by install-plugins.sh)
|
||||
brew install gh # macOS
|
||||
sudo apt install gh # Linux
|
||||
|
||||
# Authenticate (interactive — opens browser)
|
||||
gh auth login
|
||||
# Choose: GitHub.com → HTTPS → authenticate with browser
|
||||
|
||||
# Verify
|
||||
gh auth status
|
||||
```
|
||||
|
||||
**Option B — Personal Access Token (for CI or headless)**
|
||||
|
||||
1. Go to **github.com → Settings → Developer settings → Personal access tokens → Tokens (classic)**
|
||||
2. Click **Generate new token**
|
||||
3. Required scopes: `repo` (full), `read:org` (if org repo)
|
||||
4. Copy the token
|
||||
|
||||
```bash
|
||||
# Set in environment
|
||||
export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"
|
||||
echo 'export GITHUB_TOKEN="ghp_xxxxxxxxxxxx"' >> ~/.zshrc # persist
|
||||
|
||||
# Claude Code reads GITHUB_TOKEN automatically for gh CLI fallback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### GitLab
|
||||
|
||||
**Option A — glab CLI (recommended)**
|
||||
|
||||
```bash
|
||||
# Install (done by install-plugins.sh)
|
||||
brew install glab # macOS
|
||||
|
||||
# Authenticate
|
||||
glab auth login
|
||||
# Choose: gitlab.com → Token or browser
|
||||
|
||||
# For self-hosted GitLab
|
||||
glab auth login --hostname gitlab.yourcompany.com
|
||||
|
||||
# Verify
|
||||
glab auth status
|
||||
```
|
||||
|
||||
**Option B — Personal Access Token**
|
||||
|
||||
1. Go to **gitlab.com → User Settings → Access Tokens** (or your instance)
|
||||
2. Click **Add new token**
|
||||
3. Required scopes: `api`, `read_repository`, `write_repository`
|
||||
4. Copy the token
|
||||
|
||||
```bash
|
||||
export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"
|
||||
echo 'export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"' >> ~/.zshrc
|
||||
|
||||
# For self-hosted
|
||||
export GITLAB_HOST="https://gitlab.yourcompany.com"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Gogs
|
||||
|
||||
Gogs has no official CLI. `/git-pr` uses the REST API directly.
|
||||
|
||||
**Create an API token:**
|
||||
|
||||
1. Log in to your Gogs instance
|
||||
2. Go to **User Settings (top-right avatar) → Applications**
|
||||
3. Under **Token Name**, enter `claude-code`
|
||||
4. Click **Generate Token**
|
||||
5. Copy the token (shown only once)
|
||||
|
||||
```bash
|
||||
# Set in environment
|
||||
export GOGS_TOKEN="your-token-here"
|
||||
echo 'export GOGS_TOKEN="your-token-here"' >> ~/.zshrc
|
||||
|
||||
# Verify the API works
|
||||
curl -H "Authorization: token $GOGS_TOKEN" \
|
||||
https://your-gogs-server/api/v1/user
|
||||
# Should return your user JSON
|
||||
```
|
||||
|
||||
**Required API permissions:** read/write on repos (tokens in Gogs have full API access by default).
|
||||
|
||||
---
|
||||
|
||||
### Gitea
|
||||
|
||||
Same API format as Gogs. Gitea is a Gogs fork.
|
||||
|
||||
**Create an API token:**
|
||||
|
||||
1. Log in to your Gitea instance
|
||||
2. Go to **User Settings → Applications → Manage Access Tokens**
|
||||
3. Enter token name `claude-code`
|
||||
4. Select permissions: `Issues: Read/Write`, `Repository: Read/Write`
|
||||
5. Click **Generate Token** and copy it
|
||||
|
||||
```bash
|
||||
export GITEA_TOKEN="your-token-here"
|
||||
echo 'export GITEA_TOKEN="your-token-here"' >> ~/.zshrc
|
||||
|
||||
# Verify
|
||||
curl -H "Authorization: token $GITEA_TOKEN" \
|
||||
https://your-gitea-server/api/v1/user
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Self-hosted GitHub Enterprise
|
||||
|
||||
```bash
|
||||
# Configure gh for your instance
|
||||
gh config set -h github.yourcompany.com git_protocol https
|
||||
gh auth login --hostname github.yourcompany.com
|
||||
|
||||
# Verify
|
||||
gh auth status --hostname github.yourcompany.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Self-hosted GitLab
|
||||
|
||||
```bash
|
||||
glab auth login --hostname gitlab.yourcompany.com --token glpat-xxxx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Token security
|
||||
|
||||
- **Never commit tokens** to git — they go in `~/.zshrc`, `~/.bashrc`, or a secrets manager
|
||||
- **Rotate tokens** when they expire or are compromised
|
||||
- **Minimum scopes** — only grant what `/git-pr` needs (repo read/write)
|
||||
- Claude Code reads env vars securely — tokens are never written to disk by Claude
|
||||
|
||||
---
|
||||
|
||||
### Verify your setup
|
||||
|
||||
```bash
|
||||
# Run inside Claude Code to verify everything
|
||||
/git-pr check-auth
|
||||
# → Detects provider from current repo remote
|
||||
# → Tests authentication
|
||||
# → Reports status per provider
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
git remote get-url origin # see which provider
|
||||
gh auth status # GitHub CLI status
|
||||
glab auth status # GitLab CLI status
|
||||
curl -s -H "Authorization: token $GOGS_TOKEN" \
|
||||
<your-gogs-url>/api/v1/user | jq .login # Gogs/Gitea
|
||||
→ Blocks with OPTIONS if critical plugins are missing (including Superpowers)
|
||||
→ Or confirms "proceed" if config is optimal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Plugins reference
|
||||
|
||||
All plugins installed by `install-plugins.sh`.
|
||||
All plugins below are installed by `install-plugins.sh`.
|
||||
|
||||
### At-a-glance: always on vs toggle
|
||||
### Quick reference
|
||||
|
||||
The mechanism: Claude Code loads every active skill's **description** at session start
|
||||
into a shared budget (8000 chars). Even if never invoked, the description costs tokens.
|
||||
Disabling a plugin → descriptions never load.
|
||||
The mechanism: Claude Code loads every active skill's **description** into a shared context budget
|
||||
at session start (default 8000 chars). Even if you never invoke the skill, its description
|
||||
is already consuming tokens. **Disabling a plugin prevents its descriptions from loading entirely.**
|
||||
|
||||
A `hooks/session-start.sh` hook shows toggle status at every session start.
|
||||
Run `/plugin-check` for a full recommendation for the current project type.
|
||||
A `hooks/session-start.sh` hook shows the current toggle status at the start of every session.
|
||||
Run `/plugin-check` anytime to get a full recommendation for the current project type.
|
||||
|
||||
| Plugin | Status | Cost/session | When to enable | Installed by |
|
||||
| Plugin | Status | Passive cost | When to toggle ON | Installed by |
|
||||
|---|---|---|---|---|
|
||||
| **security-guidance** | ✅ ALWAYS ON | 0 (hook only) | — | marketplace |
|
||||
| **RTK** | ✅ ALWAYS ON | 0 (hook only) | — | cargo + rtk init |
|
||||
| **Superpowers** | ✅ ALWAYS ON | ~600–1000 | — auto-activates | marketplace |
|
||||
| **skill-creator** | ✅ ALWAYS ON | ~100 | — | marketplace |
|
||||
| **pr-review-toolkit** | ✅ ALWAYS ON | ~300 | — `/pr-review-toolkit:review-pr` | marketplace |
|
||||
| **GStack** | 🔄 TOGGLE | ~2500–3000 | Full-product: UI + design + deploy + QA browser | submodule |
|
||||
| **GSD** | 🔄 TOGGLE | ~500–800 | Feature spanning multiple days/sessions | npx |
|
||||
| **frontend-design** | 🔄 TOGGLE | ~200 | Any project with a UI | marketplace |
|
||||
| **ui-ux-pro-max** | 🔄 TOGGLE | ~400 | Design system, color/typography | marketplace |
|
||||
| **Context7 MCP** | 🔄 TOGGLE | ~200 | Fast-evolving libs (Next.js, React, Prisma…) | MCP manual |
|
||||
| **security-guidance** | ✅ ALWAYS ON | 0 tokens (hook only) | — | marketplace |
|
||||
| **RTK** | ✅ ALWAYS ON | 0 tokens (hook only) | — | cargo (pinned in plugins.lock.json) |
|
||||
| **Superpowers** | ✅ REQUIRED | ~600–1000 tokens | — required by orchestrators, auto-detected | marketplace |
|
||||
| **skill-creator** | ✅ ALWAYS ON | ~100 tokens | — | marketplace |
|
||||
| **pr-review-toolkit** | ✅ ALWAYS ON | ~300 tokens | — use `/pr-review-toolkit:review-pr` | marketplace |
|
||||
| **GStack** | 🔄 TOGGLE | ~2500–3000 tokens | Full-product: UI + design + deploy + browser QA | git submodule |
|
||||
| **GSD** | 🔄 TOGGLE | ~500–800 tokens | Feature spanning multiple days/sessions | npx (pinned in plugins.lock.json) |
|
||||
| **frontend-design** | 🔄 TOGGLE | ~200 tokens | Any project with a UI | marketplace |
|
||||
| **ui-ux-pro-max** | 🔄 TOGGLE | ~400 tokens | Design system, color/typography choices | marketplace |
|
||||
| **Context7 MCP** | 🔄 TOGGLE | ~200 tokens | Fast-evolving libs (Next.js, React, Prisma…) | MCP manual |
|
||||
|
||||
Toggle plugins start **OFF**. `/plugin-check` signals when to enable them.
|
||||
`/init-project` and `/ship-feature` run plugin-check automatically as STEP 0b.
|
||||
**Rule:** toggle plugins are OFF by default. `/plugin-check` signals when to enable them.
|
||||
If you use `/init-project` or `/ship-feature`, plugin-check runs automatically as STEP 0
|
||||
and **blocks if Superpowers is not active**.
|
||||
|
||||
### Disable a plugin for a specific project
|
||||
### Version pinning
|
||||
|
||||
```bash
|
||||
/plugin # inside Claude Code → toggle off
|
||||
RTK and GSD versions are pinned in `plugins.lock.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"rtk": { "version": "v0.34.3" },
|
||||
"gsd": { "version": "1.30.0" }
|
||||
}
|
||||
```
|
||||
|
||||
Or in `.claude/settings.json`:
|
||||
`install-plugins.sh` reads these versions automatically.
|
||||
To update a pinned version: edit `plugins.lock.json`, then re-run `install-plugins.sh`.
|
||||
GStack is pinned via its git submodule pointer.
|
||||
|
||||
### Disabling a plugin for a specific project
|
||||
|
||||
```bash
|
||||
# In Claude Code
|
||||
/plugin
|
||||
# → Find the plugin → toggle off for this scope
|
||||
```
|
||||
|
||||
Or in the project's `.claude/settings.json`:
|
||||
```json
|
||||
{
|
||||
"enabledPlugins": {
|
||||
"gstack@gstack": false
|
||||
"gstack@gstack": false,
|
||||
"gsd@gsd": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Enable a plugin for a project (share with teammates)
|
||||
### Enabling a plugin for a specific project (so teammates can install it)
|
||||
|
||||
```json
|
||||
{
|
||||
@ -481,7 +309,10 @@ Or in `.claude/settings.json`:
|
||||
},
|
||||
"extraKnownMarketplaces": {
|
||||
"ui-ux-pro-max-skill": {
|
||||
"source": { "source": "github", "repo": "nextlevelbuilder/ui-ux-pro-max-skill" }
|
||||
"source": {
|
||||
"source": "github",
|
||||
"repo": "nextlevelbuilder/ui-ux-pro-max-skill"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -506,81 +337,93 @@ DENY always wins over ALLOW at any level.
|
||||
.claudeignore applies independently of all permission rules.
|
||||
```
|
||||
|
||||
### Global `settings.json` (this repo)
|
||||
### Global settings (this repo's `settings.json`)
|
||||
|
||||
Contains global deny/ask/allow rules AND a SessionStart hook:
|
||||
|
||||
```json
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{ "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/session-start.sh" }] }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The hook prints toggle plugin status at every session start — zero API calls, filesystem only.
|
||||
77 deny rules, 16 ask rules, 57 allow rules.
|
||||
|
||||
| Section | Purpose |
|
||||
|---|---|
|
||||
| `deny` — secrets | Blocks `.env`, `.pem`, `.key`, SSH keys, cloud credentials |
|
||||
| `deny` — secrets (Read) | Blocks `Read` on `.env`, `.pem`, `.key`, SSH keys, cloud credentials |
|
||||
| `deny` — secrets (Bash) | Blocks `cat`, `head`, `tail`, `grep`, `less`, `more` on `.env` and secret files |
|
||||
| `deny` — destructive | Blocks `rm -rf`, `git push --force`, `chmod 777` |
|
||||
| `deny` — system | Blocks `sudo`, `ssh`, `scp`, `crontab`, `systemctl` |
|
||||
| `deny` — injection | Blocks `curl \| bash`, `wget \| sh` |
|
||||
| `deny` — escalation | Blocks `bash -c`, `eval`, `exec`, `find -delete`, `perl -e`, `ruby -e` |
|
||||
| `ask` — risky | Prompts before `git push`, `docker run`, package managers |
|
||||
| `allow` — safe reads | Auto-approves git read-only, `ls`, `cat`, `grep`, `find` |
|
||||
| `ask` — write tools | Prompts before `xargs`, `sed -i` (in-place file editing) |
|
||||
| `allow` — safe reads | Auto-approves git read-only, `ls`, `cat`, `grep`, `find`, `sed` (stdout only) |
|
||||
| `disableBypassPermissionsMode` | Prevents YOLO mode globally |
|
||||
|
||||
### Per-project setup
|
||||
|
||||
```bash
|
||||
cd your-project && mkdir -p .claude
|
||||
cd your-project
|
||||
mkdir -p .claude
|
||||
|
||||
# Project settings (commit)
|
||||
cp ~/claude-config/templates/settings/settings.json .claude/settings.json
|
||||
# Find the repo from any existing symlink
|
||||
CONF="$(dirname "$(readlink ~/.claude/CLAUDE.md)")"
|
||||
|
||||
# Personal overrides (never commit)
|
||||
cp ~/claude-config/templates/settings/settings.local.json .claude/settings.local.json
|
||||
# Project settings (commit to project git)
|
||||
cp "$CONF/templates/settings/settings.json" .claude/settings.json
|
||||
|
||||
# Personal overrides (never commit — gitignore it)
|
||||
cp "$CONF/templates/settings/settings.local.json" .claude/settings.local.json
|
||||
echo ".claude/settings.local.json" >> .gitignore
|
||||
|
||||
# Hard file exclusions (commit)
|
||||
cp ~/claude-config/templates/settings/.claudeignore .claudeignore
|
||||
# Hard file exclusions (commit to project git)
|
||||
cp "$CONF/templates/settings/.claudeignore" .claudeignore
|
||||
|
||||
# Project CLAUDE.md (commit)
|
||||
cp ~/claude-config/templates/project-CLAUDE.md .claude/CLAUDE.md
|
||||
# Project CLAUDE.md (commit to project git)
|
||||
cp "$CONF/templates/project-CLAUDE.md" .claude/CLAUDE.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating
|
||||
|
||||
### This repo
|
||||
### One-command update (recommended)
|
||||
|
||||
```bash
|
||||
cd ~/claude-config && git pull
|
||||
# Symlinks → changes active immediately, no restart needed
|
||||
# From the repo directory
|
||||
bash update-all.sh
|
||||
# Pulls config, updates GStack submodule, updates RTK (pinned version), refreshes symlinks, runs doctor
|
||||
```
|
||||
|
||||
### GStack (submodule)
|
||||
### Manual updates
|
||||
|
||||
#### This repo
|
||||
```bash
|
||||
# Option A — from Claude Code
|
||||
# cd into the repo (wherever you cloned it)
|
||||
git pull
|
||||
# Symlinks → changes active immediately
|
||||
```
|
||||
|
||||
#### GStack (submodule)
|
||||
```bash
|
||||
# Option A — inside Claude Code (recommended)
|
||||
/gstack-upgrade
|
||||
|
||||
# Option B — via submodule (pins version in your repo)
|
||||
cd ~/claude-config
|
||||
# Option B — via submodule (from the repo directory)
|
||||
git submodule update --remote skills-external/gstack
|
||||
cd skills-external/gstack && ./setup
|
||||
git add skills-external/gstack
|
||||
git commit -m "chore: update gstack"
|
||||
git commit -m "chore: update gstack to latest"
|
||||
```
|
||||
|
||||
### Marketplace plugins
|
||||
GStack is a git submodule. Its version is pinned in your config repo — reproducible on every machine.
|
||||
|
||||
#### RTK
|
||||
```bash
|
||||
/plugin marketplace update
|
||||
# Uses the version pinned in plugins.lock.json (from the repo directory)
|
||||
bash update-all.sh
|
||||
|
||||
# Or manually (check latest at https://github.com/rtk-ai/rtk/releases)
|
||||
cargo install --git https://github.com/rtk-ai/rtk --tag v0.34.3 --force
|
||||
```
|
||||
|
||||
### RTK
|
||||
#### Marketplace plugins
|
||||
```bash
|
||||
cargo install --git https://github.com/rtk-ai/rtk --force
|
||||
rtk init -g --auto-patch # re-apply hook if needed
|
||||
/plugin marketplace update # inside Claude Code
|
||||
```
|
||||
|
||||
---
|
||||
@ -596,6 +439,7 @@ name: myskill
|
||||
description: What this skill does — front-load the key use case (max 250 chars)
|
||||
argument-hint: <what to pass>
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
||||
---
|
||||
|
||||
Load and follow strictly:
|
||||
@ -612,8 +456,101 @@ $ARGUMENTS
|
||||
|
||||
## Per-project agent overrides
|
||||
|
||||
Override any global agent for a specific project:
|
||||
|
||||
```bash
|
||||
# Override an agent for a specific project
|
||||
cp ~/claude-config/agents/refactorer.md .claude/agents/refactorer.md
|
||||
# Edit — the local version takes precedence over global
|
||||
CONF="$(dirname "$(readlink ~/.claude/CLAUDE.md)")"
|
||||
cp "$CONF/agents/refactorer.md" .claude/agents/refactorer.md
|
||||
# Edit .claude/agents/refactorer.md — the local version takes precedence
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Diagnostic
|
||||
|
||||
```bash
|
||||
# Quick check from terminal (from the repo directory)
|
||||
bash doctor.sh
|
||||
|
||||
# Or from within Claude Code
|
||||
/health
|
||||
|
||||
# Unified commands via Makefile (from the repo directory)
|
||||
make doctor # diagnostic
|
||||
make update # pull + submodules + symlinks + doctor
|
||||
make install # link.sh + install-plugins.sh
|
||||
```
|
||||
|
||||
`doctor.sh` checks 7 axes: symlinks, GStack submodule, prerequisites (git, Node, Cargo, Python, Claude Code),
|
||||
plugins (RTK, Superpowers, Context7), permissions, token budget estimate, and config consistency
|
||||
(frontmatter coherence, CRLF detection).
|
||||
|
||||
`session-start.sh` runs a quick health check at every session start (filesystem only, no subprocesses)
|
||||
and displays toggle plugin status with `/plugin-check` and `/health` hints.
|
||||
|
||||
Both scripts source `lib/detect-plugins.sh` for consistent plugin detection logic.
|
||||
|
||||
### Updating
|
||||
|
||||
```bash
|
||||
# One-command update (from the repo directory)
|
||||
bash update-all.sh
|
||||
|
||||
# Or step by step
|
||||
git pull # this repo
|
||||
git submodule update --remote skills-external/gstack # GStack
|
||||
bash link.sh # refresh symlinks
|
||||
bash doctor.sh # verify
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "command not found" after install
|
||||
Restart your shell or run `source ~/.bashrc` / `source ~/.zshrc`.
|
||||
|
||||
### Orchestrator blocks at STEP 0 — Superpowers missing
|
||||
The plugin-advisor blocks `/init-project` and `/ship-feature` if Superpowers is not active.
|
||||
Install: `claude plugin marketplace add obra/superpowers-marketplace && claude plugin install --scope user superpowers@superpowers-marketplace`
|
||||
Then re-run the orchestrator.
|
||||
|
||||
### "agent not found" or hallucinated agent content
|
||||
Symlinks are broken. `cd` into your config repo and run `bash link.sh`, then verify with `bash doctor.sh`.
|
||||
|
||||
### GStack skills not showing up
|
||||
Run `bash link.sh` and verify: `ls -la ~/.claude/skills/gstack`.
|
||||
If missing: `cd` into your config repo and run `git submodule update --init`.
|
||||
|
||||
### link.sh warns "is a real directory"
|
||||
If `~/.claude/agents/`, `~/.claude/skills/`, or `~/.claude/lib/` exist as real directories (not symlinks
|
||||
from a previous `link.sh` run), the script skips them to avoid data loss. Rename or remove the directory, then re-run `link.sh`.
|
||||
|
||||
### Token budget exceeded / skills truncated at session start
|
||||
Too many plugins active. Run `/plugin-check` to optimize.
|
||||
Run `bash doctor.sh` for a token budget estimate.
|
||||
|
||||
### settings.json not applying
|
||||
Check precedence: deny always wins over allow at any level. `.claudeignore` overrides all permission rules.
|
||||
Verify deny count: `cat ~/.claude/settings.json | python3 -c "import json,sys; print(len(json.load(sys.stdin)['permissions']['deny']))"`
|
||||
Expected: 77 deny rules.
|
||||
|
||||
### Claude reads .env despite deny rules
|
||||
The `Read(**/.env)` deny rule blocks the Read tool. `Bash(cat .env)` and similar commands have separate
|
||||
deny rules (included in this config). For hard exclusion regardless of tool, use `.claudeignore` in the project root.
|
||||
|
||||
### install-plugins.sh failed — where are the logs?
|
||||
Check `install-YYYYMMDD-HHMMSS.log` in your config repo directory — the script logs all output to a timestamped file.
|
||||
|
||||
---
|
||||
|
||||
## Known limitations
|
||||
|
||||
- **Deny rules are pattern-based, not sandboxed.** Common bypass vectors (`bash -c`, `eval`, `xargs`, `cat .env`) are blocked, but novel indirect patterns are still possible. `.claudeignore` is the only hard file exclusion mechanism.
|
||||
- **Superpowers is a hard dependency** for `/init-project` and `/ship-feature`. The plugin-advisor (STEP 0) auto-detects and blocks if Superpowers is missing, with install instructions. There is no manual fallback mode.
|
||||
- **Marketplace plugin versions are not pinned.** They install latest. Non-marketplace tools (RTK, GSD) are pinned in `plugins.lock.json` and read by `install-plugins.sh`.
|
||||
- **Token budget is finite and not directly observable.** With all toggle plugins active, the description budget can exceed 60%. Run `/health` or `bash doctor.sh` for an estimate.
|
||||
- **Agent frontmatter fields** like `model` and `memory` are declared but their enforcement by Claude Code is not guaranteed. They serve as documentation more than strict runtime controls.
|
||||
- **`Bash(cat *)` in allow vs `Bash(cat .env)` in deny** depends on Claude Code resolving deny-wins. This is the expected behavior but cannot be tested outside the runtime.
|
||||
|
||||
@ -1,473 +0,0 @@
|
||||
---
|
||||
name: git-workflow
|
||||
description: Analyze all changes since branch start (retroactive, session-agnostic), create logical commits, push, and open a PR/MR on GitHub, GitLab, Gogs, or Gitea. Never merges — creates a draft PR for user validation.
|
||||
tools: Read, Bash, Grep, Glob
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
# GIT WORKFLOW
|
||||
|
||||
## ROLE
|
||||
Turn all work done on a branch into a clean, reviewed set of commits
|
||||
and an open PR/MR — regardless of how many sessions it took.
|
||||
|
||||
## GOAL
|
||||
- Stage and commit all uncommitted changes in logical groups
|
||||
- Push the branch to the remote
|
||||
- Create a PR/MR on the right platform
|
||||
- Never merge — the user validates the PR
|
||||
|
||||
---
|
||||
|
||||
## BRANCH SETUP (called by init-project and ship-feature)
|
||||
|
||||
This procedure runs before any code is written.
|
||||
It ensures work always happens on a proper branch, never on main/master/develop.
|
||||
|
||||
### 1. Check current branch
|
||||
|
||||
```bash
|
||||
CURRENT=$(git branch --show-current)
|
||||
echo "Current branch: $CURRENT"
|
||||
```
|
||||
|
||||
### 2. Determine protected branches
|
||||
|
||||
Protected branches (never commit directly):
|
||||
- `main`, `master`, `develop`, `dev`, `staging`, `production`, `prod`
|
||||
|
||||
```bash
|
||||
PROTECTED="main master develop dev staging production prod"
|
||||
```
|
||||
|
||||
### 3. If on a protected branch → create a feature branch
|
||||
|
||||
```bash
|
||||
# Derive branch name from context:
|
||||
# - init-project: feature/<project-slug-from-brief>
|
||||
# - ship-feature: feature/<feature-slug-from-argument>
|
||||
# Slugify: lowercase, replace spaces with hyphens, max 50 chars
|
||||
|
||||
BRANCH_NAME="feature/<slug>"
|
||||
|
||||
# Ensure main is up to date before branching
|
||||
git fetch origin
|
||||
git pull origin $CURRENT --ff-only 2>/dev/null || true
|
||||
|
||||
# Create and checkout the feature branch
|
||||
git checkout -b $BRANCH_NAME
|
||||
|
||||
echo "✅ Created branch: $BRANCH_NAME (from $CURRENT)"
|
||||
```
|
||||
|
||||
### 4. If already on a feature/bugfix/hotfix branch → sync with base
|
||||
|
||||
```bash
|
||||
BASE=$(git merge-base HEAD origin/main 2>/dev/null || git merge-base HEAD origin/master 2>/dev/null)
|
||||
|
||||
# Check if the base branch has new commits the feature branch doesn't have
|
||||
git fetch origin
|
||||
BEHIND=$(git rev-list HEAD..origin/<base-branch> --count 2>/dev/null || echo "0")
|
||||
```
|
||||
|
||||
If `BEHIND > 0`:
|
||||
```
|
||||
⚠️ Your branch is behind <base-branch> by $BEHIND commit(s).
|
||||
Rebasing to sync...
|
||||
```
|
||||
Run the CONFLICT-SAFE REBASE procedure below.
|
||||
|
||||
If `BEHIND = 0`: print `✅ Branch is up to date` and continue.
|
||||
|
||||
### 5. Branch naming conventions
|
||||
|
||||
| Context | Branch format | Example |
|
||||
|---|---|---|
|
||||
| New project (init-project) | `feature/<project-name>` | `feature/zenquality-website` |
|
||||
| New feature (ship-feature) | `feature/<feature-name>` | `feature/user-authentication` |
|
||||
| Bug on a feature branch | `bugfix/<description>` from feature | `bugfix/fix-login-redirect` |
|
||||
| Urgent production fix | `hotfix/<description>` from main | `hotfix/patch-csrf-vulnerability` |
|
||||
| Release prep | `release/<version>` from main | `release/v1.2.0` |
|
||||
|
||||
---
|
||||
|
||||
## CONFLICT-SAFE REBASE
|
||||
|
||||
Use this whenever rebasing a branch against its base.
|
||||
|
||||
```bash
|
||||
git rebase origin/<base-branch>
|
||||
```
|
||||
|
||||
**If rebase exits cleanly:** done.
|
||||
|
||||
**If conflicts are detected:**
|
||||
|
||||
```bash
|
||||
# List conflicted files
|
||||
git diff --name-only --diff-filter=U
|
||||
```
|
||||
|
||||
For each conflicted file:
|
||||
1. Read the file — identify the conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`)
|
||||
2. Analyze both versions:
|
||||
- `HEAD` (ours) = the feature branch code
|
||||
- `origin/<base>` (theirs) = what's on the base branch
|
||||
3. Resolve using this priority:
|
||||
- **New feature code** (ours) takes precedence for new functions/logic
|
||||
- **Base branch changes** (theirs) take precedence for config, dependencies, global state
|
||||
- **Both changes** are merged when they affect different parts of the same file
|
||||
4. Write the resolved file (no conflict markers left)
|
||||
5. Stage it: `git add <file>`
|
||||
6. Continue: `git rebase --continue`
|
||||
|
||||
**If a conflict cannot be auto-resolved** (same lines modified with incompatible logic):
|
||||
```
|
||||
⚠️ CONFLICT — manual resolution required
|
||||
File: <filename>
|
||||
Ours: <what the feature branch has>
|
||||
Theirs: <what base branch has>
|
||||
|
||||
How should this be resolved?
|
||||
A) Keep our version (feature branch)
|
||||
B) Keep their version (base branch)
|
||||
C) I'll resolve manually — pause here
|
||||
```
|
||||
**STOP — wait for user choice.**
|
||||
|
||||
After user responds:
|
||||
- A or B → apply, `git add <file>`, `git rebase --continue`
|
||||
- C → `git rebase --abort` and hand back control to user
|
||||
|
||||
**After all conflicts resolved:**
|
||||
```bash
|
||||
git log --oneline <base-branch>..HEAD
|
||||
echo "✅ Rebase complete — branch is clean"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 0 — DETECT GIT PROVIDER
|
||||
|
||||
Run:
|
||||
```bash
|
||||
git remote get-url origin 2>/dev/null || git remote get-url upstream 2>/dev/null
|
||||
```
|
||||
|
||||
Parse the URL to determine the provider:
|
||||
|
||||
| URL pattern | Provider | CLI available? |
|
||||
|---|---|---|
|
||||
| `github.com` | GitHub | check `gh auth status` |
|
||||
| `gitlab.com` or `gitlab.*` | GitLab | check `glab auth status` |
|
||||
| anything else | Gogs / Gitea | API only (no official CLI) |
|
||||
|
||||
Extract:
|
||||
- `REMOTE_URL` — full remote URL
|
||||
- `PROVIDER` — github / gitlab / gogs-gitea
|
||||
- `BASE_URL` — for Gogs/Gitea: `https://hostname` (strip path)
|
||||
- `OWNER` — repo owner/organization
|
||||
- `REPO` — repo name
|
||||
- `CLI_AVAILABLE` — gh / glab / none
|
||||
|
||||
For Gogs/Gitea, check for an API token in env:
|
||||
```bash
|
||||
echo "${GOGS_TOKEN:-${GITEA_TOKEN:-not-set}}"
|
||||
```
|
||||
If not set, print:
|
||||
```
|
||||
⚠️ Gogs/Gitea detected. Set one of these env vars:
|
||||
export GOGS_TOKEN="your-token"
|
||||
export GITEA_TOKEN="your-token"
|
||||
Then re-run /git-pr
|
||||
```
|
||||
And STOP.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1 — ANALYZE BRANCH STATE
|
||||
|
||||
### 1a. Identify current branch and base
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Determine the base branch from the branch name:
|
||||
| Branch prefix | Default base | PR type |
|
||||
|---|---|---|
|
||||
| `feature/*` | `develop` (or `main` if no develop) | Feature |
|
||||
| `feat/*` | `develop` (or `main`) | Feature |
|
||||
| `bugfix/*` | `develop` | Bug fix |
|
||||
| `fix/*` | `develop` | Bug fix |
|
||||
| `hotfix/*` | `main` | Hotfix |
|
||||
| `release/*` | `main` | Release |
|
||||
| `chore/*` | `develop` (or `main`) | Chore |
|
||||
| anything else | `main` | General |
|
||||
|
||||
Verify the base branch exists:
|
||||
```bash
|
||||
git rev-parse --verify <base-branch> 2>/dev/null
|
||||
```
|
||||
|
||||
### 1b. Retroactive diff — ALL changes since branch start
|
||||
|
||||
```bash
|
||||
# All committed changes on this branch (retroactive, session-agnostic)
|
||||
git log --oneline <base-branch>..HEAD
|
||||
|
||||
# All uncommitted changes
|
||||
git status --short
|
||||
|
||||
# Full diff of everything: committed + uncommitted vs base
|
||||
git diff <base-branch>...HEAD --name-status
|
||||
|
||||
# Stats
|
||||
git diff <base-branch>...HEAD --stat
|
||||
```
|
||||
|
||||
The `git diff <base>...HEAD` (three dots) shows everything since
|
||||
the branch diverged from base — not just since last commit.
|
||||
This is the source of truth regardless of session count.
|
||||
|
||||
### 1c. Build the CHANGE MAP
|
||||
|
||||
Categorize every changed file:
|
||||
- `config` — package.json, Cargo.toml, go.mod, requirements.txt, docker-compose.yml, Makefile, CI files
|
||||
- `model` — data models, schemas, migrations, types
|
||||
- `core` — business logic, services, domain
|
||||
- `api` / `routes` — endpoints, controllers, handlers
|
||||
- `ui` — components, pages, styles, assets
|
||||
- `test` — all test files
|
||||
- `docs` — README, CLAUDE.md, markdown docs
|
||||
- `infra` — Dockerfile, deploy scripts, k8s, terraform
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2 — PROPOSE COMMITS
|
||||
|
||||
Group the changes from the CHANGE MAP into logical commits.
|
||||
Order: config → model → core → api/routes → ui → test → docs → infra
|
||||
|
||||
For each group, propose a commit using Conventional Commits:
|
||||
```
|
||||
<type>(<scope>): <description>
|
||||
|
||||
Types: feat, fix, chore, refactor, test, docs, style, ci, build, perf
|
||||
Scope: optional, matches the module/directory
|
||||
```
|
||||
|
||||
Present the proposed commit plan:
|
||||
```
|
||||
================================================================
|
||||
GIT WORKFLOW — COMMIT PLAN
|
||||
================================================================
|
||||
|
||||
BRANCH : <current-branch>
|
||||
BASE : <base-branch>
|
||||
PROVIDER : <github/gitlab/gogs-gitea>
|
||||
|
||||
CHANGES SINCE BRANCH START
|
||||
---------------------------
|
||||
<git diff --stat output>
|
||||
|
||||
PROPOSED COMMITS
|
||||
----------------
|
||||
1. chore(deps): update dependencies — [package.json, go.mod]
|
||||
2. feat(auth): add user model and migration — [models/user.go, migrations/001_users.sql]
|
||||
3. feat(auth): implement login and JWT handlers — [handlers/auth.go, services/auth.go]
|
||||
4. test(auth): add unit tests for auth service — [tests/auth_test.go]
|
||||
5. docs: update README with auth setup — [README.md]
|
||||
|
||||
UNCOMMITTED CHANGES (will be staged in their respective commit)
|
||||
---------------------------------------------------------------
|
||||
<git status --short>
|
||||
|
||||
================================================================
|
||||
Approve this commit plan? (yes / modify / cancel)
|
||||
================================================================
|
||||
```
|
||||
|
||||
**MANDATORY STOP — wait for user approval.**
|
||||
|
||||
IF modify → user describes changes → adjust plan → re-present
|
||||
IF cancel → stop, no changes made
|
||||
IF yes → proceed to PHASE 3
|
||||
|
||||
---
|
||||
|
||||
## PHASE 3 — EXECUTE COMMITS
|
||||
|
||||
For each proposed commit, in order:
|
||||
|
||||
```bash
|
||||
# Stage the specific files for this commit
|
||||
git add <files-for-this-commit>
|
||||
|
||||
# Commit with the proposed message
|
||||
git commit -m "<type>(<scope>): <description>"
|
||||
```
|
||||
|
||||
If a file has both committed and uncommitted changes:
|
||||
- Stage only the uncommitted portion
|
||||
- Include it in the appropriate commit group
|
||||
|
||||
After all commits:
|
||||
```bash
|
||||
git log --oneline <base-branch>..HEAD
|
||||
```
|
||||
Show the final commit list for confirmation.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 4 — PUSH
|
||||
|
||||
```bash
|
||||
# Push, setting upstream if branch is new
|
||||
git push --set-upstream origin <current-branch>
|
||||
```
|
||||
|
||||
**If push is rejected** (remote has diverged):
|
||||
1. Run the CONFLICT-SAFE REBASE procedure:
|
||||
```bash
|
||||
git fetch origin
|
||||
git rebase origin/<current-branch>
|
||||
```
|
||||
2. Resolve any conflicts as described in CONFLICT-SAFE REBASE
|
||||
3. Push again: `git push origin <current-branch>`
|
||||
|
||||
**If the push is still rejected after rebase:**
|
||||
```bash
|
||||
git log --oneline origin/<current-branch>..HEAD
|
||||
```
|
||||
Show the commits that haven't been pushed and ask the user:
|
||||
```
|
||||
⚠️ Push still rejected after rebase.
|
||||
Local commits not on remote: <N>
|
||||
Options:
|
||||
A) Force push (overwrites remote — use only if remote is yours)
|
||||
B) Investigate manually
|
||||
```
|
||||
**STOP — wait for user choice. Never force push without explicit approval.**
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5 — CREATE PR / MR
|
||||
|
||||
Build the PR body from:
|
||||
- `git log <base-branch>..HEAD --format="- %s"` — commit list
|
||||
- Modified file categories (from CHANGE MAP)
|
||||
- CLAUDE.md project context
|
||||
|
||||
PR body template:
|
||||
```markdown
|
||||
## Summary
|
||||
|
||||
<2-3 sentence description derived from branch name and commit messages>
|
||||
|
||||
## Changes
|
||||
|
||||
<commit list from git log>
|
||||
|
||||
## Modified areas
|
||||
|
||||
<list of changed modules/directories>
|
||||
|
||||
## Testing
|
||||
|
||||
<describe test coverage based on test files changed>
|
||||
|
||||
---
|
||||
*Created by /git-pr — validate then merge*
|
||||
```
|
||||
|
||||
### GitHub
|
||||
|
||||
```bash
|
||||
# With gh CLI (preferred)
|
||||
gh pr create \
|
||||
--base <base-branch> \
|
||||
--head <current-branch> \
|
||||
--title "<type>: <feature-name-from-branch>" \
|
||||
--body "<pr-body>" \
|
||||
--draft
|
||||
|
||||
# Without gh CLI — print URL for manual creation
|
||||
echo "Create PR at: https://github.com/<owner>/<repo>/compare/<base>...<branch>"
|
||||
```
|
||||
|
||||
### GitLab
|
||||
|
||||
```bash
|
||||
# With glab CLI (preferred)
|
||||
glab mr create \
|
||||
--source-branch <current-branch> \
|
||||
--target-branch <base-branch> \
|
||||
--title "<type>: <feature-name>" \
|
||||
--description "<pr-body>" \
|
||||
--draft
|
||||
|
||||
# Without glab CLI
|
||||
echo "Create MR at: https://gitlab.com/<owner>/<repo>/-/merge_requests/new?merge_request[source_branch]=<branch>"
|
||||
```
|
||||
|
||||
### Gogs / Gitea
|
||||
|
||||
Use the API directly (both use GitHub API v3-compatible format):
|
||||
|
||||
```bash
|
||||
curl -s -X POST \
|
||||
"${BASE_URL}/api/v1/repos/${OWNER}/${REPO}/pulls" \
|
||||
-H "Authorization: token ${GOGS_TOKEN:-$GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"title\": \"<type>: <feature-name>\",
|
||||
\"body\": \"<pr-body-escaped>\",
|
||||
\"head\": \"<current-branch>\",
|
||||
\"base\": \"<base-branch>\"
|
||||
}"
|
||||
```
|
||||
|
||||
If the API call returns an error, print the full response and suggest
|
||||
creating the PR manually via the web UI.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 6 — FINAL REPORT
|
||||
|
||||
```
|
||||
================================================================
|
||||
PR CREATED
|
||||
================================================================
|
||||
|
||||
BRANCH : <current-branch> → <base-branch>
|
||||
COMMITS : <N> commits pushed
|
||||
PLATFORM : <GitHub/GitLab/Gogs/Gitea>
|
||||
|
||||
COMMITS
|
||||
-------
|
||||
<git log --oneline output>
|
||||
|
||||
PR / MR
|
||||
-------
|
||||
URL : <pr-url or "create manually at <url>">
|
||||
Type : Draft — awaiting your review and merge
|
||||
|
||||
NEXT STEPS
|
||||
----------
|
||||
1. Review the PR at the URL above
|
||||
2. Request reviews if needed
|
||||
3. Merge when approved
|
||||
================================================================
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## RULES
|
||||
|
||||
- Never merge, never rebase main/master/develop
|
||||
- Never force push unless explicitly asked
|
||||
- Never create commits on main, master, or develop directly
|
||||
- If on main/master — STOP and ask user to checkout a feature branch first
|
||||
- Draft PR by default — user controls merge
|
||||
- If no CLI tool and no API token — print manual instructions, do not fail silently
|
||||
@ -123,6 +123,7 @@ ACTION REQUIRED? [YES — resolve blocking issues first] / [NO — proceed]
|
||||
## THRESHOLDS
|
||||
|
||||
**Block and require action if:**
|
||||
- Superpowers is not active (required by /init-project and /ship-feature orchestrators — install command: `claude plugin marketplace add obra/superpowers-marketplace && claude plugin install --scope user superpowers@superpowers-marketplace`)
|
||||
- Project has significant frontend AND frontend-design + ui-ux-pro-max are both disabled
|
||||
- Project uses Next.js/React/Prisma/Supabase AND context7 is not configured
|
||||
- Project is full-product (UI + deploy + QA) AND gstack is not installed
|
||||
|
||||
261
doctor.sh
Normal file
261
doctor.sh
Normal file
@ -0,0 +1,261 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# Claude Code — Config doctor
|
||||
# Diagnoses symlinks, prerequisites, plugins, permissions,
|
||||
# and token budget. Run after install or when something breaks.
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||||
ERRORS=0; WARNS=0
|
||||
|
||||
pass() { echo -e " ${GREEN}✓${NC} $1"; }
|
||||
fail() { echo -e " ${RED}✗${NC} $1"; ERRORS=$((ERRORS + 1)); }
|
||||
warn() { echo -e " ${YELLOW}⚠${NC} $1"; WARNS=$((WARNS + 1)); }
|
||||
info() { echo -e " ${BLUE}→${NC} $1"; }
|
||||
|
||||
REPO="$(cd "$(dirname "$0")" && pwd)"
|
||||
VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
|
||||
|
||||
# Load shared detection library
|
||||
# shellcheck source=lib/detect-plugins.sh
|
||||
source "$REPO/lib/detect-plugins.sh"
|
||||
|
||||
echo ""
|
||||
echo "═══ claude-config doctor (v${VERSION}) ═══"
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 1. Core symlinks
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Symlinks ──"
|
||||
|
||||
check_symlink() {
|
||||
local name="$1"
|
||||
local target="$HOME/.claude/$name"
|
||||
|
||||
if [ ! -e "$target" ] && [ ! -L "$target" ]; then
|
||||
fail "~/.claude/$name — MISSING"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -L "$target" ]; then
|
||||
local real
|
||||
real=$(readlink -f "$target" 2>/dev/null || readlink "$target")
|
||||
if [ ! -e "$real" ]; then
|
||||
fail "~/.claude/$name → $real — BROKEN SYMLINK"
|
||||
else
|
||||
pass "~/.claude/$name"
|
||||
fi
|
||||
else
|
||||
warn "~/.claude/$name exists but is NOT a symlink (expected symlink to repo)"
|
||||
fi
|
||||
}
|
||||
|
||||
check_symlink "CLAUDE.md"
|
||||
check_symlink "settings.json"
|
||||
check_symlink "agents"
|
||||
check_symlink "skills"
|
||||
check_symlink "hooks/session-start.sh"
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 2. GStack submodule
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── GStack submodule ──"
|
||||
|
||||
if [ -d "$REPO/skills-external/gstack" ] || [ -f "$REPO/skills-external/gstack/.git" ]; then
|
||||
pass "Submodule present at skills-external/gstack"
|
||||
else
|
||||
warn "Submodule not initialized — run: git submodule update --init"
|
||||
fi
|
||||
|
||||
if [ -L "$HOME/.claude/skills/gstack" ]; then
|
||||
real=$(readlink -f "$HOME/.claude/skills/gstack" 2>/dev/null || readlink "$HOME/.claude/skills/gstack")
|
||||
if [ -d "$real" ]; then
|
||||
pass "Symlink OK → $real"
|
||||
else
|
||||
fail "Symlink broken → $real"
|
||||
fi
|
||||
else
|
||||
warn "GStack not symlinked — run: bash link.sh"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 3. Prerequisites
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Prerequisites ──"
|
||||
|
||||
if command -v git &>/dev/null; then
|
||||
pass "git $(git --version | awk '{print $3}')"
|
||||
else
|
||||
fail "git not found"
|
||||
fi
|
||||
|
||||
if command -v node &>/dev/null; then
|
||||
NODE_VER=$(node --version | sed 's/v//' | cut -d. -f1)
|
||||
if [ "$NODE_VER" -ge 18 ]; then
|
||||
pass "Node.js $(node --version)"
|
||||
else
|
||||
warn "Node.js $(node --version) — need >=18"
|
||||
fi
|
||||
else
|
||||
fail "Node.js not found"
|
||||
fi
|
||||
|
||||
if command -v cargo &>/dev/null; then
|
||||
pass "Cargo $(cargo --version | awk '{print $2}')"
|
||||
else
|
||||
warn "Cargo not found (RTK unavailable)"
|
||||
fi
|
||||
|
||||
if command -v python3 &>/dev/null; then
|
||||
pass "Python $(python3 --version | awk '{print $2}')"
|
||||
else
|
||||
warn "Python3 not found"
|
||||
fi
|
||||
|
||||
if command -v claude &>/dev/null; then
|
||||
pass "Claude Code $(claude --version 2>/dev/null | head -1 || echo 'installed')"
|
||||
else
|
||||
fail "Claude Code not found — install from https://code.claude.com"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 4. Key plugins
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Plugins ──"
|
||||
|
||||
if detect_rtk; then
|
||||
pass "RTK installed"
|
||||
else
|
||||
warn "RTK not installed — run install-plugins.sh"
|
||||
fi
|
||||
|
||||
if detect_superpowers; then
|
||||
pass "Superpowers plugin detected"
|
||||
else
|
||||
fail "Superpowers not detected — orchestrators (/init-project, /ship-feature) will fail"
|
||||
fi
|
||||
|
||||
if detect_context7; then
|
||||
pass "Context7 MCP configured"
|
||||
else
|
||||
info "Context7 MCP not configured (optional — needed for fast-evolving libs)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 5. Permissions check
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Permissions ──"
|
||||
|
||||
SETTINGS="$HOME/.claude/settings.json"
|
||||
if [ -f "$SETTINGS" ] || [ -L "$SETTINGS" ]; then
|
||||
if grep -q '"disableBypassPermissionsMode"' "$SETTINGS" 2>/dev/null; then
|
||||
pass "Bypass mode disabled"
|
||||
else
|
||||
warn "disableBypassPermissionsMode not found in settings"
|
||||
fi
|
||||
|
||||
DENY_COUNT=$(python3 -c "
|
||||
import json
|
||||
with open('$SETTINGS') as f:
|
||||
d = json.load(f)
|
||||
print(len(d.get('permissions',{}).get('deny',[])))
|
||||
" 2>/dev/null || echo "?")
|
||||
pass "Deny rules: $DENY_COUNT"
|
||||
else
|
||||
fail "~/.claude/settings.json not found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 6. Token budget estimate
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Token budget estimate ──"
|
||||
|
||||
TOTAL_CHARS=0
|
||||
|
||||
# Skill descriptions
|
||||
for f in "$HOME/.claude/skills/"*/SKILL.md; do
|
||||
[ -f "$f" ] || continue
|
||||
desc=$(sed -n 's/^description: //p' "$f" 2>/dev/null || true)
|
||||
TOTAL_CHARS=$((TOTAL_CHARS + ${#desc}))
|
||||
done
|
||||
|
||||
# Agent descriptions
|
||||
for f in "$HOME/.claude/agents/"*.md; do
|
||||
[ -f "$f" ] || continue
|
||||
desc=$(sed -n '/^---$/,/^---$/{ s/^description: //p }' "$f" 2>/dev/null || true)
|
||||
TOTAL_CHARS=$((TOTAL_CHARS + ${#desc}))
|
||||
done
|
||||
|
||||
if [ "$TOTAL_CHARS" -gt 6000 ]; then
|
||||
warn "Custom descriptions: ~${TOTAL_CHARS} chars (budget ~8000) — risk of truncation"
|
||||
elif [ "$TOTAL_CHARS" -gt 4000 ]; then
|
||||
info "Custom descriptions: ~${TOTAL_CHARS} chars (within budget, moderate margin)"
|
||||
else
|
||||
pass "Custom descriptions: ~${TOTAL_CHARS} chars (comfortable)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# 7. File consistency
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Consistency ──"
|
||||
|
||||
# Check all skills have disable-model-invocation
|
||||
MISSING_DMI=()
|
||||
for f in "$HOME/.claude/skills/"*/SKILL.md; do
|
||||
[ -f "$f" ] || continue
|
||||
name=$(basename "$(dirname "$f")")
|
||||
if ! grep -q "disable-model-invocation" "$f" 2>/dev/null; then
|
||||
MISSING_DMI+=("$name")
|
||||
fi
|
||||
done
|
||||
if [ ${#MISSING_DMI[@]} -eq 0 ]; then
|
||||
pass "All skills have disable-model-invocation"
|
||||
else
|
||||
warn "Skills missing disable-model-invocation: ${MISSING_DMI[*]}"
|
||||
fi
|
||||
|
||||
# Check CRLF
|
||||
CRLF_FILES=()
|
||||
for f in "$REPO"/*.md "$REPO"/agents/*.md "$REPO"/skills/*/SKILL.md; do
|
||||
[ -f "$f" ] || continue
|
||||
if grep -qP '\r' "$f" 2>/dev/null; then
|
||||
CRLF_FILES+=("$(basename "$f")")
|
||||
fi
|
||||
done
|
||||
if [ ${#CRLF_FILES[@]} -eq 0 ]; then
|
||||
pass "No CRLF line endings detected"
|
||||
else
|
||||
warn "CRLF detected in: ${CRLF_FILES[*]}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ────────────────────────────────────────────────────────────
|
||||
# Summary
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "═══════════════════════════════════════════"
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo -e "${RED} $ERRORS error(s)${NC}, ${YELLOW}$WARNS warning(s)${NC}"
|
||||
echo ""
|
||||
echo " Fix: cd $REPO && bash link.sh && bash install-plugins.sh"
|
||||
exit 1
|
||||
elif [ "$WARNS" -gt 0 ]; then
|
||||
echo -e " ${GREEN}No errors${NC}, ${YELLOW}$WARNS warning(s)${NC}"
|
||||
else
|
||||
echo -e " ${GREEN}All checks passed ✓${NC}"
|
||||
fi
|
||||
echo ""
|
||||
@ -4,52 +4,88 @@
|
||||
# Runs once per session. Zero API calls. Filesystem only.
|
||||
# ============================================================
|
||||
|
||||
# ── Quick health check (filesystem only, no subprocesses) ──
|
||||
BROKEN=()
|
||||
for f in CLAUDE.md settings.json agents skills; do
|
||||
[ ! -e "$HOME/.claude/$f" ] && BROKEN+=("$f")
|
||||
done
|
||||
|
||||
if [ ${#BROKEN[@]} -gt 0 ]; then
|
||||
# Try to find the repo path from an existing symlink
|
||||
_repo_hint=""
|
||||
for _probe in CLAUDE.md settings.json; do
|
||||
if [ -L "$HOME/.claude/$_probe" ]; then
|
||||
_repo_hint="$(cd "$(dirname "$(readlink "$HOME/.claude/$_probe")")" 2>/dev/null && pwd)"
|
||||
break
|
||||
fi
|
||||
done
|
||||
_fix_cmd="${_repo_hint:+cd $_repo_hint && }bash link.sh"
|
||||
|
||||
echo ""
|
||||
echo "┌─ ⚠️ CONFIG ISSUES ────────────────────────────────┐"
|
||||
for b in "${BROKEN[@]}"; do
|
||||
printf "│ MISSING: ~/.claude/%-30s│\n" "$b"
|
||||
done
|
||||
printf "│ → %-47s│\n" "$_fix_cmd"
|
||||
echo "│ → /health for full diagnostic │"
|
||||
echo "└───────────────────────────────────────────────────┘"
|
||||
unset _repo_hint _fix_cmd
|
||||
fi
|
||||
|
||||
# ── Load shared detection library ──
|
||||
_lib="$(dirname "${BASH_SOURCE[0]}")/../lib/detect-plugins.sh"
|
||||
if [ -f "$_lib" ]; then
|
||||
# shellcheck source=../lib/detect-plugins.sh
|
||||
source "$_lib"
|
||||
else
|
||||
# Fallback: inline detection if lib is missing
|
||||
detect_gstack() { [ -d "$HOME/.claude/skills/gstack" ]; }
|
||||
detect_gsd() { ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"; }
|
||||
detect_uiux_pro_max() { ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "ui-ux-pro-max"; }
|
||||
detect_frontend_design() { ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "frontend-design"; }
|
||||
detect_context7() { claude mcp list 2>/dev/null | grep -q "context7"; }
|
||||
fi
|
||||
unset _lib
|
||||
|
||||
# ── Toggle plugin detection ──
|
||||
|
||||
TOGGLE_ACTIVE=()
|
||||
TOGGLE_INACTIVE=()
|
||||
|
||||
# --- GStack ---
|
||||
if [ -d "$HOME/.claude/skills/gstack" ]; then
|
||||
TOGGLE_ACTIVE+=("gstack")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("gstack")
|
||||
fi
|
||||
for plugin in gstack gsd uiux_pro_max frontend_design context7; do
|
||||
# Map function name to display name
|
||||
case "$plugin" in
|
||||
uiux_pro_max) display="ui-ux-pro-max" ;;
|
||||
frontend_design) display="frontend-design" ;;
|
||||
*) display="$plugin" ;;
|
||||
esac
|
||||
|
||||
# --- GSD ---
|
||||
if ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"; then
|
||||
TOGGLE_ACTIVE+=("gsd")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("gsd")
|
||||
fi
|
||||
|
||||
# --- UI/UX Pro Max ---
|
||||
if ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "ui-ux-pro-max"; then
|
||||
TOGGLE_ACTIVE+=("ui-ux-pro-max")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("ui-ux-pro-max")
|
||||
fi
|
||||
|
||||
# --- frontend-design ---
|
||||
if ls "$HOME/.claude/plugins/cache/" 2>/dev/null | grep -qi "frontend-design"; then
|
||||
TOGGLE_ACTIVE+=("frontend-design")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("frontend-design")
|
||||
fi
|
||||
|
||||
# --- Context7 MCP ---
|
||||
if claude mcp list 2>/dev/null | grep -q "context7"; then
|
||||
TOGGLE_ACTIVE+=("context7")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("context7")
|
||||
fi
|
||||
if "detect_$plugin" 2>/dev/null; then
|
||||
TOGGLE_ACTIVE+=("$display")
|
||||
else
|
||||
TOGGLE_INACTIVE+=("$display")
|
||||
fi
|
||||
done
|
||||
|
||||
# --- Format output ---
|
||||
ACTIVE_STR="${TOGGLE_ACTIVE[*]:-none}"
|
||||
INACTIVE_STR="${TOGGLE_INACTIVE[*]:-none}"
|
||||
|
||||
# Version detection: follow CLAUDE.md symlink back to repo, then read version.txt
|
||||
_claude_real="$(readlink "$HOME/.claude/CLAUDE.md" 2>/dev/null || true)"
|
||||
if [ -n "$_claude_real" ]; then
|
||||
_repo_dir="$(cd "$(dirname "$_claude_real")" 2>/dev/null && pwd)"
|
||||
CONFIG_VERSION=$(cat "$_repo_dir/version.txt" 2>/dev/null || echo "?")
|
||||
else
|
||||
CONFIG_VERSION="?"
|
||||
fi
|
||||
unset _claude_real _repo_dir
|
||||
|
||||
echo ""
|
||||
echo "┌─ Toggle plugins ──────────────────────────────────┐"
|
||||
printf "│ 🟢 ON : %-40s│\n" "$ACTIVE_STR"
|
||||
printf "│ ⚫ OFF : %-40s│\n" "$INACTIVE_STR"
|
||||
echo "│ 💡 /plugin-check before starting a new project │"
|
||||
echo "│ 🩺 /health to run full diagnostic │"
|
||||
echo "└───────────────────────────────────────────────────┘"
|
||||
echo ""
|
||||
|
||||
@ -16,6 +16,31 @@ err() { echo -e "${RED}✗${NC} $1"; }
|
||||
|
||||
REPO="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Log to file for post-mortem debugging (terminal output unchanged)
|
||||
LOG_FILE="$REPO/install-$(date +%Y%m%d-%H%M%S).log"
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
|
||||
# Load shared detection library
|
||||
# shellcheck source=lib/detect-plugins.sh
|
||||
source "$REPO/lib/detect-plugins.sh"
|
||||
|
||||
# Read pinned version from plugins.lock.json
|
||||
# Usage: pinned_version "rtk" → prints version string or "latest"
|
||||
pinned_version() {
|
||||
local key="$1"
|
||||
if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
|
||||
python3 -c "
|
||||
import json, sys
|
||||
with open('$REPO/plugins.lock.json') as f:
|
||||
d = json.load(f)
|
||||
v = d.get('$key', {}).get('version', 'latest')
|
||||
print(v)
|
||||
" 2>/dev/null || echo "latest"
|
||||
else
|
||||
echo "latest"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# DETECT OS
|
||||
# ============================================================
|
||||
@ -128,52 +153,9 @@ fi
|
||||
echo ""
|
||||
|
||||
# ============================================================
|
||||
# STEP 2 — GIT CLI TOOLS (gh + glab for /git-pr)
|
||||
# STEP 2 — GSTACK SUBMODULE
|
||||
# ============================================================
|
||||
echo "── Step 2: Git CLI tools ────────────────────────────────────"
|
||||
echo ""
|
||||
|
||||
# --- gh (GitHub CLI) ---
|
||||
if command -v gh &>/dev/null; then
|
||||
ok "gh $(gh --version | head -1 | awk '{print $3}')"
|
||||
else
|
||||
info "Installing gh (GitHub CLI)..."
|
||||
case $OS in
|
||||
macos) brew install gh ;;
|
||||
linux-apt) type -p curl > /dev/null || sudo apt-get install -y curl
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
|
||||
sudo apt-get update && sudo apt-get install -y gh ;;
|
||||
linux-dnf) sudo dnf install -y gh ;;
|
||||
linux-pacman) sudo pacman -S --noconfirm github-cli ;;
|
||||
*) warn "Cannot auto-install gh on $OS — install from https://cli.github.com" ;;
|
||||
esac
|
||||
command -v gh &>/dev/null && ok "gh installed" || warn "gh not installed — GitHub PRs will use API fallback"
|
||||
fi
|
||||
|
||||
# --- glab (GitLab CLI) ---
|
||||
if command -v glab &>/dev/null; then
|
||||
ok "glab $(glab --version | head -1)"
|
||||
else
|
||||
info "Installing glab (GitLab CLI)..."
|
||||
case $OS in
|
||||
macos) brew install glab ;;
|
||||
linux-apt) curl -s https://raw.githubusercontent.com/profclems/glab/trunk/scripts/install.sh | sudo bash ;;
|
||||
linux-dnf) sudo dnf install -y glab ;;
|
||||
linux-pacman) sudo pacman -S --noconfirm glab ;;
|
||||
*) warn "Cannot auto-install glab on $OS — install from https://gitlab.com/gitlab-org/cli" ;;
|
||||
esac
|
||||
command -v glab &>/dev/null && ok "glab installed" || warn "glab not installed — GitLab MRs will use API fallback"
|
||||
fi
|
||||
|
||||
warn "Gogs/Gitea: set GOGS_TOKEN or GITEA_TOKEN in your shell profile"
|
||||
echo " export GOGS_TOKEN="your-token" # add to ~/.zshrc or ~/.bashrc"
|
||||
echo ""
|
||||
|
||||
# ============================================================
|
||||
# STEP 3 — GSTACK SUBMODULE
|
||||
# ============================================================
|
||||
echo "── Step 3: GStack submodule ─────────────────────────────────"
|
||||
echo "── Step 2: GStack submodule ─────────────────────────────────"
|
||||
echo ""
|
||||
# Note: GStack is managed as a git submodule in this repo.
|
||||
# It lives at skills-external/gstack/ and is symlinked to ~/.claude/skills/gstack/
|
||||
@ -198,10 +180,12 @@ fi
|
||||
if [ -d "$GSTACK_DIR" ]; then
|
||||
info "Running GStack setup..."
|
||||
cd "$GSTACK_DIR" && ./setup && cd - > /dev/null
|
||||
# Ensure symlink from link.sh is in place
|
||||
mkdir -p "$HOME/.claude/skills"
|
||||
ln -sf "$GSTACK_DIR" "$HOME/.claude/skills/gstack" 2>/dev/null || true
|
||||
ok "GStack ready at ~/.claude/skills/gstack (→ submodule)"
|
||||
# Symlinks are handled by link.sh — verify it was run
|
||||
if [ -L "$HOME/.claude/skills/gstack" ]; then
|
||||
ok "GStack ready (submodule initialized, symlink OK)"
|
||||
else
|
||||
warn "GStack submodule ready but not symlinked — run: bash link.sh"
|
||||
fi
|
||||
else
|
||||
warn "GStack submodule directory not found after init — check .gitmodules"
|
||||
fi
|
||||
@ -211,13 +195,19 @@ echo ""
|
||||
# ============================================================
|
||||
# STEP 3 — RTK
|
||||
# ============================================================
|
||||
echo "── Step 4: RTK — Rust Token Killer ─────────────────────────"
|
||||
echo "── Step 3: RTK — Rust Token Killer ─────────────────────────"
|
||||
echo ""
|
||||
if command -v rtk &>/dev/null; then
|
||||
ok "rtk already installed ($(rtk --version 2>/dev/null | head -1))"
|
||||
else
|
||||
info "Installing RTK..."
|
||||
cargo install --git https://github.com/rtk-ai/rtk
|
||||
RTK_VER=$(pinned_version "rtk")
|
||||
if [ "$RTK_VER" != "latest" ]; then
|
||||
info "Installing RTK $RTK_VER (pinned in plugins.lock.json)..."
|
||||
cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VER"
|
||||
else
|
||||
info "Installing RTK (latest — consider pinning in plugins.lock.json)..."
|
||||
cargo install --git https://github.com/rtk-ai/rtk
|
||||
fi
|
||||
fi
|
||||
info "Configuring RTK PreToolUse hook (global)..."
|
||||
rtk init -g --auto-patch
|
||||
@ -227,10 +217,17 @@ echo ""
|
||||
# ============================================================
|
||||
# STEP 4 — GSD
|
||||
# ============================================================
|
||||
echo "── Step 5: GSD — get-shit-done ─────────────────────────────"
|
||||
echo "── Step 4: GSD — get-shit-done ─────────────────────────────"
|
||||
echo ""
|
||||
info "Installing GSD globally..."
|
||||
npx get-shit-done-cc --claude --global --auto
|
||||
GSD_VER=$(pinned_version "gsd")
|
||||
if [ "$GSD_VER" != "latest" ]; then
|
||||
info "Version $GSD_VER (pinned in plugins.lock.json)"
|
||||
npx "get-shit-done-cc@$GSD_VER" --claude --global --auto
|
||||
else
|
||||
info "Version: latest (consider pinning in plugins.lock.json)"
|
||||
npx get-shit-done-cc --claude --global --auto
|
||||
fi
|
||||
ok "GSD installed"
|
||||
echo ""
|
||||
|
||||
@ -239,7 +236,7 @@ echo ""
|
||||
# ============================================================
|
||||
# All claude plugin install commands use --scope user to ensure
|
||||
# they install to ~/.claude/plugins/ regardless of working directory.
|
||||
echo "── Step 6: Marketplace plugins (scope: user) ────────────────"
|
||||
echo "── Step 5: Marketplace plugins (scope: user) ────────────────"
|
||||
echo ""
|
||||
|
||||
install_plugin() {
|
||||
@ -276,7 +273,7 @@ echo ""
|
||||
# ============================================================
|
||||
# STEP 6 — CONTEXT7 MCP (manual — requires API key)
|
||||
# ============================================================
|
||||
echo "── Step 7: Context7 MCP ─────────────────────────────────────"
|
||||
echo "── Step 6: Context7 MCP ─────────────────────────────────────"
|
||||
echo ""
|
||||
if claude mcp list 2>/dev/null | grep -q "context7"; then
|
||||
ok "Context7 MCP already configured"
|
||||
@ -316,7 +313,6 @@ echo ""
|
||||
echo " All plugins installed at: user scope (~/.claude/plugins/)"
|
||||
echo " GStack at: ~/.claude/skills/gstack/ (symlink → submodule)"
|
||||
echo ""
|
||||
echo " → Authenticate: gh auth login (GitHub) / glab auth login (GitLab)"
|
||||
echo " → Restart Claude Code"
|
||||
echo " → Run /reload-plugins"
|
||||
echo ""
|
||||
|
||||
64
lib/detect-plugins.sh
Normal file
64
lib/detect-plugins.sh
Normal file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# lib/detect-plugins.sh — Single source of truth for plugin detection
|
||||
# Sourced by: session-start.sh, doctor.sh, install-plugins.sh
|
||||
#
|
||||
# Each function returns 0 (detected) or 1 (not detected).
|
||||
# No output — callers handle messaging.
|
||||
# ============================================================
|
||||
|
||||
# --- Always-on plugins ---
|
||||
|
||||
detect_rtk() {
|
||||
command -v rtk &>/dev/null
|
||||
}
|
||||
|
||||
detect_superpowers() {
|
||||
# Fast check: filesystem (plugin cache)
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
if [ -d "$cache_dir" ]; then
|
||||
ls "$cache_dir" 2>/dev/null | grep -qi "superpowers" && return 0
|
||||
fi
|
||||
# Slow fallback: CLI (only if fast check fails)
|
||||
claude plugin list 2>/dev/null | grep -qi "superpowers" && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
detect_security_guidance() {
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
[ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "security-guidance"
|
||||
}
|
||||
|
||||
detect_skill_creator() {
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
[ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "skill-creator"
|
||||
}
|
||||
|
||||
detect_pr_review_toolkit() {
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
[ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "pr-review-toolkit"
|
||||
}
|
||||
|
||||
# --- Toggle plugins ---
|
||||
|
||||
detect_gstack() {
|
||||
[ -d "$HOME/.claude/skills/gstack" ]
|
||||
}
|
||||
|
||||
detect_gsd() {
|
||||
ls "$HOME/.claude/skills/" 2>/dev/null | grep -qi "gsd"
|
||||
}
|
||||
|
||||
detect_frontend_design() {
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
[ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "frontend-design"
|
||||
}
|
||||
|
||||
detect_uiux_pro_max() {
|
||||
local cache_dir="$HOME/.claude/plugins/cache"
|
||||
[ -d "$cache_dir" ] && ls "$cache_dir" 2>/dev/null | grep -qi "ui-ux-pro-max"
|
||||
}
|
||||
|
||||
detect_context7() {
|
||||
claude mcp list 2>/dev/null | grep -q "context7"
|
||||
}
|
||||
24
link.sh
24
link.sh
@ -9,21 +9,33 @@ CLAUDE="$HOME/.claude"
|
||||
|
||||
mkdir -p "$CLAUDE"
|
||||
|
||||
# Core config files
|
||||
# Core config files (plain files — ln -sf handles these correctly)
|
||||
ln -sf "$REPO/CLAUDE.md" "$CLAUDE/CLAUDE.md"
|
||||
ln -sf "$REPO/settings.json" "$CLAUDE/settings.json"
|
||||
|
||||
# Agents and skills
|
||||
ln -sf "$REPO/agents" "$CLAUDE/agents"
|
||||
ln -sf "$REPO/skills" "$CLAUDE/skills"
|
||||
# Agents and skills — must handle the case where target exists
|
||||
# as a real directory (ln -sf would create a link INSIDE the dir
|
||||
# instead of replacing it)
|
||||
for item in agents skills lib; do
|
||||
target="$CLAUDE/$item"
|
||||
if [ -L "$target" ]; then
|
||||
# Stale symlink from a previous run — remove before recreating
|
||||
rm -f "$target"
|
||||
elif [ -d "$target" ]; then
|
||||
echo "⚠️ ~/.claude/$item is a real directory (not a symlink)."
|
||||
echo " Rename or remove it, then re-run link.sh."
|
||||
echo " Skipping $item to avoid data loss."
|
||||
continue
|
||||
fi
|
||||
ln -sf "$REPO/$item" "$target"
|
||||
done
|
||||
|
||||
# Hooks
|
||||
mkdir -p "$CLAUDE/hooks"
|
||||
ln -sf "$REPO/hooks/session-start.sh" "$CLAUDE/hooks/session-start.sh"
|
||||
|
||||
# GStack (submodule) — symlink from skills-external/ into ~/.claude/skills/
|
||||
# GStack (submodule) — symlink into ~/.claude/skills/ (which points to repo/skills/)
|
||||
# The submodule must be initialized first (done by install-plugins.sh)
|
||||
mkdir -p "$CLAUDE/skills"
|
||||
if [ -d "$REPO/skills-external/gstack" ]; then
|
||||
ln -sf "$REPO/skills-external/gstack" "$CLAUDE/skills/gstack"
|
||||
echo "✅ GStack symlinked from submodule"
|
||||
|
||||
24
plugins.lock.json
Normal file
24
plugins.lock.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"_readme": "Pinned versions for reproducible installs. Update versions deliberately, then run install-plugins.sh.",
|
||||
"rtk": {
|
||||
"source": "https://github.com/rtk-ai/rtk",
|
||||
"install_cmd": "cargo install --git https://github.com/rtk-ai/rtk --tag {version}",
|
||||
"version": "v0.34.3",
|
||||
"note": "Check latest at https://github.com/rtk-ai/rtk/releases before updating"
|
||||
},
|
||||
"gsd": {
|
||||
"source": "npm:get-shit-done-cc",
|
||||
"install_cmd": "npx get-shit-done-cc@{version} --claude --global --auto",
|
||||
"version": "1.30.0",
|
||||
"note": "Check latest at https://www.npmjs.com/package/get-shit-done-cc before updating"
|
||||
},
|
||||
"gstack": {
|
||||
"source": "https://github.com/garrytan/gstack.git",
|
||||
"managed_by": "git submodule",
|
||||
"note": "Version controlled by submodule pointer in .gitmodules. Update: git submodule update --remote"
|
||||
},
|
||||
"node": {
|
||||
"minimum": "18",
|
||||
"recommended": "22"
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"_readme": "Global user settings \u2014 place at ~/.claude/settings.json. Applies to ALL projects. Never commit this file.",
|
||||
"_readme": "Global user settings — place at ~/.claude/settings.json. Applies to ALL projects. Never commit this file.",
|
||||
"cleanupPeriodDays": 30,
|
||||
"permissions": {
|
||||
"defaultMode": "default",
|
||||
@ -53,7 +53,35 @@
|
||||
"Write(**/.env.*)",
|
||||
"Write(**/secrets/**)",
|
||||
"Write(**/*.pem)",
|
||||
"Write(**/*.key)"
|
||||
"Write(**/*.key)",
|
||||
"Bash(bash -c *)",
|
||||
"Bash(eval *)",
|
||||
"Bash(exec *)",
|
||||
"Bash(find * -delete*)",
|
||||
"Bash(find * -exec rm*)",
|
||||
"Bash(find * -execdir rm*)",
|
||||
"Bash(perl -e *)",
|
||||
"Bash(ruby -e *)",
|
||||
"Bash(cat .env)",
|
||||
"Bash(cat .env.*)",
|
||||
"Bash(cat */.env)",
|
||||
"Bash(cat */.env.*)",
|
||||
"Bash(cat */secrets/*)",
|
||||
"Bash(cat */*.pem)",
|
||||
"Bash(cat */*.key)",
|
||||
"Bash(cat */id_rsa*)",
|
||||
"Bash(cat */id_ed25519*)",
|
||||
"Bash(cat */.aws/credentials)",
|
||||
"Bash(head .env)",
|
||||
"Bash(head .env.*)",
|
||||
"Bash(tail .env)",
|
||||
"Bash(tail .env.*)",
|
||||
"Bash(less .env)",
|
||||
"Bash(less .env.*)",
|
||||
"Bash(more .env)",
|
||||
"Bash(more .env.*)",
|
||||
"Bash(grep * .env)",
|
||||
"Bash(grep * .env.*)"
|
||||
],
|
||||
"ask": [
|
||||
"Bash(git push *)",
|
||||
@ -68,7 +96,10 @@
|
||||
"Bash(dnf install *)",
|
||||
"Bash(pacman -S *)",
|
||||
"WebSearch",
|
||||
"WebFetch"
|
||||
"WebFetch",
|
||||
"Bash(xargs *)",
|
||||
"Bash(sed -i *)",
|
||||
"Bash(sed -i'' *)"
|
||||
],
|
||||
"allow": [
|
||||
"Bash(git status)",
|
||||
@ -112,7 +143,6 @@
|
||||
"Bash(awk *)",
|
||||
"Bash(sort *)",
|
||||
"Bash(uniq *)",
|
||||
"Bash(xargs *)",
|
||||
"Bash(tr *)",
|
||||
"Bash(cut *)",
|
||||
"Bash(diff *)",
|
||||
@ -144,4 +174,4 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
---
|
||||
name: analyze
|
||||
description: Analyze code or a codebase deeply before any modification
|
||||
description: Deep factual code analysis — read-only, no solutions proposed
|
||||
argument-hint: <code, file, or area to analyze>
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Grep, Glob, Bash
|
||||
---
|
||||
|
||||
Load and follow strictly:
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
---
|
||||
name: git-pr
|
||||
description: Analyze all changes on the current branch since it diverged from base (retroactive across sessions), create logical commits, push, and open a draft PR/MR. Works with GitHub, GitLab, Gogs, and Gitea. Never merges — creates a draft for user validation.
|
||||
argument-hint: [PR title or leave empty for auto-detection]
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Bash, Grep, Glob
|
||||
---
|
||||
|
||||
Load and follow strictly:
|
||||
- .claude/agents/git-workflow.md
|
||||
|
||||
Execute the GIT WORKFLOW on the current repository.
|
||||
|
||||
User context (optional title or instructions):
|
||||
$ARGUMENTS
|
||||
18
skills/health/SKILL.md
Normal file
18
skills/health/SKILL.md
Normal file
@ -0,0 +1,18 @@
|
||||
---
|
||||
name: health
|
||||
description: Run setup diagnostic — check symlinks, plugins, permissions, token budget
|
||||
argument-hint: (no arguments needed)
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Bash
|
||||
---
|
||||
|
||||
Run the health check script and report findings to the user:
|
||||
|
||||
```bash
|
||||
bash ~/.claude/doctor.sh
|
||||
```
|
||||
|
||||
After displaying the output:
|
||||
- If errors are found, suggest the specific fix commands shown in the output.
|
||||
- If only warnings, note them but confirm the setup is functional.
|
||||
- If all checks pass, confirm the setup is healthy.
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: init-project
|
||||
description: Initialize a complete project from scratch. Plugin check → interview → analyze → design → validate → scaffold skeleton → plan v1 features → validate plan → implement (TDD, subagents) → analyze → review → finish. Same implementation rigor as ship-feature.
|
||||
description: Full project init: interview → design → scaffold → implement (TDD). Two validation gates.
|
||||
argument-hint: <project idea or description>
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
||||
@ -35,42 +35,7 @@ $ARGUMENTS
|
||||
|
||||
---
|
||||
|
||||
### STEP 0a — BRANCH SETUP
|
||||
|
||||
Load the BRANCH SETUP section from: `.claude/agents/git-workflow.md`
|
||||
|
||||
Before anything else, ensure we are NOT on a protected branch.
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
**If on `main`, `master`, `develop`, or any protected branch:**
|
||||
|
||||
Derive a branch slug from the initial request:
|
||||
- Take the first 3–4 meaningful words
|
||||
- Lowercase, hyphen-separated
|
||||
- Max 50 chars
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git pull origin <current> --ff-only 2>/dev/null || true
|
||||
git checkout -b feature/<project-slug>
|
||||
```
|
||||
|
||||
Print: `✅ Working branch created: feature/<project-slug>`
|
||||
|
||||
**If already on a feature branch:**
|
||||
Run the CONFLICT-SAFE REBASE procedure from git-workflow.md
|
||||
to sync with main before starting.
|
||||
|
||||
Print: `✅ Branch: <current> (synced with main)`
|
||||
|
||||
**Do not proceed until the branch is clean and ready.**
|
||||
|
||||
---
|
||||
|
||||
### STEP 0b — PLUGIN CHECK
|
||||
### STEP 0 — PLUGIN CHECK
|
||||
|
||||
Load and follow: `.claude/agents/plugin-advisor.md`
|
||||
|
||||
@ -88,7 +53,7 @@ B) Type "force" to proceed without them
|
||||
================================================================
|
||||
```
|
||||
**STOP. Wait for user response.**
|
||||
- Re-run → restart from STEP 0b
|
||||
- Re-run → restart from STEP 0
|
||||
- "force" → note missing plugins, continue to STEP 1
|
||||
|
||||
**If `ACTION REQUIRED: NO`:**
|
||||
@ -341,8 +306,7 @@ SYNC mode — no stop required. The readme-updater:
|
||||
|
||||
## RULES
|
||||
|
||||
- Never skip STEP 0a — branch setup is mandatory. Never commit on main/master.
|
||||
- Never skip STEP 0b — plugin check is mandatory.
|
||||
- Never skip STEP 0 — plugin check is mandatory.
|
||||
- Never skip STEP 1 — no assumptions about missing info.
|
||||
- Never implement without explicit user approval at STEP 4.
|
||||
- Never implement without explicit user approval at STEP 7.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: plugin-check
|
||||
description: Check active plugins vs current project needs. Recommends enabling or disabling based on context signals (frontend, design, QA, deployment, multi-session, fast-evolving libs). Run before init-project or ship-feature on a new project type.
|
||||
description: Audit active plugins vs project needs. Recommends enable/disable actions.
|
||||
argument-hint: [project description or feature to build]
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Bash, Glob, Grep
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: readme
|
||||
description: Update the project README to reflect the current state of the codebase. Audits what is outdated, missing, or no longer accurate, then applies surgical updates. Preserves existing structure and style.
|
||||
description: README audit — detect outdated sections, apply surgical updates
|
||||
argument-hint: [what changed, feature name, or leave empty for full audit]
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Write, Edit, Bash, Glob, Grep
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
---
|
||||
name: refactor
|
||||
description: Improve code quality without changing behavior
|
||||
description: Improve code quality without changing behavior — strict norm enforcement
|
||||
argument-hint: <file, function, or module to refactor>
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Write, Edit, Grep, Glob, Bash
|
||||
---
|
||||
|
||||
Load and follow strictly:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: ship-feature
|
||||
description: Ship a feature end-to-end using the Superpowers workflow. Starts with a plugin check, then Brainstorm → Plan → Implement (subagent-driven) → Review → Finish branch.
|
||||
description: Ship feature end-to-end: design → plan → implement (TDD) → review → finish
|
||||
argument-hint: <feature description>
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Write, Edit, Bash, Grep, Glob
|
||||
@ -33,48 +33,7 @@ $ARGUMENTS
|
||||
|
||||
---
|
||||
|
||||
### STEP 0a — BRANCH SETUP
|
||||
|
||||
Load the BRANCH SETUP section from: `.claude/agents/git-workflow.md`
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
**If on `main`, `master`, `develop`, or any protected branch:**
|
||||
|
||||
Derive a branch slug from the feature request:
|
||||
- Take the first 3–4 meaningful words from $ARGUMENTS
|
||||
- Lowercase, hyphen-separated, max 50 chars
|
||||
- Prefix with `feature/`
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git pull origin <current> --ff-only 2>/dev/null || true
|
||||
git checkout -b feature/<feature-slug>
|
||||
```
|
||||
|
||||
Print: `✅ Working branch created: feature/<feature-slug>`
|
||||
|
||||
**If already on a feature/bugfix/hotfix branch:**
|
||||
Run the CONFLICT-SAFE REBASE procedure from git-workflow.md
|
||||
to sync with the base branch before implementing.
|
||||
|
||||
Print: `✅ Branch: <current> (synced)`
|
||||
|
||||
**Special case — bugfix on a feature branch:**
|
||||
If the user explicitly says "bugfix" or "fix" in the request AND
|
||||
the current branch is a feature branch:
|
||||
```bash
|
||||
git checkout -b bugfix/<bug-slug>
|
||||
```
|
||||
Creates the bugfix branch FROM the feature branch — correct hierarchy.
|
||||
|
||||
**Do not proceed until the branch is clean.**
|
||||
|
||||
---
|
||||
|
||||
### STEP 0b — PLUGIN CHECK (mandatory gate)
|
||||
### STEP 0 — PLUGIN CHECK (mandatory gate)
|
||||
|
||||
Load and follow: `.claude/agents/plugin-advisor.md`
|
||||
|
||||
@ -105,7 +64,7 @@ Options:
|
||||
```
|
||||
|
||||
Wait for user response.
|
||||
- If user re-runs `/ship-feature` → start from STEP 0a again
|
||||
- If user re-runs `/ship-feature` → start from STEP 0 again
|
||||
- If user types "force" → note missing plugins and continue to STEP 1
|
||||
|
||||
**If the advisor output says `ACTION REQUIRED: NO`:**
|
||||
@ -198,40 +157,9 @@ SYNC mode — no stop required. The readme-updater:
|
||||
|
||||
---
|
||||
|
||||
### STEP 9 — CREATE PR (optional gate)
|
||||
|
||||
Ask the user:
|
||||
```
|
||||
================================================================
|
||||
SHIP FEATURE — PR CREATION
|
||||
================================================================
|
||||
Feature is implemented, tested, and README is synced.
|
||||
|
||||
Create a PR/MR now?
|
||||
yes → run /git-pr and open a draft PR
|
||||
no → stop here, you can run /git-pr manually later
|
||||
================================================================
|
||||
```
|
||||
|
||||
**STOP — wait for user response.**
|
||||
|
||||
IF yes:
|
||||
Load and follow: `.claude/agents/git-workflow.md`
|
||||
The git-workflow agent will:
|
||||
- Show all changes since branch start (retroactive)
|
||||
- Propose a commit plan for approval
|
||||
- Push and create a draft PR/MR on GitHub/GitLab/Gogs/Gitea
|
||||
|
||||
IF no:
|
||||
Print: `✅ Feature shipped. Run /git-pr when ready to open a PR.`
|
||||
Stop.
|
||||
|
||||
---
|
||||
|
||||
## RULES
|
||||
|
||||
- Never skip STEP 0a — branch setup is mandatory. Never implement on main/master.
|
||||
- Never skip STEP 0b — plugin check is mandatory.
|
||||
- Never skip STEP 0 — plugin check is mandatory.
|
||||
- Never skip brainstorming.
|
||||
- Never implement without explicit user approval of the plan.
|
||||
- Keep subagents isolated — no shared context between tasks.
|
||||
|
||||
78
update-all.sh
Normal file
78
update-all.sh
Normal file
@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================
|
||||
# Claude Code — Update all components
|
||||
# Pulls latest config, updates submodules, refreshes symlinks,
|
||||
# and runs doctor to verify.
|
||||
# ============================================================
|
||||
set -euo pipefail
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||||
ok() { echo -e "${GREEN}✓${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
||||
info() { echo -e "${BLUE}→${NC} $1"; }
|
||||
|
||||
REPO="$(cd "$(dirname "$0")" && pwd)"
|
||||
VERSION=$(cat "$REPO/version.txt" 2>/dev/null || echo "unknown")
|
||||
|
||||
echo ""
|
||||
echo "═══ claude-config update (v${VERSION}) ═══"
|
||||
echo ""
|
||||
|
||||
# ── 1. Pull latest config ──
|
||||
echo "── Pulling latest config..."
|
||||
cd "$REPO"
|
||||
if git pull --rebase 2>/dev/null; then
|
||||
ok "Config repo updated"
|
||||
else
|
||||
warn "git pull failed — check for uncommitted changes"
|
||||
fi
|
||||
|
||||
# ── 2. Update GStack submodule ──
|
||||
echo ""
|
||||
echo "── Updating GStack submodule..."
|
||||
if git submodule update --remote skills-external/gstack 2>/dev/null; then
|
||||
if [ -d "skills-external/gstack" ]; then
|
||||
cd skills-external/gstack && ./setup 2>/dev/null && cd "$REPO"
|
||||
ok "GStack updated"
|
||||
fi
|
||||
else
|
||||
warn "GStack submodule update failed — run: git submodule update --init"
|
||||
fi
|
||||
|
||||
# ── 3. Update RTK (if pinned version available) ──
|
||||
echo ""
|
||||
echo "── Updating RTK..."
|
||||
if command -v cargo &>/dev/null; then
|
||||
RTK_VERSION=""
|
||||
if [ -f "$REPO/plugins.lock.json" ] && command -v python3 &>/dev/null; then
|
||||
RTK_VERSION=$(python3 -c "
|
||||
import json
|
||||
with open('$REPO/plugins.lock.json') as f:
|
||||
d = json.load(f)
|
||||
print(d.get('rtk',{}).get('version',''))
|
||||
" 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
if [ -n "$RTK_VERSION" ] && [ "$RTK_VERSION" != "latest" ]; then
|
||||
info "Pinned version: $RTK_VERSION"
|
||||
cargo install --git https://github.com/rtk-ai/rtk --tag "$RTK_VERSION" --force 2>/dev/null \
|
||||
&& ok "RTK updated to $RTK_VERSION" \
|
||||
|| warn "RTK update failed"
|
||||
else
|
||||
info "No pinned version — installing latest"
|
||||
cargo install --git https://github.com/rtk-ai/rtk --force 2>/dev/null \
|
||||
&& ok "RTK updated (latest)" \
|
||||
|| warn "RTK update failed"
|
||||
fi
|
||||
else
|
||||
warn "Cargo not available — skipping RTK"
|
||||
fi
|
||||
|
||||
# ── 4. Refresh symlinks ──
|
||||
echo ""
|
||||
echo "── Refreshing symlinks..."
|
||||
bash "$REPO/link.sh"
|
||||
|
||||
# ── 5. Run doctor ──
|
||||
echo ""
|
||||
bash "$REPO/doctor.sh"
|
||||
1
version.txt
Normal file
1
version.txt
Normal file
@ -0,0 +1 @@
|
||||
1.0.0
|
||||
Loading…
Reference in New Issue
Block a user