diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 0000000..5a49cd8 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", + "name": "codeforerunner", + "description": "Repo documentation tooling for Claude Code. Adds /forerunner-scan, /forerunner-readme, /forerunner-check, and 9 other documentation slash commands.", + "owner": { + "name": "Derek Palmer", + "url": "https://github.com/derek-palmer" + }, + "plugins": [ + { + "name": "codeforerunner", + "description": "Model-agnostic repo documentation prompts. Slash commands for scan, readme, api-docs, diagrams, flows, stack-docs, version-audit, check, review, audit, changelog, and agent onboarding.", + "source": "./", + "category": "productivity" + } + ] +} diff --git a/.codex/config.toml b/.codex/config.toml new file mode 100644 index 0000000..27f2e0e --- /dev/null +++ b/.codex/config.toml @@ -0,0 +1,5 @@ +# codeforerunner Codex integration +# Skills installed here are available as Codex slash commands. + +[features] +skills = true diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..5933de3 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,48 @@ +# codeforerunner — Gemini CLI context + +Model-agnostic repository documentation tooling. Ships prompt packs for codebase analysis, doc generation, drift detection, and agent onboarding. Python CLI + MCP server + agent skills. + +## Available tasks + +Run any task via `forerunner doc `, or use the installed Gemini extension skills: + +| Slash command | Task | Description | +|---|---|---| +| `/forerunner-scan` | `scan` | Scan repo; always run first | +| `/forerunner-readme` | `readme` | Generate or refresh README.md | +| `/forerunner-api-docs` | `api-docs` | Generate API reference | +| `/forerunner-diagrams` | `diagrams` | Generate Mermaid architecture diagrams | +| `/forerunner-flows` | `flows` | Document system flows | +| `/forerunner-stack-docs` | `stack-docs` | Stack-specific developer docs | +| `/forerunner-version-audit` | `version-audit` | Audit pinned versions vs EOL | +| `/forerunner-check` | `check` | Check docs for staleness | +| `/forerunner-review` | `review` | Doc-impact summary for PR review | +| `/forerunner-audit` | `audit` | Security and dependency audit | +| `/forerunner-changelog` | `changelog` | Generate changelog entry from git log | +| `/forerunner-init` | `init-agent-onboarding` | Bootstrap or refresh AGENTS.md | + +## Workflow + +1. Start with `/forerunner-scan` to collect repo evidence. +2. Run the documentation task you need. +3. Use `/forerunner-check` before commits to detect drift. + +## CLI quick reference + +```bash +forerunner doc # Get composed prompt for a task +forerunner generate # Call configured provider directly +forerunner check # Run drift-detection rules +forerunner doctor # Health report +forerunner install gemini # Install skills to Gemini config dir +``` + +## Config + +Drop a `forerunner.config.yaml` at repo root to enable drift rules. Run `forerunner doctor --fix` to generate a starter config. + +## Sources + +- Prompts: `src/codeforerunner/prompts/tasks/` +- Skills: `skills/` (source) → `plugins/codeforerunner/skills/` (distribution) +- Repo: https://github.com/derek-palmer/codeforerunner diff --git a/README.md b/README.md index a93bb84..204ab95 100644 --- a/README.md +++ b/README.md @@ -2,115 +2,160 @@ # codeForerunner -Model-agnostic repository documentation tooling. Ships a prompt pack for codebase analysis and doc generation, a thin Python CLI, an MCP server, a Codex marketplace plugin, and drift-detection rules that keep docs honest. +Model-agnostic repository documentation tooling. Ships a prompt pack for codebase analysis and doc generation, a thin Python CLI, an MCP server, drift-detection rules that keep docs honest — and native slash-command skills for Claude Code, Codex, Gemini CLI, and other agent CLIs. -## Install +## Two modes + +### Mode A — Agent skill (recommended, no API key required) + +Install forerunner's prompt pack as skills into your agent CLI. Each documentation task becomes a slash command (`/forerunner-readme`, `/forerunner-check`, etc.) available inside Claude Code, Codex, Gemini CLI, and other agents. Authentication is handled by your existing agent subscription — no separate API key needed. + +```bash +# From a cloned repo +./install.sh + +# One-liner (auto-detects Claude Code, Codex, Gemini CLI) +curl -fsSL https://raw.githubusercontent.com/derek-palmer/codeforerunner/main/install.sh | bash + +# Windows +irm https://raw.githubusercontent.com/derek-palmer/codeforerunner/main/install.ps1 | iex + +# Via forerunner CLI (after pip install) +forerunner install --all claude +forerunner install --all codex +``` + +Then in your agent: + +``` +/forerunner-scan ← scan the repo first +/forerunner-readme ← generate README +/forerunner-check ← detect doc drift +``` + +### Mode B — Direct API (needs API key or Ollama) + +Install the Python CLI and call your provider directly. Works without any agent CLI installed. ```bash -pipx install codeforerunner # recommended — isolated environment +pipx install codeforerunner # recommended pip install codeforerunner # alternative ``` -From source: +Configure a provider (or start Ollama for keyless local generation): ```bash -git clone https://github.com/derek-palmer/codeforerunner -cd codeforerunner -python -m pip install -e . +export ANTHROPIC_API_KEY=sk-... +forerunner generate readme --stream ``` -Verify: `forerunner --help` +If no API key and no `--provider` flag, forerunner auto-detects Ollama at `localhost:11434` and falls back to local mode. + +## Slash commands + +| Command | Task | Purpose | +|---------|------|---------| +| `/forerunner-scan` | `scan` | Collect repo evidence (run first) | +| `/forerunner-readme` | `readme` | Generate or refresh README.md | +| `/forerunner-api-docs` | `api-docs` | Generate API reference docs | +| `/forerunner-diagrams` | `diagrams` | Generate Mermaid architecture diagrams | +| `/forerunner-flows` | `flows` | Document system flows | +| `/forerunner-stack-docs` | `stack-docs` | Stack-specific developer docs | +| `/forerunner-version-audit` | `version-audit` | Audit pinned versions vs EOL | +| `/forerunner-check` | `check` | Check docs for staleness | +| `/forerunner-review` | `review` | Doc-impact summary for PR review | +| `/forerunner-audit` | `audit` | Security and dependency audit | +| `/forerunner-changelog` | `changelog` | Generate changelog from git log | +| `/forerunner-init` | `init-agent-onboarding` | Bootstrap or refresh AGENTS.md | + +Slash command availability depends on the agent CLI. Claude Code, Codex, and Gemini CLI support all 12 commands after install. + +## Skill install options + +| Flag | Effect | +|------|--------| +| `./install.sh` | Auto-detect all agents, install all skills | +| `./install.sh --only claude` | Claude Code only | +| `./install.sh --only codex` | Codex only | +| `./install.sh --only gemini` | Gemini CLI only | +| `./install.sh --dry-run` | Preview, write nothing | +| `./install.sh --list` | Show detected agents + skill list | +| `./install.sh --uninstall` | Remove all installed skills | ## CLI +```bash +pip install codeforerunner +``` + | Command | Purpose | |---------|---------| -| `forerunner init` | Resolve agent-onboarding bundle to stdout (`--full` prepends scan; `--agents-only` is the default scope). | +| `forerunner init` | Resolve agent-onboarding bundle to stdout. | | `forerunner scan` | Resolve scan bundle to stdout. | | `forerunner doc ` | Resolve `base + partials + task` bundle to stdout. | -| `forerunner check` | Run drift-detection rules; silent no-op without `forerunner.config.yaml`. | -| `forerunner generate ` | Resolve bundle for `` and call the configured provider. Add `--stream` to stream output token-by-token. | -| `forerunner doctor` | Single-screen health report: skill parity, marketplace validation, installed destinations, config, provider key. Add `--fix` to write a starter `forerunner.config.yaml` if absent. | +| `forerunner check` | Run drift-detection rules; no-op without `forerunner.config.yaml`. | +| `forerunner generate ` | Call configured provider directly. Add `--stream` for token-by-token output. Falls back to Ollama automatically when no API key is configured. | +| `forerunner doctor` | Health report: skill parity, config, provider key, local-mode status. Add `--fix` to write a starter config. | | `forerunner mcp-server` | Serve prompt bundles as MCP tools over stdio (JSON-RPC 2.0). | -| `forerunner install ` | Idempotently write the canonical skill into agent-specific directories. | +| `forerunner install ` | Install canonical skill into agent-specific directory. Add `--all` for all per-task skills. | -## Prompt Pack +## Prompt pack Prompts are bundled inside the package at `src/codeforerunner/prompts/`. ```text prompts/ -├── system/ -│ └── base.md +├── system/base.md ├── partials/ │ ├── context-format.md │ ├── output-rules.md │ └── stack-hints.md └── tasks/ - ├── scan.md - ├── init-agent-onboarding.md - ├── readme.md - ├── api-docs.md - ├── stack-docs.md - ├── diagrams.md - ├── flows.md - ├── version-audit.md - ├── check.md - ├── review.md - ├── audit.md - └── changelog.md + ├── scan.md api-docs.md audit.md + ├── readme.md diagrams.md changelog.md + ├── check.md flows.md version-audit.md + ├── review.md stack-docs.md + └── init-agent-onboarding.md ``` -| Task | Purpose | -|------|---------| -| `scan` | Structured repo scan used by downstream tasks. | -| `init-agent-onboarding` | Generates or updates `AGENTS.md` from repo evidence. | -| `readme` | Generates or rewrites a top-level README. | -| `api-docs` | Documents public APIs. | -| `stack-docs` | Documents stack-specific areas. | -| `diagrams` | Generates Mermaid architecture or flow diagrams. | -| `flows` | Documents user, request, job, or data flows. | -| `version-audit` | Audits pinned versions from manifests, lockfiles, workflows, IaC. | -| `check` | Checks existing docs for staleness against a fresh scan. | -| `review` | Summarizes documentation impact for review. | -| `audit` | Security and dependency audit report. | -| `changelog` | Generates a Keep-a-Changelog entry from git log. | - -## Quick Start +## Quick start (agent skill mode) ```bash -# 1. Point your agent at the scan prompt -forerunner scan +# Install skills into Claude Code +curl -fsSL https://raw.githubusercontent.com/derek-palmer/codeforerunner/main/install.sh | bash -# 2. Generate or update docs for a task -export FORERUNNER_SCAN_DONE=1 -forerunner doc readme - -# 3. Direct model call (needs provider config) -forerunner generate readme --stream +# In Claude Code: +# /forerunner-scan → scans your repo +# /forerunner-readme → generates README.md +# /forerunner-check → checks for doc drift ``` -## GitHub Action +## Quick start (direct API mode) -Use forerunner check as a reusable action in any workflow: +```bash +# 1. Install and configure +pip install codeforerunner +export ANTHROPIC_API_KEY=sk-... -```yaml -- uses: derek-palmer/codeforerunner@v0.3.2 +# 2. Run a task +forerunner generate readme --stream + +# 3. Enable drift detection +forerunner doctor --fix # writes forerunner.config.yaml +forerunner check # run any time or as pre-commit hook ``` -With a pinned version: +## GitHub Action ```yaml - uses: derek-palmer/codeforerunner@v0.3.2 - with: - version: '0.3.2' ``` No-op when `forerunner.config.yaml` is absent. ## Configuration -Copy `forerunner.config.yaml.example` to `forerunner.config.yaml` to opt in. Without that file, `forerunner check` is a silent no-op. Generate a starter config with: +Copy `forerunner.config.yaml.example` to `forerunner.config.yaml` to opt in to drift rules. Generate a starter config with: ```bash forerunner doctor --fix @@ -122,7 +167,7 @@ forerunner doctor --fix provider: anthropic # anthropic | openai | google | ollama model: claude-opus-4-7 api_key_env: - anthropic: ANTHROPIC_API_KEY # override per-provider env var name + anthropic: ANTHROPIC_API_KEY tasks: check: @@ -134,10 +179,10 @@ tasks: - R5-no-python-package - R7-no-mcp - R8-no-marketplace - - RI1-missing-cli # inverse: doc claims CLI but file absent + - RI1-missing-cli - RI5-missing-python-package - RI7-missing-mcp - - RV1-version-drift # pinned version in docs ≠ pyproject.toml + - RV1-version-drift ignore_paths: - docs/legacy/**/*.md ``` @@ -159,7 +204,7 @@ tasks: | `RI7-missing-mcp` | Doc references `forerunner mcp-server` but `mcp_server.py` absent | | `RV1-version-drift` | Doc pins `codeforerunner==X.Y.Z` differing from current version | -### MCP Server +## MCP Server `forerunner mcp-server` speaks JSON-RPC 2.0 over stdio and exposes one tool per `prompts/tasks/*.md`. A scan-first gate enforces SPEC V2: any tool except `scan` or `init-agent-onboarding` returns an error until `scan` has been called in the same session. @@ -167,7 +212,7 @@ See `examples/mcp/` for Claude Desktop and mcp-cli wiring examples. ## Providers -`forerunner generate` supports four providers. Set the appropriate env var before calling: +`forerunner generate` supports four providers. When no provider is explicitly configured and no API key is found, forerunner probes `localhost:11434` and falls back to Ollama automatically. | Provider | Env var | Default model | |----------|---------|---------------| @@ -176,20 +221,11 @@ See `examples/mcp/` for Claude Desktop and mcp-cli wiring examples. | `google` | `GOOGLE_API_KEY` | `gemini-2.5-pro` | | `ollama` | `OLLAMA_HOST` (optional) | `llama3` | -## Codex Plugin - -```bash -forerunner install codex --marketplace -``` - -Installs the Codex marketplace entry and skill. Or install manually: -`forerunner install ` copies the canonical skill into the agent-specific directory. - -## Docs and Spec +## Docs and spec - `SPEC.md` — canonical phase/task tracker - `docs/getting-started.md` — manual prompt use - `docs/prompt-guide.md` — how system, partial, and task prompts compose - `docs/editor-agent-setup.md` — adapting prompts to local agents - `docs/roadmap.md` — human-readable roadmap -- `docs/agent-distribution-design.md` — design backing Codex/Claude packages +- `docs/agent-distribution-design.md` — packaging and installer design diff --git a/bin/install.js b/bin/install.js new file mode 100644 index 0000000..dfad458 --- /dev/null +++ b/bin/install.js @@ -0,0 +1,451 @@ +#!/usr/bin/env node +// codeforerunner — unified cross-platform installer. +// +// Installs forerunner's prompt-pack skills into every detected agent CLI +// so documentation slash commands (/forerunner-scan, /forerunner-readme, +// etc.) are available without a separate API key. +// +// Distribution: +// Local clone: node bin/install.js [flags] +// curl|bash: delegated from install.sh shim → npx -y github:derek-palmer/codeforerunner -- [flags] +// Windows: pwsh install.ps1 [flags] → same npx delegation +// +// Pure stdlib, zero npm runtime deps. +// Modelled on JuliusBrussee/caveman bin/install.js. + +'use strict'; + +const fs = require('fs'); +const os = require('os'); +const path = require('path'); +const child_process = require('child_process'); + +const REPO = 'derek-palmer/codeforerunner'; +const RAW_BASE = `https://raw.githubusercontent.com/${REPO}/main`; + +// ── Argv ────────────────────────────────────────────────────────────────── + +function parseArgs(argv) { + const opts = { + dryRun: false, force: false, skipSkills: false, + all: false, minimal: false, listOnly: false, noColor: false, + only: [], uninstall: false, help: false, + }; + for (let i = 0; i < argv.length; i++) { + const a = argv[i]; + switch (a) { + case '--dry-run': opts.dryRun = true; break; + case '--force': opts.force = true; break; + case '--skip-skills': opts.skipSkills = true; break; + case '--all': opts.all = true; break; + case '--minimal': opts.minimal = true; break; + case '--list': opts.listOnly = true; break; + case '--no-color': opts.noColor = true; break; + case '--uninstall': case '-u': opts.uninstall = true; break; + case '-h': case '--help': opts.help = true; break; + case '--': break; // npx may forward a literal -- + case '--only': { + const v = argv[++i]; + if (!v) die('error: --only requires an argument'); + opts.only.push(v); + break; + } + default: + die(`error: unknown flag: ${a}\nrun with --help for usage`); + } + } + if (opts.all && opts.minimal) die('error: --all and --minimal are mutually exclusive'); + if (opts.only.length) { + const known = new Set(PROVIDERS.map(p => p.id)); + for (const id of opts.only) { + if (!known.has(id)) die(`error: unknown agent: ${id}\n see --list for valid ids`); + } + } + return opts; +} + +function die(msg) { process.stderr.write(msg + '\n'); process.exit(2); } + +// ── Color helpers ───────────────────────────────────────────────────────── + +function makeChalk(noColor) { + const use = !noColor && process.stdout.isTTY && !process.env.NO_COLOR; + const wrap = (c) => (s) => use ? `\x1b[${c}m${s}\x1b[0m` : s; + return { + green: wrap('32'), + yellow: wrap('33'), + red: wrap('31'), + dim: wrap('2'), + bold: wrap('1'), + cyan: wrap('36'), + }; +} + +// ── Provider matrix ─────────────────────────────────────────────────────── +// Same detection rules as caveman/bin/install.js: +// command: — binary on PATH +// dir: — directory exists (soft-only; avoid false positives) +// file: — file exists +// macapp: — /Applications/.app present +// vscode-ext: — VS Code / Cursor / Windsurf extension dir match +// cursor-ext: — Cursor extension dir match only +// jetbrains-plugin: — JetBrains plugin dir walk +// +// `soft: true` → excluded from auto-detect; only installs with --only . +// `profile` → npx skills add profile slug (https://github.com/vercel-labs/skills) + +const PROVIDERS = [ + { id: 'claude', label: 'Claude Code', mech: 'claude plugin install', detect: 'command:claude' }, + { id: 'gemini', label: 'Gemini CLI', mech: 'gemini extensions install', detect: 'command:gemini' }, + { id: 'opencode', label: 'opencode', mech: 'npx skills add (opencode)', detect: 'command:opencode', profile: 'opencode' }, + { id: 'codex', label: 'Codex CLI', mech: 'npx skills add (codex)', detect: 'command:codex', profile: 'codex' }, + + { id: 'cursor', label: 'Cursor', mech: 'npx skills add (cursor)', detect: 'command:cursor||macapp:Cursor', profile: 'cursor' }, + { id: 'windsurf', label: 'Windsurf', mech: 'npx skills add (windsurf)', detect: 'command:windsurf||macapp:Windsurf', profile: 'windsurf' }, + { id: 'cline', label: 'Cline', mech: 'npx skills add (cline)', detect: 'vscode-ext:cline', profile: 'cline' }, + { id: 'continue', label: 'Continue', mech: 'npx skills add (continue)', detect: 'vscode-ext:continue.continue||vscode-ext:continue', profile: 'continue' }, + { id: 'kilo', label: 'Kilo Code', mech: 'npx skills add (kilo)', detect: 'vscode-ext:kilocode', profile: 'kilo' }, + { id: 'roo', label: 'Roo Code', mech: 'npx skills add (roo)', detect: 'vscode-ext:roo||vscode-ext:rooveterinaryinc.roo-cline||cursor-ext:roo', profile: 'roo' }, + { id: 'augment', label: 'Augment Code', mech: 'npx skills add (augment)', detect: 'vscode-ext:augment||jetbrains-plugin:augment', profile: 'augment' }, + + { id: 'copilot', label: 'GitHub Copilot', mech: 'npx skills add (github-copilot)', detect: 'command:copilot', profile: 'github-copilot', soft: true }, + + { id: 'aider-desk', label: 'Aider Desk', mech: 'npx skills add (aider-desk)', detect: 'command:aider', profile: 'aider-desk' }, + { id: 'amp', label: 'Sourcegraph Amp', mech: 'npx skills add (amp)', detect: 'command:amp', profile: 'amp' }, + { id: 'bob', label: 'IBM Bob', mech: 'npx skills add (bob)', detect: 'command:bob', profile: 'bob' }, + { id: 'crush', label: 'Crush', mech: 'npx skills add (crush)', detect: 'command:crush', profile: 'crush' }, + { id: 'devin', label: 'Devin (terminal)', mech: 'npx skills add (devin)', detect: 'command:devin', profile: 'devin' }, + { id: 'droid', label: 'Droid (Factory)', mech: 'npx skills add (droid)', detect: 'command:droid', profile: 'droid' }, + { id: 'forgecode', label: 'ForgeCode', mech: 'npx skills add (forgecode)', detect: 'command:forge', profile: 'forgecode' }, + { id: 'goose', label: 'Block Goose', mech: 'npx skills add (goose)', detect: 'command:goose', profile: 'goose' }, + { id: 'iflow', label: 'iFlow CLI', mech: 'npx skills add (iflow-cli)', detect: 'command:iflow', profile: 'iflow-cli' }, + { id: 'kiro', label: 'Kiro CLI', mech: 'npx skills add (kiro-cli)', detect: 'command:kiro', profile: 'kiro-cli' }, + { id: 'mistral', label: 'Mistral Vibe', mech: 'npx skills add (mistral-vibe)', detect: 'command:mistral', profile: 'mistral-vibe' }, + { id: 'openhands', label: 'OpenHands', mech: 'npx skills add (openhands)', detect: 'command:openhands', profile: 'openhands' }, + { id: 'qwen', label: 'Qwen Code', mech: 'npx skills add (qwen-code)', detect: 'command:qwen', profile: 'qwen-code' }, + { id: 'rovodev', label: 'Atlassian Rovo Dev', mech: 'npx skills add (rovodev)', detect: 'command:rovodev', profile: 'rovodev' }, + { id: 'tabnine', label: 'Tabnine CLI', mech: 'npx skills add (tabnine-cli)', detect: 'command:tabnine', profile: 'tabnine-cli' }, + { id: 'trae', label: 'Trae', mech: 'npx skills add (trae)', detect: 'command:trae', profile: 'trae' }, + { id: 'warp', label: 'Warp', mech: 'npx skills add (warp)', detect: 'command:warp', profile: 'warp' }, + { id: 'replit', label: 'Replit Agent', mech: 'npx skills add (replit)', detect: 'command:replit', profile: 'replit' }, + + { id: 'junie', label: 'JetBrains Junie', mech: 'npx skills add (junie)', detect: 'jetbrains-plugin:junie', profile: 'junie', soft: true }, + { id: 'qoder', label: 'Qoder', mech: 'npx skills add (qoder)', detect: 'dir:$HOME/.qoder', profile: 'qoder', soft: true }, + { id: 'antigravity', label: 'Google Antigravity', mech: 'npx skills add (antigravity)', detect: 'dir:$HOME/.gemini/antigravity', profile: 'antigravity', soft: true }, +]; + +// ── Detection helpers ───────────────────────────────────────────────────── + +const IS_WIN = process.platform === 'win32'; + +function shellEscape(s) { return `'${String(s).replace(/'/g, `'\\''`)}`; } + +function expandHome(p) { + return String(p).replace(/^\$HOME(?=\/|$)/, os.homedir()).replace(/^~(?=\/|$)/, os.homedir()); +} + +function hasCmd(cmd) { + try { + if (IS_WIN) { + return child_process.spawnSync('where', [cmd], { stdio: 'ignore' }).status === 0; + } + return child_process.spawnSync('sh', ['-c', `command -v ${shellEscape(cmd)}`], { stdio: 'ignore' }).status === 0; + } catch (_) { return false; } +} + +function safeStat(p, method) { + try { return fs.statSync(p)[method](); } catch (_) { return false; } +} + +function macAppPresent(name) { + if (process.platform !== 'darwin') return false; + return [ + `/Applications/${name}.app`, + path.join(os.homedir(), 'Applications', `${name}.app`), + ].some(p => fs.existsSync(p)); +} + +function vscodeExtPresent(needle) { + const roots = [ + path.join(os.homedir(), '.vscode/extensions'), + path.join(os.homedir(), '.vscode-server/extensions'), + path.join(os.homedir(), '.cursor/extensions'), + path.join(os.homedir(), '.windsurf/extensions'), + ]; + const re = new RegExp(needle, 'i'); + for (const r of roots) { + if (!fs.existsSync(r)) continue; + let entries; try { entries = fs.readdirSync(r); } catch (_) { continue; } + if (entries.some(e => re.test(e))) return true; + } + return false; +} + +function cursorExtPresent(needle) { + const dir = path.join(os.homedir(), '.cursor/extensions'); + if (!fs.existsSync(dir)) return false; + const re = new RegExp(needle, 'i'); + try { return fs.readdirSync(dir).some(e => re.test(e)); } catch (_) { return false; } +} + +function walkDir(root, depth) { + if (depth < 0) return []; + const out = []; + let entries; try { entries = fs.readdirSync(root, { withFileTypes: true }); } catch (_) { return out; } + for (const e of entries) { + const full = path.join(root, e.name); + if (e.isDirectory()) { out.push(full); out.push(...walkDir(full, depth - 1)); } + } + return out; +} + +function jetbrainsPluginPresent(needle) { + const roots = [ + path.join(os.homedir(), 'Library/Application Support/JetBrains'), + path.join(os.homedir(), '.config/JetBrains'), + ]; + const re = new RegExp(needle, 'i'); + for (const r of roots) { + if (!fs.existsSync(r)) continue; + if (walkDir(r, 4).some(p => re.test(path.basename(p)))) return true; + } + return false; +} + +// detectMatch — parse `||`-delimited probe specs and return true on first match. +// Handles bash-3.2-style `||` splitting cleanly even with whitespace around delimiters. +function detectMatch(spec) { + if (!spec) return false; + for (const clause of spec.split('||')) { + const c = clause.trim(); + if (!c) continue; + const colon = c.indexOf(':'); + const kind = colon === -1 ? c : c.slice(0, colon); + const val = colon === -1 ? '' : expandHome(c.slice(colon + 1)); + let ok = false; + switch (kind) { + case 'command': ok = hasCmd(val); break; + case 'dir': ok = safeStat(val, 'isDirectory'); break; + case 'file': ok = safeStat(val, 'isFile'); break; + case 'macapp': ok = macAppPresent(val); break; + case 'vscode-ext': ok = vscodeExtPresent(val); break; + case 'cursor-ext': ok = cursorExtPresent(val); break; + case 'jetbrains-plugin': ok = jetbrainsPluginPresent(val); break; + } + if (ok) return true; + } + return false; +} + +// ── Platform spawn helpers ──────────────────────────────────────────────── + +function quoteWinArg(a) { + if (!IS_WIN) return a; + if (a === '' || /[\s"]/.test(a)) { + return '"' + String(a).replace(/\\(?=\\*"|$)/g, '\\\\').replace(/"/g, '\\"') + '"'; + } + return a; +} + +function spawnXplat(cmd, args, opts) { + if (IS_WIN) { + const quoted = args.map(quoteWinArg).join(' '); + return child_process.spawnSync(`${cmd} ${quoted}`, [], Object.assign({ shell: true }, opts || {})); + } + return child_process.spawnSync(cmd, args, opts || {}); +} + +function runSpawn(cmd, args, dryRun, c) { + const line = `${cmd} ${args.join(' ')}`; + if (dryRun) { process.stdout.write(` ${c.dim('would run:')} ${line}\n`); return { status: 0 }; } + process.stdout.write(` ${c.dim('$')} ${line}\n`); + return spawnXplat(cmd, args, { stdio: 'inherit' }); +} + +function captureSpawn(cmd, args) { + try { return spawnXplat(cmd, args, { encoding: 'utf8' }); } + catch (_) { return { status: 1, stdout: '', stderr: '' }; } +} + +// ── Repo root detection ─────────────────────────────────────────────────── + +function detectRepoRoot() { + const here = path.dirname(__filename); + const root = path.resolve(here, '..'); + if (fs.existsSync(path.join(root, 'skills')) && + fs.existsSync(path.join(root, 'plugins', 'codeforerunner', 'skills'))) { + return root; + } + return null; +} + +// ── Per-provider install logic ──────────────────────────────────────────── + +function installClaude(opts, results, c) { + results.detected++; + process.stdout.write(`\n${c.bold('→ Claude Code')}\n`); + + if (!opts.force) { + const r = captureSpawn('claude', ['plugin', 'list']); + if (r.status === 0 && /codeforerunner/i.test(r.stdout || '')) { + process.stdout.write(` ${c.dim('codeforerunner plugin already installed (use --force to reinstall)')}\n`); + results.skipped.push({ id: 'claude', why: 'already installed' }); + return; + } + } + const r1 = runSpawn('claude', ['plugin', 'marketplace', 'add', REPO], opts.dryRun, c); + const r2 = runSpawn('claude', ['plugin', 'install', 'codeforerunner@codeforerunner'], opts.dryRun, c); + if ((r1.status || 0) === 0 && (r2.status || 0) === 0) results.installed.push('claude'); + else results.failed.push({ id: 'claude', why: 'claude plugin install failed' }); +} + +function installGemini(opts, results, c) { + results.detected++; + process.stdout.write(`\n${c.bold('→ Gemini CLI')}\n`); + + if (!opts.force) { + const r = captureSpawn('gemini', ['extensions', 'list']); + if (r.status === 0 && /codeforerunner/i.test(r.stdout || '')) { + process.stdout.write(` ${c.dim('codeforerunner extension already installed (use --force to reinstall)')}\n`); + results.skipped.push({ id: 'gemini', why: 'already installed' }); + return; + } + } + const r = runSpawn('gemini', ['extensions', 'install', `https://github.com/${REPO}`], opts.dryRun, c); + if ((r.status || 0) === 0) results.installed.push('gemini'); + else results.failed.push({ id: 'gemini', why: 'gemini extensions install failed' }); +} + +function installViaSkills(prov, opts, results, c) { + results.detected++; + process.stdout.write(`\n${c.bold(`→ ${prov.label}`)}\n`); + // --yes --all: skip the upstream skill-selection TUI. Without these, curl|bash + // (no TTY on stdin) renders an empty checkbox list and exits 0 with nothing installed. + const args = ['-y', 'skills', 'add', REPO, '-a', prov.profile, '--yes', '--all']; + const r = runSpawn('npx', args, opts.dryRun, c); + if ((r.status || 0) === 0) results.installed.push(prov.id); + else results.failed.push({ id: prov.id, why: `npx skills add (${prov.profile}) failed` }); +} + +// ── Help / list ─────────────────────────────────────────────────────────── + +function printHelp() { + process.stdout.write(`\ +codeforerunner installer — adds /forerunner-* slash commands to agent CLIs + +Usage: + node bin/install.js [flags] + +Flags: + --all Install to every detected agent (default mode) + --minimal Install without any extras + --only Install to a specific agent only (repeatable) + --force Reinstall even if already installed + --skip-skills Skip the npx skills add step + --dry-run Print what would run; write nothing + --list Show all supported agents and detection status + --no-color Disable colored output + --uninstall, -u Remove codeforerunner from detected agents + -h, --help Show this help + +Agents (${PROVIDERS.length}): +${PROVIDERS.map(p => ` ${p.id.padEnd(14)} ${p.label}`).join('\n')} +`); +} + +function printList(c) { + process.stdout.write(`codeforerunner installer — ${PROVIDERS.length} supported agents\n\n`); + const maxId = Math.max(...PROVIDERS.map(p => p.id.length)); + const maxLabel = Math.max(...PROVIDERS.map(p => p.label.length)); + for (const p of PROVIDERS) { + const detected = detectMatch(p.detect); + const status = p.soft && !detected + ? c.dim('soft (--only ' + p.id + ')') + : detected + ? c.green('✓ detected') + : c.dim('not found'); + const soft = p.soft ? c.dim(' [soft]') : ''; + process.stdout.write( + ` ${p.id.padEnd(maxId + 2)}${p.label.padEnd(maxLabel + 2)}${status}${soft}\n` + ); + } + process.stdout.write('\n'); +} + +// ── Uninstall ───────────────────────────────────────────────────────────── + +function uninstall(opts, c) { + process.stdout.write('codeforerunner — uninstalling\n\n'); + const targets = opts.only.length ? opts.only : ['claude']; + for (const id of targets) { + if (id === 'claude') { + process.stdout.write(`${c.bold('→ Claude Code')}\n`); + runSpawn('claude', ['plugin', 'uninstall', 'codeforerunner'], opts.dryRun, c); + } else { + process.stdout.write(` ${c.yellow('warn:')} uninstall for ${id} not yet automated — remove manually\n`); + } + } + process.stdout.write('\ndone\n'); +} + +// ── Summary ─────────────────────────────────────────────────────────────── + +function printSummary(results, c) { + process.stdout.write('\n─────────────────────────────────\n'); + if (results.installed.length) { + process.stdout.write(c.green(`✓ installed: ${results.installed.join(', ')}\n`)); + } + if (results.skipped.length) { + const ids = results.skipped.map(s => `${s.id} (${s.why})`).join(', '); + process.stdout.write(c.yellow(`– skipped: ${ids}\n`)); + } + if (results.failed.length) { + const ids = results.failed.map(s => `${s.id} (${s.why})`).join(', '); + process.stdout.write(c.red(`✗ failed: ${ids}\n`)); + } + if (!results.installed.length && !results.skipped.length && !results.failed.length) { + process.stdout.write(c.yellow('no agents detected\n')); + process.stdout.write(c.dim(' use --list to see all supported agents\n')); + process.stdout.write(c.dim(' use --only to install for a specific agent\n')); + } + process.stdout.write('\n'); + process.stdout.write(c.dim(` docs: https://github.com/${REPO}\n`)); + process.stdout.write(c.dim(' to configure drift rules: forerunner doctor --fix\n')); +} + +// ── Main ────────────────────────────────────────────────────────────────── + +function main() { + const opts = parseArgs(process.argv.slice(2)); + const c = makeChalk(opts.noColor); + + if (opts.help) { printHelp(); return; } + if (opts.listOnly) { printList(c); return; } + if (opts.uninstall){ uninstall(opts,c); return; } + + const results = { detected: 0, installed: [], skipped: [], failed: [] }; + + process.stdout.write(c.bold('codeforerunner') + c.dim(' — installing skills into detected agents\n')); + if (opts.dryRun) process.stdout.write(c.yellow(' (dry-run — no files written)\n')); + + for (const prov of PROVIDERS) { + // soft providers only install when explicitly requested via --only + if (prov.soft && !opts.only.includes(prov.id)) continue; + // --only filter + if (opts.only.length && !opts.only.includes(prov.id)) continue; + + const detected = detectMatch(prov.detect); + if (!detected) continue; + + if (opts.skipSkills && prov.profile) continue; + + if (prov.id === 'claude') { installClaude(opts, results, c); continue; } + if (prov.id === 'gemini') { installGemini(opts, results, c); continue; } + if (prov.profile) { installViaSkills(prov, opts, results, c); continue; } + } + + printSummary(results, c); + if (results.failed.length) process.exit(1); +} + +main(); diff --git a/bin/package.json b/bin/package.json new file mode 100644 index 0000000..a3c15a7 --- /dev/null +++ b/bin/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..73e9f63 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,23 @@ +# codeforerunner skill installer — thin Node.js shim (Windows PowerShell). +# Delegates to bin\install.js when run from a local clone, +# or fetches and runs it via npx from a remote invocation. +# +# Usage (local clone): +# .\install.ps1 [flags] +# +# All flags (--dry-run, --force, --only, --all, --minimal, --list, --no-color, +# --skip-skills, --uninstall, -h/--help) are forwarded to bin\install.js. + +param([Parameter(ValueFromRemainingArguments=$true)][string[]]$Args) + +$ErrorActionPreference = "Stop" + +$Repo = "derek-palmer/codeforerunner" +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$LocalJs = Join-Path $ScriptDir "bin\install.js" + +if (Test-Path $LocalJs) { + & node $LocalJs @Args +} else { + & npx -y "github:$Repo" -- @Args +} diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..98bce7f --- /dev/null +++ b/install.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# codeforerunner skill installer — thin Node.js shim. +# Delegates to bin/install.js when run from a local clone, +# or fetches and runs it via npx from a curl|bash one-liner. +# +# Usage (local clone): +# ./install.sh [flags] +# +# One-liner: +# curl -fsSL https://raw.githubusercontent.com/derek-palmer/codeforerunner/main/install.sh | bash +# +# All flags (--dry-run, --force, --only, --all, --minimal, --list, --no-color, +# --skip-skills, --uninstall, -h/--help) are forwarded to bin/install.js. + +set -euo pipefail + +REPO="derek-palmer/codeforerunner" + +# Locate bin/install.js relative to this script (works even when piped through bash) +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-install.sh}")" 2>/dev/null && pwd || echo "")" +LOCAL_JS="${SCRIPT_DIR}/bin/install.js" + +if [[ -n "$SCRIPT_DIR" && -f "$LOCAL_JS" ]]; then + exec node "$LOCAL_JS" "$@" +else + exec npx -y "github:${REPO}" -- "$@" +fi diff --git a/plugins/codeforerunner/skills/forerunner-api-docs/SKILL.md b/plugins/codeforerunner/skills/forerunner-api-docs/SKILL.md new file mode 100644 index 0000000..1638ffc --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-api-docs/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-api-docs +description: Generate endpoint-level API documentation from route and handler files. Use when the user wants to document a public API or REST endpoints. +--- + +# forerunner-api-docs + +Generates API reference documentation at the endpoint level. Requires scan result and all route/handler files in context. + +## Activate when + +User asks to: document the API, generate API reference, write endpoint docs, create OpenAPI-style documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- All route/handler files (every file the scan identified as an API entry point) +- Middleware files +- Auth and validation logic (for request/response shapes) +- Existing API docs (when updating) + +## Execute + +Run `forerunner doc api-docs` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/api-docs.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +Structured API reference covering: endpoint list, HTTP method, path, auth requirement, request parameters/body, response shape, status codes. Write to `docs/api.md` or return as Markdown. Append `## Gaps` for endpoints without sufficient source evidence. diff --git a/plugins/codeforerunner/skills/forerunner-audit/SKILL.md b/plugins/codeforerunner/skills/forerunner-audit/SKILL.md new file mode 100644 index 0000000..1018286 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-audit/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-audit +description: Run a security and dependency audit against a repository. Use when the user wants a security review, dependency vulnerability check, or supply-chain audit. +--- + +# forerunner-audit + +Produces a structured security and dependency audit report. Covers known vulnerability patterns, dependency hygiene, secret exposure risks, and supply-chain concerns. + +## Activate when + +User asks to: audit the repo, run a security check, check for vulnerabilities, review dependencies for security issues. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- All manifest and lockfiles: `package.json`, `package-lock.json`, `yarn.lock`, `pyproject.toml`, `poetry.lock`, `requirements*.txt`, `go.mod`, `go.sum`, `Cargo.toml`, `Cargo.lock`, `Gemfile.lock` +- CI/CD workflow files +- Dockerfile and compose files +- `.env.example` or similar (never actual secret files) + +## Execute + +Run `forerunner doc audit` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/audit.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Structured audit report covering: outdated/vulnerable dependencies, hardcoded secrets risk surface, CI security posture, supply-chain exposure. Severity-tagged findings (HIGH / MEDIUM / LOW). Write to `docs/audit.md` or return as Markdown. diff --git a/plugins/codeforerunner/skills/forerunner-changelog/SKILL.md b/plugins/codeforerunner/skills/forerunner-changelog/SKILL.md new file mode 100644 index 0000000..d684611 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-changelog/SKILL.md @@ -0,0 +1,31 @@ +--- +name: forerunner-changelog +description: Generate a Keep-a-Changelog entry from git history since the last release tag. Use when the user wants to write a CHANGELOG entry or document what changed in a release. +--- + +# forerunner-changelog + +Produces a Keep-a-Changelog–style entry for changes since the last release tag. Does not require a full scan — operates on git log and diff output. + +## Activate when + +User asks to: write the changelog, generate a changelog entry, document the release, write what changed since vX.Y.Z. + +## Collect this context + +- `git log v...HEAD --oneline` output +- `git diff v...HEAD --stat` output +- (Optional) recent commit messages with full bodies for context +- (Optional) existing `CHANGELOG.md` for format reference + +## Execute + +Run `forerunner doc changelog` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/changelog.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +A formatted `## [X.Y.Z] — YYYY-MM-DD` section with `### Added`, `### Changed`, `### Fixed`, `### Removed` subsections. Infer the version from the tag pattern if not specified. Suitable for direct insertion into `CHANGELOG.md`. diff --git a/plugins/codeforerunner/skills/forerunner-check/SKILL.md b/plugins/codeforerunner/skills/forerunner-check/SKILL.md new file mode 100644 index 0000000..3fff0bf --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-check/SKILL.md @@ -0,0 +1,37 @@ +--- +name: forerunner-check +description: Check whether existing documentation is stale relative to the current codebase. Use when the user wants to detect doc drift before a commit, PR, or release. +--- + +# forerunner-check + +Evaluates documentation staleness against a fresh scan. Classifies each doc section as CURRENT, STALE, MISSING, or UNVERIFIABLE. Designed for pre-commit hooks, CI gates, and on-demand runs. + +## Activate when + +User asks to: check docs, detect stale documentation, verify README accuracy, find doc drift, validate docs before a PR/release. Also triggers when `forerunner check` exits non-zero. + +## Collect this context + +- Scan result — run fresh, not cached (run `/forerunner-scan` first) +- Existing documentation files: `README.md`, `docs/*.md` +- `.forerunner/state.json` (last-run checksums, if present) +- Git diff of changed files (for pre-commit mode) + +## Execute + +Run `forerunner doc check` to compose the full prompt with system rules, then execute it. + +Without CLI, also available as `forerunner check` (automated rule-based drift detection using `forerunner.config.yaml`). + +Get the manual-agent prompt from: +- `src/codeforerunner/prompts/tasks/check.md` +- `src/codeforerunner/prompts/system/base.md` + +## What to check + +README accuracy · API docs accuracy · Diagram accuracy · Version audit currency (stale after 30 days) · Undocumented new modules · Docs referencing removed files + +## Output + +Staleness report with file-level classification. STALE findings include specific mismatch descriptions. Write to stdout or `.forerunner/check-report.md`. Exit non-zero when STALE or MISSING findings exceed threshold. diff --git a/plugins/codeforerunner/skills/forerunner-diagrams/SKILL.md b/plugins/codeforerunner/skills/forerunner-diagrams/SKILL.md new file mode 100644 index 0000000..39c5ab6 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-diagrams/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-diagrams +description: Generate Mermaid architecture and flow diagrams from a repository's structure. Use when the user wants architecture diagrams, component diagrams, or visual documentation. +--- + +# forerunner-diagrams + +Generates Mermaid diagrams: one master architecture overview plus focused section diagrams for key subsystems. All diagrams grounded in scan evidence. + +## Activate when + +User asks to: generate diagrams, create architecture diagrams, visualize the system, draw component relationships, produce a Mermaid diagram. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Entry-point files (up to 5) +- Key module and interface files identified in the scan +- Existing `docs/diagrams.md` (when updating) + +## Execute + +Run `forerunner doc diagrams` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/diagrams.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +`docs/diagrams.md` containing fenced Mermaid code blocks: one top-level architecture diagram + one focused diagram per major subsystem detected. Each diagram preceded by a short prose caption. Never invent components not present in the provided files. diff --git a/plugins/codeforerunner/skills/forerunner-flows/SKILL.md b/plugins/codeforerunner/skills/forerunner-flows/SKILL.md new file mode 100644 index 0000000..0332e32 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-flows/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-flows +description: Generate narrative flow documentation for key system paths. Use when the user wants to document how data, requests, or jobs move through the system. +--- + +# forerunner-flows + +Generates prose documentation for key system flows: request/response cycles, data pipelines, background jobs, user journeys, and integration paths. Complements diagrams with narrative explanation. + +## Activate when + +User asks to: document flows, describe how the system works end-to-end, explain data flow, document request lifecycle, write flow documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Entry-point and routing files +- Key middleware and service layer files +- Background job or queue handler files (if detected) +- External integration clients (if detected) + +## Execute + +Run `forerunner doc flows` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/flows.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +`docs/flows.md` with one section per major flow. Each section: flow name, narrative description, step-by-step trace (actor → component → component), and a Mermaid sequence or flowchart diagram. Append `## Gaps` for flows with insufficient source evidence. diff --git a/plugins/codeforerunner/skills/forerunner-init/SKILL.md b/plugins/codeforerunner/skills/forerunner-init/SKILL.md new file mode 100644 index 0000000..bd26bae --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-init/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-init +description: Bootstrap or refresh AGENTS.md and per-agent instruction overlays from repo evidence. Use when the user wants to create or update onboarding instructions for coding agents. +--- + +# forerunner-init + +Generates or updates `AGENTS.md` (and per-agent overlays like `CLAUDE.md`, `GEMINI.md`, `.cursor/rules/`) from direct inspection of the repo. No scan required — derives everything from file tree evidence. + +## Activate when + +User asks to: create AGENTS.md, update agent onboarding, refresh coding agent instructions, generate CLAUDE.md, set up agent configuration for this repo. + +## Collect this context + +- Full file tree (respecting `.gitignore`) +- Root manifests and lockfiles +- Entry-point files +- Existing `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.cursor/rules/` (when updating) +- Build and test commands +- CI configuration + +## Execute + +Run `forerunner init` (or `forerunner doc init-agent-onboarding`) to compose the full prompt, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/init-agent-onboarding.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +`AGENTS.md` at repo root with: project overview, build/test commands, repo structure, agent-specific guidance. Optionally produces per-agent overlays. Minimal diff when updating existing files. diff --git a/plugins/codeforerunner/skills/forerunner-readme/SKILL.md b/plugins/codeforerunner/skills/forerunner-readme/SKILL.md new file mode 100644 index 0000000..9baf919 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-readme/SKILL.md @@ -0,0 +1,39 @@ +--- +name: forerunner-readme +description: Generate or rewrite README.md from a repository's actual code. Use when the user wants to create, refresh, or update the README. +--- + +# forerunner-readme + +Generates or rewrites the top-level `README.md` from verified repo evidence. Every claim must be grounded in provided files — no placeholder text, no invented content. + +## Activate when + +User asks to: generate a README, write the README, refresh or update README.md, create project documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Existing `README.md` (when updating) +- Entry-point files (up to 5) +- Key module files (up to 10) +- Build and test configuration + +## Execute + +Run `forerunner doc readme` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/readme.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Required sections + +Title + one-line description · Stack table · Prerequisites · Setup (copy-pasteable) · Configuration (env vars table) · Usage · Project structure (file tree snippet) + +**Conditional:** Testing (if test framework detected) · Deployment (if CI/CD present) · Architecture (link to diagrams.md if exists) · Contributing (if open-source) + +## Output + +Write `README.md` to repo root. For existing files, produce a minimal reviewable diff. Append `## Gaps` for anything unverifiable. diff --git a/plugins/codeforerunner/skills/forerunner-review/SKILL.md b/plugins/codeforerunner/skills/forerunner-review/SKILL.md new file mode 100644 index 0000000..25d3dc4 --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-review/SKILL.md @@ -0,0 +1,30 @@ +--- +name: forerunner-review +description: Summarize documentation impact of pending changes for reviewer approval. Use when the user wants a doc-impact review before merging a PR. +--- + +# forerunner-review + +Produces a human-readable summary of documentation impact for a pending change. Tells reviewers: which docs are affected, what's now stale, what needs updating before merge. + +## Activate when + +User asks to: review docs impact, summarize documentation changes, check what docs need updating for this PR, generate a doc review summary. + +## Collect this context + +- Check report from `.forerunner/check-report.md` (or run `/forerunner-check` first) +- Git diff of staged or PR files (`git diff --staged` or `git diff main...HEAD`) +- Existing documentation files affected by the diff + +## Execute + +Run `forerunner doc review` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/review.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Review summary with: list of affected docs, staleness classification per doc, recommended actions (update / skip / flag for later), and an overall merge-readiness verdict. Formatted for inclusion in a PR description or review comment. diff --git a/plugins/codeforerunner/skills/forerunner-scan/SKILL.md b/plugins/codeforerunner/skills/forerunner-scan/SKILL.md new file mode 100644 index 0000000..1877fad --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-scan/SKILL.md @@ -0,0 +1,37 @@ +--- +name: forerunner-scan +description: Scan a repository to collect structured evidence for documentation tasks. Always run this first — all other forerunner tasks depend on its output. +--- + +# forerunner-scan + +First task in every codeforerunner workflow. Produces a structured YAML scan result that all downstream tasks consume as input. + +## Activate when + +User asks to: scan a repo, analyze the codebase before generating docs, collect repo evidence, or run any forerunner task that says "requires scan result." + +## Collect this context + +- Full file tree (respecting `.gitignore`) +- Root manifests and lockfiles: `package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`, `requirements*.txt`, and matching lockfiles +- Entry-point files (up to 5) +- Build, test, lint, CI configuration files +- `forerunner.config.yaml` if present + +## Execute + +Run `forerunner doc scan` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/scan.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/context-format.md` + +## Output + +A YAML-structured scan result containing: detected stack, runtime versions, entry points, key module catalog, config file inventory, and test framework. Save as `.forerunner/scan.yaml` or pass inline to the next task. + +## Important + +Never skip this step for readme, api-docs, diagrams, flows, stack-docs, check, audit, or version-audit tasks. Only `changelog` and `init` can run without a prior scan. diff --git a/plugins/codeforerunner/skills/forerunner-stack-docs/SKILL.md b/plugins/codeforerunner/skills/forerunner-stack-docs/SKILL.md new file mode 100644 index 0000000..01ce43f --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-stack-docs/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-stack-docs +description: Generate stack-specific developer documentation. Use when the user wants deep technical docs for a specific part of the stack — database schema, service interfaces, configuration reference, etc. +--- + +# forerunner-stack-docs + +Generates developer documentation tailored to the detected stack. Template selected based on scan result: backend API, frontend SPA, CLI tool, data pipeline, ML service, etc. + +## Activate when + +User asks to: generate developer docs, document the stack, write technical documentation, create a developer guide, document the database schema / service layer / config reference. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Key module files for the detected stack (schema files, service interfaces, config loaders, handler files) +- Type definitions or interface files +- Configuration documentation (env vars, config schemas) + +## Execute + +Run `forerunner doc stack-docs` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/stack-docs.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/stack-hints.md` + +## Output + +Stack-specific `docs/stack.md` covering: architecture decisions, key interfaces, configuration reference, data model, extension points. Format and depth matched to detected stack type. Append `## Gaps` for areas with insufficient source evidence. diff --git a/plugins/codeforerunner/skills/forerunner-version-audit/SKILL.md b/plugins/codeforerunner/skills/forerunner-version-audit/SKILL.md new file mode 100644 index 0000000..e87bc5d --- /dev/null +++ b/plugins/codeforerunner/skills/forerunner-version-audit/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-version-audit +description: Audit all pinned runtime versions, base images, and key dependencies against end-of-life data. Use when the user wants to check for outdated or EOL software versions. +--- + +# forerunner-version-audit + +Scans every pinned version in the repository — runtimes, base images, language versions, container versions, key dependencies — and cross-references against end-of-life data from https://endoflife.date. + +## Activate when + +User asks to: audit versions, check for EOL software, find outdated dependencies, run a version audit, check if anything is past end-of-life. + +## Collect this context + +- All manifest and lockfiles: `package.json`, `package-lock.json`, `pyproject.toml`, `poetry.lock`, `go.mod`, `go.sum`, `Cargo.toml`, `Cargo.lock`, `requirements*.txt` +- `Dockerfile` and `docker-compose.yml` +- CI/CD workflow files (`.github/workflows/*.yml`, etc.) +- IaC files (Terraform, Pulumi, etc.) +- `.tool-versions`, `.nvmrc`, `.python-version`, `.ruby-version` + +## Execute + +Run `forerunner doc version-audit` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/version-audit.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Version audit report: table of all detected versions with columns Version | Status | EOL Date | Latest | Notes. Severity-tagged findings (EOL = HIGH, approaching EOL within 6 months = MEDIUM, current = OK). Write to `docs/version-audit.md`. Re-run monthly — `forerunner check` flags this as stale after 30 days. diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000..824734c --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,83 @@ +{ + "version": 1, + "skills": { + "codeforerunner": { + "source": "plugins/codeforerunner/skills/codeforerunner/SKILL.md", + "sourceType": "local", + "skillPath": "skills/codeforerunner/SKILL.md", + "computedHash": "6ad73a8da10842b0ae9e642eabf91805dad295d825ae95bab1f663af829adb0d" + }, + "forerunner-scan": { + "source": "plugins/codeforerunner/skills/forerunner-scan/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-scan/SKILL.md", + "computedHash": "3d7b0fe2ba54ade4b629751e227fd871f3215c0c69fd15fd5c588dc900fd1569" + }, + "forerunner-readme": { + "source": "plugins/codeforerunner/skills/forerunner-readme/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-readme/SKILL.md", + "computedHash": "1c3e6c6ae9759c0dab6475a2f3f62cf12bce02dc9b6d4733951d3ffa47161a5d" + }, + "forerunner-api-docs": { + "source": "plugins/codeforerunner/skills/forerunner-api-docs/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-api-docs/SKILL.md", + "computedHash": "9cb7636fe715e7b3024273f5dfe064fa57a35b09e1016b5692c68cdd9f7a9d43" + }, + "forerunner-audit": { + "source": "plugins/codeforerunner/skills/forerunner-audit/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-audit/SKILL.md", + "computedHash": "cebb2b1c15b824994a8e0f6e9f51b682f9041641d9c1c189d8b1be173938a0fe" + }, + "forerunner-changelog": { + "source": "plugins/codeforerunner/skills/forerunner-changelog/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-changelog/SKILL.md", + "computedHash": "e622f4563243207c277088b2f35b66df02d7218893e7253b77f821dafc9ccdbd" + }, + "forerunner-check": { + "source": "plugins/codeforerunner/skills/forerunner-check/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-check/SKILL.md", + "computedHash": "a5f03599888640a90a71c2cec20418d9be39301fb5fa59f938feb01dec30149d" + }, + "forerunner-diagrams": { + "source": "plugins/codeforerunner/skills/forerunner-diagrams/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-diagrams/SKILL.md", + "computedHash": "4040c91cb7c6c2646b1ee7f29d536881329db4dc212294905d52755bc4b9a07d" + }, + "forerunner-flows": { + "source": "plugins/codeforerunner/skills/forerunner-flows/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-flows/SKILL.md", + "computedHash": "d7f01af2f125304a3b58e502ff106927f2ea0ebab95f05a92e87e4149b35d00d" + }, + "forerunner-init": { + "source": "plugins/codeforerunner/skills/forerunner-init/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-init/SKILL.md", + "computedHash": "1a6122cb77f8ce7c68b6e189374e5e69179de7ec3682a39c24051243acd02ae3" + }, + "forerunner-review": { + "source": "plugins/codeforerunner/skills/forerunner-review/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-review/SKILL.md", + "computedHash": "0d24cfbcc77c5d82509c2d701c73ce2c61a99ec61000b36ac22224f6976037a9" + }, + "forerunner-stack-docs": { + "source": "plugins/codeforerunner/skills/forerunner-stack-docs/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-stack-docs/SKILL.md", + "computedHash": "1f608dbbd98da240beac45679fd456990626454d79ec7bfb9b56df049b6479c5" + }, + "forerunner-version-audit": { + "source": "plugins/codeforerunner/skills/forerunner-version-audit/SKILL.md", + "sourceType": "local", + "skillPath": "skills/forerunner-version-audit/SKILL.md", + "computedHash": "17d9367e2e3608b9a9fde05730a4199cb1674a1e4529aaf53364c02b76e5149a" + } + } +} diff --git a/skills/forerunner-api-docs/SKILL.md b/skills/forerunner-api-docs/SKILL.md new file mode 100644 index 0000000..1638ffc --- /dev/null +++ b/skills/forerunner-api-docs/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-api-docs +description: Generate endpoint-level API documentation from route and handler files. Use when the user wants to document a public API or REST endpoints. +--- + +# forerunner-api-docs + +Generates API reference documentation at the endpoint level. Requires scan result and all route/handler files in context. + +## Activate when + +User asks to: document the API, generate API reference, write endpoint docs, create OpenAPI-style documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- All route/handler files (every file the scan identified as an API entry point) +- Middleware files +- Auth and validation logic (for request/response shapes) +- Existing API docs (when updating) + +## Execute + +Run `forerunner doc api-docs` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/api-docs.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +Structured API reference covering: endpoint list, HTTP method, path, auth requirement, request parameters/body, response shape, status codes. Write to `docs/api.md` or return as Markdown. Append `## Gaps` for endpoints without sufficient source evidence. diff --git a/skills/forerunner-audit/SKILL.md b/skills/forerunner-audit/SKILL.md new file mode 100644 index 0000000..1018286 --- /dev/null +++ b/skills/forerunner-audit/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-audit +description: Run a security and dependency audit against a repository. Use when the user wants a security review, dependency vulnerability check, or supply-chain audit. +--- + +# forerunner-audit + +Produces a structured security and dependency audit report. Covers known vulnerability patterns, dependency hygiene, secret exposure risks, and supply-chain concerns. + +## Activate when + +User asks to: audit the repo, run a security check, check for vulnerabilities, review dependencies for security issues. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- All manifest and lockfiles: `package.json`, `package-lock.json`, `yarn.lock`, `pyproject.toml`, `poetry.lock`, `requirements*.txt`, `go.mod`, `go.sum`, `Cargo.toml`, `Cargo.lock`, `Gemfile.lock` +- CI/CD workflow files +- Dockerfile and compose files +- `.env.example` or similar (never actual secret files) + +## Execute + +Run `forerunner doc audit` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/audit.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Structured audit report covering: outdated/vulnerable dependencies, hardcoded secrets risk surface, CI security posture, supply-chain exposure. Severity-tagged findings (HIGH / MEDIUM / LOW). Write to `docs/audit.md` or return as Markdown. diff --git a/skills/forerunner-changelog/SKILL.md b/skills/forerunner-changelog/SKILL.md new file mode 100644 index 0000000..d684611 --- /dev/null +++ b/skills/forerunner-changelog/SKILL.md @@ -0,0 +1,31 @@ +--- +name: forerunner-changelog +description: Generate a Keep-a-Changelog entry from git history since the last release tag. Use when the user wants to write a CHANGELOG entry or document what changed in a release. +--- + +# forerunner-changelog + +Produces a Keep-a-Changelog–style entry for changes since the last release tag. Does not require a full scan — operates on git log and diff output. + +## Activate when + +User asks to: write the changelog, generate a changelog entry, document the release, write what changed since vX.Y.Z. + +## Collect this context + +- `git log v...HEAD --oneline` output +- `git diff v...HEAD --stat` output +- (Optional) recent commit messages with full bodies for context +- (Optional) existing `CHANGELOG.md` for format reference + +## Execute + +Run `forerunner doc changelog` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/changelog.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +A formatted `## [X.Y.Z] — YYYY-MM-DD` section with `### Added`, `### Changed`, `### Fixed`, `### Removed` subsections. Infer the version from the tag pattern if not specified. Suitable for direct insertion into `CHANGELOG.md`. diff --git a/skills/forerunner-check/SKILL.md b/skills/forerunner-check/SKILL.md new file mode 100644 index 0000000..3fff0bf --- /dev/null +++ b/skills/forerunner-check/SKILL.md @@ -0,0 +1,37 @@ +--- +name: forerunner-check +description: Check whether existing documentation is stale relative to the current codebase. Use when the user wants to detect doc drift before a commit, PR, or release. +--- + +# forerunner-check + +Evaluates documentation staleness against a fresh scan. Classifies each doc section as CURRENT, STALE, MISSING, or UNVERIFIABLE. Designed for pre-commit hooks, CI gates, and on-demand runs. + +## Activate when + +User asks to: check docs, detect stale documentation, verify README accuracy, find doc drift, validate docs before a PR/release. Also triggers when `forerunner check` exits non-zero. + +## Collect this context + +- Scan result — run fresh, not cached (run `/forerunner-scan` first) +- Existing documentation files: `README.md`, `docs/*.md` +- `.forerunner/state.json` (last-run checksums, if present) +- Git diff of changed files (for pre-commit mode) + +## Execute + +Run `forerunner doc check` to compose the full prompt with system rules, then execute it. + +Without CLI, also available as `forerunner check` (automated rule-based drift detection using `forerunner.config.yaml`). + +Get the manual-agent prompt from: +- `src/codeforerunner/prompts/tasks/check.md` +- `src/codeforerunner/prompts/system/base.md` + +## What to check + +README accuracy · API docs accuracy · Diagram accuracy · Version audit currency (stale after 30 days) · Undocumented new modules · Docs referencing removed files + +## Output + +Staleness report with file-level classification. STALE findings include specific mismatch descriptions. Write to stdout or `.forerunner/check-report.md`. Exit non-zero when STALE or MISSING findings exceed threshold. diff --git a/skills/forerunner-diagrams/SKILL.md b/skills/forerunner-diagrams/SKILL.md new file mode 100644 index 0000000..39c5ab6 --- /dev/null +++ b/skills/forerunner-diagrams/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-diagrams +description: Generate Mermaid architecture and flow diagrams from a repository's structure. Use when the user wants architecture diagrams, component diagrams, or visual documentation. +--- + +# forerunner-diagrams + +Generates Mermaid diagrams: one master architecture overview plus focused section diagrams for key subsystems. All diagrams grounded in scan evidence. + +## Activate when + +User asks to: generate diagrams, create architecture diagrams, visualize the system, draw component relationships, produce a Mermaid diagram. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Entry-point files (up to 5) +- Key module and interface files identified in the scan +- Existing `docs/diagrams.md` (when updating) + +## Execute + +Run `forerunner doc diagrams` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/diagrams.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +`docs/diagrams.md` containing fenced Mermaid code blocks: one top-level architecture diagram + one focused diagram per major subsystem detected. Each diagram preceded by a short prose caption. Never invent components not present in the provided files. diff --git a/skills/forerunner-flows/SKILL.md b/skills/forerunner-flows/SKILL.md new file mode 100644 index 0000000..0332e32 --- /dev/null +++ b/skills/forerunner-flows/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-flows +description: Generate narrative flow documentation for key system paths. Use when the user wants to document how data, requests, or jobs move through the system. +--- + +# forerunner-flows + +Generates prose documentation for key system flows: request/response cycles, data pipelines, background jobs, user journeys, and integration paths. Complements diagrams with narrative explanation. + +## Activate when + +User asks to: document flows, describe how the system works end-to-end, explain data flow, document request lifecycle, write flow documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Entry-point and routing files +- Key middleware and service layer files +- Background job or queue handler files (if detected) +- External integration clients (if detected) + +## Execute + +Run `forerunner doc flows` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/flows.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Output + +`docs/flows.md` with one section per major flow. Each section: flow name, narrative description, step-by-step trace (actor → component → component), and a Mermaid sequence or flowchart diagram. Append `## Gaps` for flows with insufficient source evidence. diff --git a/skills/forerunner-init/SKILL.md b/skills/forerunner-init/SKILL.md new file mode 100644 index 0000000..bd26bae --- /dev/null +++ b/skills/forerunner-init/SKILL.md @@ -0,0 +1,33 @@ +--- +name: forerunner-init +description: Bootstrap or refresh AGENTS.md and per-agent instruction overlays from repo evidence. Use when the user wants to create or update onboarding instructions for coding agents. +--- + +# forerunner-init + +Generates or updates `AGENTS.md` (and per-agent overlays like `CLAUDE.md`, `GEMINI.md`, `.cursor/rules/`) from direct inspection of the repo. No scan required — derives everything from file tree evidence. + +## Activate when + +User asks to: create AGENTS.md, update agent onboarding, refresh coding agent instructions, generate CLAUDE.md, set up agent configuration for this repo. + +## Collect this context + +- Full file tree (respecting `.gitignore`) +- Root manifests and lockfiles +- Entry-point files +- Existing `AGENTS.md`, `CLAUDE.md`, `GEMINI.md`, `.cursor/rules/` (when updating) +- Build and test commands +- CI configuration + +## Execute + +Run `forerunner init` (or `forerunner doc init-agent-onboarding`) to compose the full prompt, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/init-agent-onboarding.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +`AGENTS.md` at repo root with: project overview, build/test commands, repo structure, agent-specific guidance. Optionally produces per-agent overlays. Minimal diff when updating existing files. diff --git a/skills/forerunner-readme/SKILL.md b/skills/forerunner-readme/SKILL.md new file mode 100644 index 0000000..9baf919 --- /dev/null +++ b/skills/forerunner-readme/SKILL.md @@ -0,0 +1,39 @@ +--- +name: forerunner-readme +description: Generate or rewrite README.md from a repository's actual code. Use when the user wants to create, refresh, or update the README. +--- + +# forerunner-readme + +Generates or rewrites the top-level `README.md` from verified repo evidence. Every claim must be grounded in provided files — no placeholder text, no invented content. + +## Activate when + +User asks to: generate a README, write the README, refresh or update README.md, create project documentation. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Existing `README.md` (when updating) +- Entry-point files (up to 5) +- Key module files (up to 10) +- Build and test configuration + +## Execute + +Run `forerunner doc readme` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/readme.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/output-rules.md` + +## Required sections + +Title + one-line description · Stack table · Prerequisites · Setup (copy-pasteable) · Configuration (env vars table) · Usage · Project structure (file tree snippet) + +**Conditional:** Testing (if test framework detected) · Deployment (if CI/CD present) · Architecture (link to diagrams.md if exists) · Contributing (if open-source) + +## Output + +Write `README.md` to repo root. For existing files, produce a minimal reviewable diff. Append `## Gaps` for anything unverifiable. diff --git a/skills/forerunner-review/SKILL.md b/skills/forerunner-review/SKILL.md new file mode 100644 index 0000000..25d3dc4 --- /dev/null +++ b/skills/forerunner-review/SKILL.md @@ -0,0 +1,30 @@ +--- +name: forerunner-review +description: Summarize documentation impact of pending changes for reviewer approval. Use when the user wants a doc-impact review before merging a PR. +--- + +# forerunner-review + +Produces a human-readable summary of documentation impact for a pending change. Tells reviewers: which docs are affected, what's now stale, what needs updating before merge. + +## Activate when + +User asks to: review docs impact, summarize documentation changes, check what docs need updating for this PR, generate a doc review summary. + +## Collect this context + +- Check report from `.forerunner/check-report.md` (or run `/forerunner-check` first) +- Git diff of staged or PR files (`git diff --staged` or `git diff main...HEAD`) +- Existing documentation files affected by the diff + +## Execute + +Run `forerunner doc review` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/review.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Review summary with: list of affected docs, staleness classification per doc, recommended actions (update / skip / flag for later), and an overall merge-readiness verdict. Formatted for inclusion in a PR description or review comment. diff --git a/skills/forerunner-scan/SKILL.md b/skills/forerunner-scan/SKILL.md new file mode 100644 index 0000000..1877fad --- /dev/null +++ b/skills/forerunner-scan/SKILL.md @@ -0,0 +1,37 @@ +--- +name: forerunner-scan +description: Scan a repository to collect structured evidence for documentation tasks. Always run this first — all other forerunner tasks depend on its output. +--- + +# forerunner-scan + +First task in every codeforerunner workflow. Produces a structured YAML scan result that all downstream tasks consume as input. + +## Activate when + +User asks to: scan a repo, analyze the codebase before generating docs, collect repo evidence, or run any forerunner task that says "requires scan result." + +## Collect this context + +- Full file tree (respecting `.gitignore`) +- Root manifests and lockfiles: `package.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`, `requirements*.txt`, and matching lockfiles +- Entry-point files (up to 5) +- Build, test, lint, CI configuration files +- `forerunner.config.yaml` if present + +## Execute + +Run `forerunner doc scan` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/scan.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/context-format.md` + +## Output + +A YAML-structured scan result containing: detected stack, runtime versions, entry points, key module catalog, config file inventory, and test framework. Save as `.forerunner/scan.yaml` or pass inline to the next task. + +## Important + +Never skip this step for readme, api-docs, diagrams, flows, stack-docs, check, audit, or version-audit tasks. Only `changelog` and `init` can run without a prior scan. diff --git a/skills/forerunner-stack-docs/SKILL.md b/skills/forerunner-stack-docs/SKILL.md new file mode 100644 index 0000000..01ce43f --- /dev/null +++ b/skills/forerunner-stack-docs/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-stack-docs +description: Generate stack-specific developer documentation. Use when the user wants deep technical docs for a specific part of the stack — database schema, service interfaces, configuration reference, etc. +--- + +# forerunner-stack-docs + +Generates developer documentation tailored to the detected stack. Template selected based on scan result: backend API, frontend SPA, CLI tool, data pipeline, ML service, etc. + +## Activate when + +User asks to: generate developer docs, document the stack, write technical documentation, create a developer guide, document the database schema / service layer / config reference. + +## Collect this context + +- Scan result (run `/forerunner-scan` first) +- Key module files for the detected stack (schema files, service interfaces, config loaders, handler files) +- Type definitions or interface files +- Configuration documentation (env vars, config schemas) + +## Execute + +Run `forerunner doc stack-docs` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/stack-docs.md` +- `src/codeforerunner/prompts/system/base.md` +- `src/codeforerunner/prompts/partials/stack-hints.md` + +## Output + +Stack-specific `docs/stack.md` covering: architecture decisions, key interfaces, configuration reference, data model, extension points. Format and depth matched to detected stack type. Append `## Gaps` for areas with insufficient source evidence. diff --git a/skills/forerunner-version-audit/SKILL.md b/skills/forerunner-version-audit/SKILL.md new file mode 100644 index 0000000..e87bc5d --- /dev/null +++ b/skills/forerunner-version-audit/SKILL.md @@ -0,0 +1,32 @@ +--- +name: forerunner-version-audit +description: Audit all pinned runtime versions, base images, and key dependencies against end-of-life data. Use when the user wants to check for outdated or EOL software versions. +--- + +# forerunner-version-audit + +Scans every pinned version in the repository — runtimes, base images, language versions, container versions, key dependencies — and cross-references against end-of-life data from https://endoflife.date. + +## Activate when + +User asks to: audit versions, check for EOL software, find outdated dependencies, run a version audit, check if anything is past end-of-life. + +## Collect this context + +- All manifest and lockfiles: `package.json`, `package-lock.json`, `pyproject.toml`, `poetry.lock`, `go.mod`, `go.sum`, `Cargo.toml`, `Cargo.lock`, `requirements*.txt` +- `Dockerfile` and `docker-compose.yml` +- CI/CD workflow files (`.github/workflows/*.yml`, etc.) +- IaC files (Terraform, Pulumi, etc.) +- `.tool-versions`, `.nvmrc`, `.python-version`, `.ruby-version` + +## Execute + +Run `forerunner doc version-audit` to compose the full prompt with system rules, then execute it. + +Without CLI, get the prompt from: +- `src/codeforerunner/prompts/tasks/version-audit.md` +- `src/codeforerunner/prompts/system/base.md` + +## Output + +Version audit report: table of all detected versions with columns Version | Status | EOL Date | Latest | Notes. Severity-tagged findings (EOL = HIGH, approaching EOL within 6 months = MEDIUM, current = OK). Write to `docs/version-audit.md`. Re-run monthly — `forerunner check` flags this as stale after 30 days. diff --git a/src/codeforerunner/installer.py b/src/codeforerunner/installer.py index b35083e..65cd5c9 100644 --- a/src/codeforerunner/installer.py +++ b/src/codeforerunner/installer.py @@ -21,6 +21,23 @@ EXIT_BODY_MISMATCH = 3 EXIT_UNMANAGED_DEST = 4 +# Per-task skill slugs (source: skills//SKILL.md → plugins/codeforerunner/skills//SKILL.md) +TASK_SKILL_SLUGS: tuple[str, ...] = ( + "codeforerunner", + "forerunner-scan", + "forerunner-readme", + "forerunner-api-docs", + "forerunner-audit", + "forerunner-changelog", + "forerunner-check", + "forerunner-diagrams", + "forerunner-flows", + "forerunner-init", + "forerunner-review", + "forerunner-stack-docs", + "forerunner-version-audit", +) + @dataclass(frozen=True) class Target: @@ -44,9 +61,65 @@ def resolve_target(agent: str, override: Path | None) -> Target: return Target(agent, home / ".codex/skills/codeforerunner/SKILL.md") if agent == "claude": return Target(agent, home / ".claude/plugins/codeforerunner/skills/codeforerunner/SKILL.md") + if agent == "gemini": + raise ValueError( + "gemini install is handled via `gemini extensions install`; " + "run `./install.sh --only gemini` instead" + ) raise ValueError(f"unknown agent '{agent}' (expected: codex, claude, generic)") +def resolve_skill_target(agent: str, slug: str) -> Target: + """Return install target for a per-task skill slug.""" + home = _home() + if agent == "codex": + return Target(agent, home / f".codex/skills/{slug}/SKILL.md") + if agent == "claude": + return Target(agent, home / f".claude/plugins/codeforerunner/skills/{slug}/SKILL.md") + raise ValueError(f"install_all not supported for agent '{agent}' (expected: codex, claude)") + + +def install_all_skills( + *, + agent: str, + repo_root: Path, + check_only: bool, + out=None, + err=None, +) -> int: + """Install all per-task skills for the given agent. Returns 0 on full success.""" + out = out or sys.stdout + err = err or sys.stderr + any_error = False + for slug in TASK_SKILL_SLUGS: + src_path = repo_root / "plugins" / "codeforerunner" / "skills" / slug / "SKILL.md" + if not src_path.is_file(): + print(f"warning: skill source not found: {src_path}", file=err) + continue + try: + target = resolve_skill_target(agent, slug) + except ValueError as e: + print(f"error: {e}", file=err) + return EXIT_USAGE + # For per-task skills use simple copy (no body-parity check against canonical) + dest = target.path + prefix = "would " if check_only else "" + if dest.exists(): + src_trimmed = src_path.read_bytes().rstrip() + dest_trimmed = dest.read_bytes().rstrip() + if src_trimmed == dest_trimmed: + print(f"skip: {dest} (up-to-date)", file=out) + continue + action = "update" + else: + action = "create" + print(f"{prefix}{action}: {dest}", file=out) + if not check_only: + dest.parent.mkdir(parents=True, exist_ok=True) + dest.write_bytes(src_path.read_bytes()) + return EXIT_OK if not any_error else EXIT_BODY_MISMATCH + + def resolve_marketplace_target(agent: str, override: Path | None) -> Target: if agent == "generic": if override is None: @@ -277,8 +350,11 @@ def install( def add_subparser(sub: argparse._SubParsersAction) -> None: - p = sub.add_parser("install", help="install skill into agent-specific directory (D.installer)") - p.add_argument("agent", choices=["codex", "claude", "generic"]) + p = sub.add_parser("install", help="install skill(s) into agent-specific directories (D.installer)") + p.add_argument("agent", choices=["codex", "claude", "generic"], nargs="?", + help="target agent (omit with --all to install to all detected agents)") + p.add_argument("--all", action="store_true", + help="install all per-task skills for the specified agent") p.add_argument("--check", action="store_true", help="dry-run: print plan, write nothing") p.add_argument("--path", type=Path, help="dest path override (required for generic)") p.add_argument("--source", type=Path, help="source skill file (default: agent/codeforerunner.skill.md)") @@ -292,6 +368,19 @@ def add_subparser(sub: argparse._SubParsersAction) -> None: def _cli_entry(args: argparse.Namespace) -> int: root = Path(args.repo).resolve() if args.repo else Path.cwd() + + if getattr(args, "all", False): + agent = args.agent or "claude" + return install_all_skills( + agent=agent, + repo_root=root, + check_only=args.check, + ) + + if not args.agent: + print("error: specify an agent or use --all", file=sys.stderr) + return EXIT_USAGE + return install( agent=args.agent, repo_root=root,