codebase-ai 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/setup.md +120 -6
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/skills/cx-review.skill +0 -0
- package/skills/dx-review.skill +0 -0
- package/skills/expert-panel.skill +0 -0
- package/skills/rust-review.skill +0 -0
- package/skills/security-review.skill +0 -0
- package/skills/self-heal.skill +0 -0
- package/skills/simulate.skill +0 -0
package/commands/setup.md
CHANGED
|
@@ -73,6 +73,120 @@ Print: `codebase manifest: generated`
|
|
|
73
73
|
|
|
74
74
|
---
|
|
75
75
|
|
|
76
|
+
## Step 2b — Project Structure Standardisation
|
|
77
|
+
|
|
78
|
+
Scaffold the standard project structure. **Never overwrite existing files or directories.**
|
|
79
|
+
|
|
80
|
+
For each path, only create if it does not already exist:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# Directories
|
|
84
|
+
mkdir -p docs src/core src/modules src/interfaces tests scripts
|
|
85
|
+
|
|
86
|
+
# README.md — only if missing
|
|
87
|
+
[ -f README.md ] || cat > README.md << 'EOF'
|
|
88
|
+
# [Project Name]
|
|
89
|
+
|
|
90
|
+
[What this project does — 1-2 sentences.]
|
|
91
|
+
|
|
92
|
+
## Getting Started
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# install dependencies
|
|
96
|
+
# run the project
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# build
|
|
103
|
+
# test
|
|
104
|
+
# lint
|
|
105
|
+
```
|
|
106
|
+
EOF
|
|
107
|
+
|
|
108
|
+
# .env.example — only if missing and no .env exists
|
|
109
|
+
[ -f .env.example ] || [ -f .env ] || cat > .env.example << 'EOF'
|
|
110
|
+
# Required environment variables
|
|
111
|
+
# Copy to .env and fill in values
|
|
112
|
+
|
|
113
|
+
# APP_PORT=3000
|
|
114
|
+
# DATABASE_URL=
|
|
115
|
+
# SECRET_KEY=
|
|
116
|
+
EOF
|
|
117
|
+
|
|
118
|
+
# docs/ARCHITECTURE.md — only if missing
|
|
119
|
+
[ -f docs/ARCHITECTURE.md ] || cat > docs/ARCHITECTURE.md << 'EOF'
|
|
120
|
+
# Architecture
|
|
121
|
+
|
|
122
|
+
## System Overview
|
|
123
|
+
|
|
124
|
+
[High-level description of how the system works.]
|
|
125
|
+
|
|
126
|
+
## Key Components
|
|
127
|
+
|
|
128
|
+
| Component | Purpose |
|
|
129
|
+
|---|---|
|
|
130
|
+
| `src/core/` | Business logic |
|
|
131
|
+
| `src/modules/` | Feature modules |
|
|
132
|
+
| `src/interfaces/` | Contracts, APIs, types |
|
|
133
|
+
|
|
134
|
+
## Data Flow
|
|
135
|
+
|
|
136
|
+
[Describe the main request/data flow through the system.]
|
|
137
|
+
|
|
138
|
+
## Key Design Decisions
|
|
139
|
+
|
|
140
|
+
[Document architectural decisions and their rationale here.]
|
|
141
|
+
EOF
|
|
142
|
+
|
|
143
|
+
# docs/IMPLEMENTATION.md — only if missing
|
|
144
|
+
[ -f docs/IMPLEMENTATION.md ] || cat > docs/IMPLEMENTATION.md << 'EOF'
|
|
145
|
+
# Implementation Guide
|
|
146
|
+
|
|
147
|
+
## Code Organisation
|
|
148
|
+
|
|
149
|
+
[How the source code is structured and why.]
|
|
150
|
+
|
|
151
|
+
## Patterns & Conventions
|
|
152
|
+
|
|
153
|
+
[Coding patterns, naming conventions, module rules.]
|
|
154
|
+
|
|
155
|
+
## Adding Features
|
|
156
|
+
|
|
157
|
+
[Step-by-step guide for contributing new functionality.]
|
|
158
|
+
|
|
159
|
+
## Common Tasks
|
|
160
|
+
|
|
161
|
+
[Runbook for frequent development tasks.]
|
|
162
|
+
EOF
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Print a structure report:
|
|
166
|
+
```
|
|
167
|
+
PROJECT STRUCTURE
|
|
168
|
+
══════════════════════════════════════
|
|
169
|
+
docs/ [created | exists]
|
|
170
|
+
ARCHITECTURE.md [created | exists]
|
|
171
|
+
IMPLEMENTATION.md [created | exists]
|
|
172
|
+
PRODUCT.md [pending — Step 6]
|
|
173
|
+
src/core/ [created | exists]
|
|
174
|
+
src/modules/ [created | exists]
|
|
175
|
+
src/interfaces/ [created | exists]
|
|
176
|
+
tests/ [created | exists]
|
|
177
|
+
scripts/ [created | exists]
|
|
178
|
+
README.md [created | exists]
|
|
179
|
+
.env.example [created | exists | skipped — .env present]
|
|
180
|
+
══════════════════════════════════════
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Rules:**
|
|
184
|
+
- Never delete or overwrite anything that already exists
|
|
185
|
+
- If the project has a non-standard structure (e.g. `app/` instead of `src/`), adapt the report but do not force-rename existing dirs
|
|
186
|
+
- Add any newly created paths to the Step 8 commit
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
76
190
|
## Step 3 — GitHub labels
|
|
77
191
|
|
|
78
192
|
```bash
|
|
@@ -150,7 +264,7 @@ fi
|
|
|
150
264
|
|
|
151
265
|
---
|
|
152
266
|
|
|
153
|
-
## Step 6 — PRODUCT.md
|
|
267
|
+
## Step 6 — Docs (PRODUCT.md, ARCHITECTURE.md, IMPLEMENTATION.md)
|
|
154
268
|
|
|
155
269
|
Use `codebase brief` as the primary source of project intelligence:
|
|
156
270
|
|
|
@@ -160,7 +274,7 @@ npx codebase brief 2>/dev/null > /tmp/cb-brief.json || true
|
|
|
160
274
|
|
|
161
275
|
Read the brief. If `docs/PRODUCT.md` exists and `--refresh` not passed: show diff of stale sections, ask user to confirm updates.
|
|
162
276
|
|
|
163
|
-
Otherwise generate `docs/PRODUCT.md` from:
|
|
277
|
+
Otherwise generate `docs/PRODUCT.md` from (note: filename is all-caps `PRODUCT.md`):
|
|
164
278
|
- `project.name`, `project.description` → Summary
|
|
165
279
|
- `stack.languages`, `stack.frameworks`, `commands.*` → Tech Stack (auto-filled)
|
|
166
280
|
- `patterns.architecture`, `patterns.api_style` → Context
|
|
@@ -173,9 +287,9 @@ Mark genuinely unknown sections with `[INFERRED: ...]`.
|
|
|
173
287
|
|
|
174
288
|
---
|
|
175
289
|
|
|
176
|
-
## Step 7 — CLAUDE.md
|
|
290
|
+
## Step 7 — CLAUDE.md (last — reads everything set up above)
|
|
177
291
|
|
|
178
|
-
Write (or update) `CLAUDE.md` for this specific project.
|
|
292
|
+
Write (or update) `CLAUDE.md` for this specific project. At this point all other setup steps are complete — read `.codebase.json`, `docs/PRODUCT.md`, `docs/ARCHITECTURE.md`, `docs/IMPLEMENTATION.md`, and the full project structure before writing, so CLAUDE.md accurately reflects the final state of the project.
|
|
179
293
|
|
|
180
294
|
**If `CLAUDE.md` already exists:** read it first. Preserve any existing sections. Only update the `<!-- codebase:start -->...<!-- codebase:end -->` block and add missing sections without removing human-authored content.
|
|
181
295
|
|
|
@@ -190,7 +304,7 @@ One paragraph describing what the project does, who it's for, and its current st
|
|
|
190
304
|
Exact commands from `.codebase.json` → `commands.*`. Include build, dev, test, lint, typecheck.
|
|
191
305
|
|
|
192
306
|
### Architecture
|
|
193
|
-
How the codebase is structured — key directories, entry points, data flow.
|
|
307
|
+
How the codebase is structured — key directories, entry points, data flow. Pull from `docs/ARCHITECTURE.md` if it was populated, otherwise infer from `structure`, `patterns`, and file scanning. Be specific, not generic.
|
|
194
308
|
|
|
195
309
|
### Key Conventions
|
|
196
310
|
Language/framework conventions detected. Coding patterns observed. Things an AI must know to not break the codebase (e.g. "zero runtime dependencies", "no cross-module state", "all DB calls go through /lib/db").
|
|
@@ -229,7 +343,7 @@ npx codebase init --quiet 2>/dev/null || true
|
|
|
229
343
|
|
|
230
344
|
```bash
|
|
231
345
|
git checkout develop 2>/dev/null || git checkout -b develop
|
|
232
|
-
git add docs/PRODUCT.md CLAUDE.md .vibekit/ .gitignore 2>/dev/null || true
|
|
346
|
+
git add docs/PRODUCT.md docs/ARCHITECTURE.md docs/IMPLEMENTATION.md CLAUDE.md README.md .env.example .vibekit/ .gitignore src/ tests/ scripts/ 2>/dev/null || true
|
|
233
347
|
git diff --cached --quiet || git commit -m "chore: bootstrap codebase + vibekit setup
|
|
234
348
|
|
|
235
349
|
Initialized by /setup"
|
package/dist/index.js
CHANGED
|
@@ -551,7 +551,7 @@ ${w("SEE ALSO")}
|
|
|
551
551
|
`:""}${w("MORE HELP")}
|
|
552
552
|
${$("codebase --help")} Show all commands
|
|
553
553
|
${tt("https://github.com/ZySec-AI/codebase/docs","Full documentation")}
|
|
554
|
-
`)}var Lc={E_NO_GIT:{message:"Not a git repository",suggestion:"Initialize git first: "+$("git init")},E_NO_PACKAGE_JSON:{message:"No package.json found",suggestion:"Initialize project: "+$("npm init")+" or "+$("pnpm init")},E_GH_NOT_AUTHENTICATED:{message:"GitHub CLI not authenticated",suggestion:"Run: "+$("gh auth login")},E_MANIFEST_NOT_FOUND:{message:".codebase.json not found",suggestion:"Run: "+$("codebase init")+" to generate it"},E_INVALID_PATH:{message:"Invalid directory path",suggestion:"Use absolute path or path relative to current directory"},E_PERMISSION_DENIED:{message:"Permission denied",suggestion:"Check file permissions or run with appropriate access"}};var oi={command:"init",subcommand:"",positionals:[],path:process.cwd(),format:"text",depth:4,categories:[],incremental:!1,quiet:!1,force:!1,verbose:!1,port:7432,tools:[],dryRun:!1,since:"",sync:!1,message:"",reason:"",examples:!1,helpCommand:!1},Zt=new Set(["scan","setup","query","mcp","issue","status","init","scan-only","brief","next","doctor","fix","release","plan","skills","serve"]);function es(e){let t={...oi},s=[];for(let n=0;n<e.length;n++){let i=e[n];if(!i.startsWith("-")&&Zt.has(i)){if(t.command=i,e[n+1]==="--help"||e[n+1]==="-h")return t.helpCommand=!0,t;break}}for(let n=0;n<e.length;n++){let i=e[n];if((i==="--help"||i==="-h")&&!t.command&&(Yt(),process.exit(0)),(i==="--version"||i==="-v")&&(console.log("codebase 0.3.
|
|
554
|
+
`)}var Lc={E_NO_GIT:{message:"Not a git repository",suggestion:"Initialize git first: "+$("git init")},E_NO_PACKAGE_JSON:{message:"No package.json found",suggestion:"Initialize project: "+$("npm init")+" or "+$("pnpm init")},E_GH_NOT_AUTHENTICATED:{message:"GitHub CLI not authenticated",suggestion:"Run: "+$("gh auth login")},E_MANIFEST_NOT_FOUND:{message:".codebase.json not found",suggestion:"Run: "+$("codebase init")+" to generate it"},E_INVALID_PATH:{message:"Invalid directory path",suggestion:"Use absolute path or path relative to current directory"},E_PERMISSION_DENIED:{message:"Permission denied",suggestion:"Check file permissions or run with appropriate access"}};var oi={command:"init",subcommand:"",positionals:[],path:process.cwd(),format:"text",depth:4,categories:[],incremental:!1,quiet:!1,force:!1,verbose:!1,port:7432,tools:[],dryRun:!1,since:"",sync:!1,message:"",reason:"",examples:!1,helpCommand:!1},Zt=new Set(["scan","setup","query","mcp","issue","status","init","scan-only","brief","next","doctor","fix","release","plan","skills","serve"]);function es(e){let t={...oi},s=[];for(let n=0;n<e.length;n++){let i=e[n];if(!i.startsWith("-")&&Zt.has(i)){if(t.command=i,e[n+1]==="--help"||e[n+1]==="-h")return t.helpCommand=!0,t;break}}for(let n=0;n<e.length;n++){let i=e[n];if((i==="--help"||i==="-h")&&!t.command&&(Yt(),process.exit(0)),(i==="--version"||i==="-v")&&(console.log("codebase 0.3.1"),process.exit(0)),i.startsWith("--")){let o=i.slice(2);if(o==="quiet"||o==="q"){t.quiet=!0;continue}if(o==="force"){t.force=!0;continue}if(o==="raw"){console.error("Warning: --raw is deprecated, use --force instead"),t.force=!0;continue}if(o==="verbose"||o==="V"){t.verbose=!0;continue}if(o==="incremental"){t.incremental=!0;continue}if(o==="dry-run"){t.dryRun=!0;continue}if(o==="sync"){t.sync=!0;continue}if(o==="examples"){t.examples=!0;continue}if(o==="mine"){s.push("mine");continue}let r=e[n+1];if(!r||r.startsWith("--"))continue;n++,o==="path"?t.path=r:o==="format"?t.format=r:o==="depth"?t.depth=parseInt(r,10)||4:o==="categories"?t.categories=r.split(",").map(a=>a.trim()):o==="port"?t.port=parseInt(r,10)||7432:o==="tools"?t.tools=r.split(",").map(a=>a.trim()):o==="since"?t.since=r:o==="message"||o==="m"?t.message=r:o==="reason"&&(t.reason=r);continue}s.push(i)}if(s.length>0&&Zt.has(s[0])&&(t.command=s.shift()),s.length>0){let n=s[0];["install","uninstall","create","close","comment","list","map"].includes(n)&&(t.subcommand=s.shift())}return t.positionals=s,s.length>0&&/^[\/\.~]/.test(s[0])&&(t.path=s[0]),process.env.CODEBASE_OUTPUT&&(t.path=process.env.CODEBASE_OUTPUT),process.env.CODEBASE_PORT&&(t.port=parseInt(process.env.CODEBASE_PORT,10)||7432),process.env.CODEBASE_DEPTH&&(t.depth=parseInt(process.env.CODEBASE_DEPTH,10)||4),process.env.CODEBASE_QUIET==="true"&&(t.quiet=!0),t}function ts(e){Xt(e),process.exit(0)}M();import{get as ri}from"https";import{readFileSync as jt,writeFileSync as ai,mkdirSync as ci}from"fs";import{homedir as li}from"os";import{join as ss}from"path";import{execSync as st,spawnSync as ui}from"child_process";var ns=ss(li(),".codebase"),is=ss(ns,"update-check.json"),di=1440*60*1e3,me="codebase-ai",we=!!process.env.NO_COLOR,E={yellow:we?"":"\x1B[33m",cyan:we?"":"\x1B[36m",green:we?"":"\x1B[32m",bold:we?"":"\x1B[1m",dim:we?"":"\x1B[2m",reset:we?"":"\x1B[0m"};function pi(){return"0.3.1"}function fi(e,t){let s=l=>l.replace(/^v/,"").split(".").map(Number),[n,i,o]=s(e),[r,a,c]=s(t);return n!==r?n>r:i!==a?i>a:o>c}function mi(){try{return JSON.parse(jt(is,"utf8"))}catch{return null}}function gi(e){try{ci(ns,{recursive:!0}),ai(is,JSON.stringify({version:e,checkedAt:Date.now()}))}catch{}}function hi(){return new Promise((e,t)=>{let s=ri(`https://registry.npmjs.org/${me}/latest`,{headers:{accept:"application/json"}},n=>{let i="";n.on("data",o=>i+=o.toString()),n.on("end",()=>{try{e(JSON.parse(i).version)}catch{t(new Error("parse error"))}})});s.on("error",t),s.setTimeout(3e3,()=>{s.destroy(),t(new Error("timeout"))})})}function bi(){try{let e=st("npm root -g 2>/dev/null",{encoding:"utf8"}).trim();if(e&&jt(`${e}/${me}/package.json`,"utf8"))return`npm install -g ${me}@latest`}catch{}try{st("pnpm --version 2>/dev/null",{encoding:"utf8"});let e=st("pnpm root -g 2>/dev/null",{encoding:"utf8"}).trim();if(e&&jt(`${e}/${me}/package.json`,"utf8"))return`pnpm add -g ${me}@latest`}catch{}try{return st("yarn --version 2>/dev/null",{encoding:"utf8"}),`yarn global add ${me}@latest`}catch{}return`npm install -g ${me}@latest`}function yi(e){let[t,...s]=e.split(" ");return ui(t,s,{stdio:"inherit"}).status===0}function ki(){return new Promise(e=>{let t=process.stdin,s=t.isTTY;s&&t.setRawMode(!0),t.resume(),t.setEncoding("utf8");let n=i=>{s&&t.setRawMode(!1),t.pause(),t.removeListener("data",n),e(i)};t.on("data",n),setTimeout(()=>{s&&t.setRawMode(!1),t.pause(),t.removeListener("data",n),e("n")},1e4)})}async function os(){if(process.env.CI||process.env.NO_UPDATE_CHECK||process.env.CODEBASE_NO_UPDATE_CHECK||!process.stdout.isTTY||!process.stdin.isTTY)return;let e=pi(),t=mi(),s;if(t&&Date.now()-t.checkedAt<di)s=t.version;else try{s=await hi(),gi(s)}catch{return}if(!fi(s,e))return;let n=bi();console.log(`
|
|
555
555
|
${E.yellow}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${E.reset}`),console.log(` ${E.yellow}\u2502${E.reset} ${E.bold}Update available${E.reset} ${E.dim}${e}${E.reset} ${E.yellow}\u2192${E.reset} ${E.bold}${E.cyan}${s}${E.reset}`),console.log(` ${E.yellow}\u2502${E.reset} Press ${E.bold}Y${E.reset} to update now, any other key to skip`),console.log(` ${E.yellow}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${E.reset}`),process.stdout.write(`
|
|
556
556
|
> `);let o=(await ki()).toLowerCase()==="y";if(console.log(o?"Updating\u2026":`Skipped.
|
|
557
557
|
`),!o)return;console.log(`
|
|
@@ -620,7 +620,7 @@ ${w("BACKLOG")} (${t.backlog.length})`);for(let n of t.backlog.slice(0,10))u(`
|
|
|
620
620
|
${w("IN PROGRESS")} (${t.in_progress.length})`);for(let n of t.in_progress.slice(0,10)){let i=n.assignee?` @${n.assignee}`:"";u(` #${n.number} ${n.title}${i}`)}t.in_progress.length>10&&te(` \u2026 and ${t.in_progress.length-10} more`);let s=t.needs_verify??[];if(s.length>0){u(`
|
|
621
621
|
${w("NEEDS VERIFY")} (${s.length})`);for(let n of s.slice(0,10))u(` #${n.number} ${n.title}`);s.length>10&&te(` \u2026 and ${s.length-10} more`)}u(`
|
|
622
622
|
${w("DONE")} (${t.done.length} recent)`);for(let n of t.done.slice(0,5))u(` #${n.number} ${n.title}`);t.done.length>5&&te(` \u2026 and ${t.done.length-5} more`)}function Ra(e){S("Priority Queue");for(let t of e.priorities.slice(0,15)){let s=t.labels.length?` [${t.labels.join(", ")}]`:"",n=t.assignee?` \u2192 @${t.assignee}`:"";u(` #${t.number} ${t.title}${s}${n}`)}}function Pa(e){S("Milestones");for(let t of e.milestones){let s=Aa(t.progress.percent),n=t.due_date?` (due: ${t.due_date.split("T")[0]})`:"";u(`
|
|
623
|
-
${w(t.title)} ${s} ${t.progress.percent}%${n}`),u(` ${t.progress.closed}/${t.progress.open+t.progress.closed} issues closed`)}}function Da(e){S("Decisions");let t=[...e.from_prs.map(s=>({...s,type:"PR"})),...e.from_adrs.map(s=>({...s,type:"ADR"})),...e.manual.map(s=>({...s,type:"Manual"}))].sort((s,n)=>(n.date||"").localeCompare(s.date||""));for(let s of t.slice(0,15))u(` [${s.type}] ${s.title}`),s.summary&&u(` ${s.summary.slice(0,100)}`)}function Aa(e){let t=Math.round(e/5),s=20-t;return`[${"\u2588".repeat(t)}${"\u2591".repeat(s)}]`}import{resolve as Ua}from"path";import{createInterface as Oa}from"readline";import{readFile as Qe,writeFile as wt,rename as vt}from"fs/promises";import{existsSync as kt,readdirSync as Pn}from"fs";import{join as Y,resolve as Dn}from"path";import{homedir as An}from"os";import{execFile as In}from"child_process";Ce();He();var Ia=[{name:"project_brief",description:"CALL THIS FIRST at the start of every session. Returns a complete project briefing: what the project is, tech stack, current priorities, open issues, blockers, what to work on next, and recent decisions. This is your single source of truth \u2014 call it before doing anything else.",inputSchema:{type:"object",properties:{}}},{name:"get_codebase",description:"Get codebase data by category with optional sparse field selection. Use the 'fields' array to request only specific fields (e.g. fields: ['languages', 'frameworks'] from category: 'stack'). For single dot-path lookups use query_codebase instead.",inputSchema:{type:"object",properties:{category:{type:"string",description:"Section to retrieve: repo, structure, stack, commands, dependencies, config, git, quality, patterns, status, roadmap, decisions"},fields:{type:"array",items:{type:"string"},description:"Optional. When category is specified, return only these keys from that section. E.g. ['languages', 'frameworks'] for stack."}}}},{name:"query_codebase",description:"Query a specific field using dot-path notation. Handles both targeted dot-path queries (e.g. 'stack.languages') and full category reads (e.g. 'stack'). Examples: 'stack.languages', 'commands.test', 'status.kanban.in_progress', 'roadmap.milestones'.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Dot-path query, e.g. 'stack.languages', 'commands.test', 'status.priorities'"},fields:{type:"array",items:{type:"string"},description:"Optional: return only these fields from the result object"}},required:["path"]}},{name:"get_next_task",description:"Get the highest-priority task you should work on next. Returns the top open issue ranked by priority labels (P0 > P1 > bugs > features), including mapped files so you know where to start coding.",inputSchema:{type:"object",properties:{}}},{name:"get_blockers",description:"Get all current blockers \u2014 issues labeled as blocked, PRs waiting for review, PRs with failing CI checks, PRs with merge conflicts, and uncommitted changes. Shows what's preventing progress.",inputSchema:{type:"object",properties:{}}},{name:"create_issue",description:"Create a new GitHub issue. Use this when you discover a bug, identify needed work, or the user asks to track something. Returns the issue URL.",inputSchema:{type:"object",properties:{title:{type:"string",description:"Issue title"},body:{type:"string",description:"Issue body/description (markdown)"},labels:{type:"array",items:{type:"string"},description:"Labels to apply: bug, feature, enhancement, P0, P1, P2, etc."}},required:["title"]}},{name:"close_issue",description:"Close a GitHub issue after fixing it. Add a comment explaining what was done.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number to close"},comment:{type:"string",description:"Comment explaining resolution"}},required:["number"]}},{name:"update_issue",description:"Update a GitHub issue \u2014 add/remove labels, set assignee. Use this to advance issues through the pipeline (e.g., add 'status:in-progress', remove 'status:backlog').",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number"},add_labels:{type:"array",items:{type:"string"},description:"Labels to add"},remove_labels:{type:"array",items:{type:"string"},description:"Labels to remove"},assignee:{type:"string",description:"GitHub username to assign (or empty string to unassign)"}},required:["number"]}},{name:"list_commands",description:"List installed Claude Code slash commands in this project. Returns names of available commands (e.g. /setup, /simulate, /build, /launch, /review).",inputSchema:{type:"object",properties:{}}},{name:"list_skills",description:"List installed Claude Code skills with their names and descriptions. Skills extend /review and other commands with stack-specific analysis.",inputSchema:{type:"object",properties:{}}},{name:"get_plan",description:"Read the project's PLAN.md \u2014 Claude's persistent working memory across sessions. Contains current sprint goals, in-flight work, decisions log, and blockers. Call this after project_brief to restore loop context.",inputSchema:{type:"object",properties:{}}},{name:"update_plan",description:"Append a status update to PLAN.md. Use this at the end of each build or simulate cycle to record what was done, decisions made, and what's next. Creates PLAN.md if it doesn't exist.",inputSchema:{type:"object",properties:{message:{type:"string",description:"Status update text to append to PLAN.md Update Log section"}},required:["message"]}},{name:"get_issue",description:"Get full details of a specific GitHub issue by number, including body, comments, and linked PRs. Use this when working on an issue and need its complete specification.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number"}},required:["number"]}},{name:"get_pr",description:"Get full details of a specific pull request by number, including body, review status, checks, and diff stats.",inputSchema:{type:"object",properties:{number:{type:"number",description:"PR number"}},required:["number"]}},{name:"rescan_project",description:"Rescan the project to refresh the manifest after making changes. Call this after major refactors, dependency updates, or when your cached data feels stale.",inputSchema:{type:"object",properties:{sync:{type:"boolean",description:"Also refresh GitHub data (issues, PRs, milestones). Default: true."},incremental:{type:"boolean",description:"Only re-scan changed areas (faster). Default: false."}}}},{name:"refresh_status",description:"Refresh only GitHub data (issues, PRs, milestones) without re-scanning the filesystem. Much faster than rescan_project. Call this after creating/closing issues to get fresh priority data.",inputSchema:{type:"object",properties:{}}}];async function Nn(e){let t=Oa({input:process.stdin,terminal:!1});for await(let s of t){if(!s.trim())continue;let n;try{n=JSON.parse(s)}catch{On({jsonrpc:"2.0",id:0,error:{code:-32700,message:"Parse error"}});continue}let i=await Na(n,e);i&&On(i)}}async function Na(e,t){switch(e.method){case"initialize":return O(e.id,{protocolVersion:"2024-11-05",serverInfo:{name:"codebase",version:"0.3.
|
|
623
|
+
${w(t.title)} ${s} ${t.progress.percent}%${n}`),u(` ${t.progress.closed}/${t.progress.open+t.progress.closed} issues closed`)}}function Da(e){S("Decisions");let t=[...e.from_prs.map(s=>({...s,type:"PR"})),...e.from_adrs.map(s=>({...s,type:"ADR"})),...e.manual.map(s=>({...s,type:"Manual"}))].sort((s,n)=>(n.date||"").localeCompare(s.date||""));for(let s of t.slice(0,15))u(` [${s.type}] ${s.title}`),s.summary&&u(` ${s.summary.slice(0,100)}`)}function Aa(e){let t=Math.round(e/5),s=20-t;return`[${"\u2588".repeat(t)}${"\u2591".repeat(s)}]`}import{resolve as Ua}from"path";import{createInterface as Oa}from"readline";import{readFile as Qe,writeFile as wt,rename as vt}from"fs/promises";import{existsSync as kt,readdirSync as Pn}from"fs";import{join as Y,resolve as Dn}from"path";import{homedir as An}from"os";import{execFile as In}from"child_process";Ce();He();var Ia=[{name:"project_brief",description:"CALL THIS FIRST at the start of every session. Returns a complete project briefing: what the project is, tech stack, current priorities, open issues, blockers, what to work on next, and recent decisions. This is your single source of truth \u2014 call it before doing anything else.",inputSchema:{type:"object",properties:{}}},{name:"get_codebase",description:"Get codebase data by category with optional sparse field selection. Use the 'fields' array to request only specific fields (e.g. fields: ['languages', 'frameworks'] from category: 'stack'). For single dot-path lookups use query_codebase instead.",inputSchema:{type:"object",properties:{category:{type:"string",description:"Section to retrieve: repo, structure, stack, commands, dependencies, config, git, quality, patterns, status, roadmap, decisions"},fields:{type:"array",items:{type:"string"},description:"Optional. When category is specified, return only these keys from that section. E.g. ['languages', 'frameworks'] for stack."}}}},{name:"query_codebase",description:"Query a specific field using dot-path notation. Handles both targeted dot-path queries (e.g. 'stack.languages') and full category reads (e.g. 'stack'). Examples: 'stack.languages', 'commands.test', 'status.kanban.in_progress', 'roadmap.milestones'.",inputSchema:{type:"object",properties:{path:{type:"string",description:"Dot-path query, e.g. 'stack.languages', 'commands.test', 'status.priorities'"},fields:{type:"array",items:{type:"string"},description:"Optional: return only these fields from the result object"}},required:["path"]}},{name:"get_next_task",description:"Get the highest-priority task you should work on next. Returns the top open issue ranked by priority labels (P0 > P1 > bugs > features), including mapped files so you know where to start coding.",inputSchema:{type:"object",properties:{}}},{name:"get_blockers",description:"Get all current blockers \u2014 issues labeled as blocked, PRs waiting for review, PRs with failing CI checks, PRs with merge conflicts, and uncommitted changes. Shows what's preventing progress.",inputSchema:{type:"object",properties:{}}},{name:"create_issue",description:"Create a new GitHub issue. Use this when you discover a bug, identify needed work, or the user asks to track something. Returns the issue URL.",inputSchema:{type:"object",properties:{title:{type:"string",description:"Issue title"},body:{type:"string",description:"Issue body/description (markdown)"},labels:{type:"array",items:{type:"string"},description:"Labels to apply: bug, feature, enhancement, P0, P1, P2, etc."}},required:["title"]}},{name:"close_issue",description:"Close a GitHub issue after fixing it. Add a comment explaining what was done.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number to close"},comment:{type:"string",description:"Comment explaining resolution"}},required:["number"]}},{name:"update_issue",description:"Update a GitHub issue \u2014 add/remove labels, set assignee. Use this to advance issues through the pipeline (e.g., add 'status:in-progress', remove 'status:backlog').",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number"},add_labels:{type:"array",items:{type:"string"},description:"Labels to add"},remove_labels:{type:"array",items:{type:"string"},description:"Labels to remove"},assignee:{type:"string",description:"GitHub username to assign (or empty string to unassign)"}},required:["number"]}},{name:"list_commands",description:"List installed Claude Code slash commands in this project. Returns names of available commands (e.g. /setup, /simulate, /build, /launch, /review).",inputSchema:{type:"object",properties:{}}},{name:"list_skills",description:"List installed Claude Code skills with their names and descriptions. Skills extend /review and other commands with stack-specific analysis.",inputSchema:{type:"object",properties:{}}},{name:"get_plan",description:"Read the project's PLAN.md \u2014 Claude's persistent working memory across sessions. Contains current sprint goals, in-flight work, decisions log, and blockers. Call this after project_brief to restore loop context.",inputSchema:{type:"object",properties:{}}},{name:"update_plan",description:"Append a status update to PLAN.md. Use this at the end of each build or simulate cycle to record what was done, decisions made, and what's next. Creates PLAN.md if it doesn't exist.",inputSchema:{type:"object",properties:{message:{type:"string",description:"Status update text to append to PLAN.md Update Log section"}},required:["message"]}},{name:"get_issue",description:"Get full details of a specific GitHub issue by number, including body, comments, and linked PRs. Use this when working on an issue and need its complete specification.",inputSchema:{type:"object",properties:{number:{type:"number",description:"Issue number"}},required:["number"]}},{name:"get_pr",description:"Get full details of a specific pull request by number, including body, review status, checks, and diff stats.",inputSchema:{type:"object",properties:{number:{type:"number",description:"PR number"}},required:["number"]}},{name:"rescan_project",description:"Rescan the project to refresh the manifest after making changes. Call this after major refactors, dependency updates, or when your cached data feels stale.",inputSchema:{type:"object",properties:{sync:{type:"boolean",description:"Also refresh GitHub data (issues, PRs, milestones). Default: true."},incremental:{type:"boolean",description:"Only re-scan changed areas (faster). Default: false."}}}},{name:"refresh_status",description:"Refresh only GitHub data (issues, PRs, milestones) without re-scanning the filesystem. Much faster than rescan_project. Call this after creating/closing issues to get fresh priority data.",inputSchema:{type:"object",properties:{}}}];async function Nn(e){let t=Oa({input:process.stdin,terminal:!1});for await(let s of t){if(!s.trim())continue;let n;try{n=JSON.parse(s)}catch{On({jsonrpc:"2.0",id:0,error:{code:-32700,message:"Parse error"}});continue}let i=await Na(n,e);i&&On(i)}}async function Na(e,t){switch(e.method){case"initialize":return O(e.id,{protocolVersion:"2024-11-05",serverInfo:{name:"codebase",version:"0.3.1"},capabilities:{tools:{}}});case"notifications/initialized":return null;case"tools/list":return O(e.id,{tools:Ia});case"tools/call":return La(e,t);default:return{jsonrpc:"2.0",id:e.id,error:{code:-32601,message:`Method not found: ${e.method}`}}}}async function La(e,t){let s=e.params||{},n=s.name,i=s.arguments||{};try{switch(n){case"project_brief":{let o=await Ve(t,!0),r=yt(o);return O(e.id,{content:[{type:"text",text:r}]})}case"get_codebase":{let o=await Ve(t),r=i.category,a=i.fields;if(r){let c=o[r];if(a?.length&&c&&typeof c=="object"&&c!==null){let l={};for(let p of a)l[p]=c[p];return O(e.id,{content:[{type:"text",text:JSON.stringify(l,null,2)}]})}return O(e.id,{content:[{type:"text",text:JSON.stringify(c??null,null,2)}]})}return O(e.id,{content:[{type:"text",text:JSON.stringify(o,null,2)}]})}case"query_codebase":{let o=await Ve(t),r=i.path,a=i.fields,c=Ae(o,r);if(a?.length&&c!==null&&c!==void 0&&typeof c=="object"&&!Array.isArray(c)){let l={};for(let p of a)l[p]=c[p];c=l}return O(e.id,{content:[{type:"text",text:JSON.stringify(c??null,null,2)}]})}case"get_next_task":{let o=await Ve(t,!0),r=Ma(o);return O(e.id,{content:[{type:"text",text:JSON.stringify(r,null,2)}]})}case"get_blockers":{let o=await Ve(t,!0),r=Ta(o);return O(e.id,{content:[{type:"text",text:JSON.stringify(r,null,2)}]})}case"create_issue":{let o=await qa(t,i);return await Bt(t),O(e.id,{content:[{type:"text",text:o}]})}case"close_issue":{let o=await Ha(t,i);return await Bt(t),O(e.id,{content:[{type:"text",text:o}]})}case"update_issue":{let o=await Ga(t,i);return await Bt(t),O(e.id,{content:[{type:"text",text:o}]})}case"list_commands":{let o=Y(t,".claude","commands"),r=Y(An(),".claude","commands"),a=new Set,c=[];for(let p of[o,r])if(kt(p))for(let d of Pn(p))d.endsWith(".md")&&!a.has(d)&&(a.add(d),c.push(d));if(c.length===0)return O(e.id,{content:[{type:"text",text:"No slash commands installed. Run: codebase setup"}]});let l=c.map(p=>"/"+p.replace(/\.md$/,"")).join(", ");return O(e.id,{content:[{type:"text",text:`Installed commands (${c.length}): ${l}
|
|
624
624
|
|
|
625
625
|
Loop: /simulate \u2192 /build \u2192 /launch`}]})}case"list_skills":{let o=Y(An(),".claude","skills"),r=Y(t,".claude","skills"),a=new Set,c=[];for(let p of[r,o])if(kt(p))for(let d of Pn(p))d.endsWith(".skill")&&!a.has(d)&&(a.add(d),c.push({file:d,dir:p}));if(c.length===0)return O(e.id,{content:[{type:"text",text:"No skills installed in ~/.claude/skills/ or <project>/.claude/skills/. Run: codebase setup"}]});let l=[];return await Promise.all(c.map(({file:p,dir:d})=>new Promise(m=>{let y=Y(d,p);In("unzip",["-p",y,"*/SKILL.md"],{timeout:1e4},(b,x)=>{if(b||!x.trim()){m();return}let j=x.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!j){m();return}let _=j[1],f=_.match(/^name:\s*(.+)$/m),P=_.match(/^description:\s*(.+)$/m),A=f?f[1].trim():p.replace(/\.skill$/,""),G=P?P[1].trim():"";l.push({name:A,description:G,file:p}),m()})}))),O(e.id,{content:[{type:"text",text:JSON.stringify(l,null,2)}]})}case"get_plan":{let o=Y(Dn(t),"PLAN.md");if(!kt(o))return O(e.id,{content:[{type:"text",text:"No PLAN.md found. Use update_plan to create one."}]});let r=await Qe(o,"utf-8");return O(e.id,{content:[{type:"text",text:r}]})}case"update_plan":{let o=Y(Dn(t),"PLAN.md"),r=i.message,c=`
|
|
626
626
|
<!-- updated: ${new Date().toISOString().split("T")[0]} -->
|
|
@@ -703,6 +703,6 @@ ${n}`;await Jn(e,o,"utf-8"),u(`${w("Created")} PLAN.md`);return}let i=await Wn(e
|
|
|
703
703
|
## Update Log
|
|
704
704
|
${n}`,await Jn(e,i,"utf-8"),u(`${w("Updated")} PLAN.md`)}M();import{join as Kt,resolve as $c}from"path";import{existsSync as xc,readdirSync as jc}from"fs";import{execFile as Cc}from"child_process";function Sc(e){return new Promise((t,s)=>{Cc("unzip",["-p",e,"*/SKILL.md"],(n,i)=>{n&&!i?s(n):t(i??"")})})}function Ec(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!t)return{};let s={};for(let n of t[1].split(`
|
|
705
705
|
`)){let i=n.indexOf(":");if(i===-1)continue;let o=n.slice(0,i).trim(),r=n.slice(i+1).trim().replace(/^['"]|['"]$/g,"");o&&(s[o]=r)}return s}async function Vn(e){let t=Kt(process.env.HOME??"~",".claude","skills"),s=Kt($c(e.path??"."),".claude","skills"),n=new Set,i=[];for(let d of[s,t])if(xc(d))for(let m of jc(d))m.endsWith(".skill")&&!n.has(m)&&(n.add(m),i.push({file:m,dir:d}));if(i.length===0){u("No skills installed. Run: codebase setup");return}let o=[];for(let{file:d,dir:m}of i){let y=Kt(m,d),b=d.replace(/\.skill$/,""),x="";try{let j=await Sc(y),_=Ec(j);_.name&&(b=_.name),_.description&&(x=_.description)}catch{}o.push({name:b,description:x,file:d})}if(o.length===0){u("No skills installed. Run: codebase setup");return}let r=Math.max(4,...o.map(d=>d.name.length)),a=Math.max(11,...o.map(d=>d.description.length)),c=Math.max(4,...o.map(d=>d.file.length)),l=(d,m)=>d.padEnd(m),p=` ${"\u2500".repeat(r)} ${"\u2500".repeat(a)} ${"\u2500".repeat(c)}`;h(`
|
|
706
|
-
${l("Name",r)} ${l("Description",a)} File`),u(p);for(let d of o)u(` ${l(d.name,r)} ${l(d.description,a)} ${d.file}`);u("")}import{createServer as Pc}from"http";Ce();import{readFile as _c,writeFile as Rc}from"fs/promises";import{join as Qn}from"path";async function Yn(e,t,s){let n=new URL(e,"http://localhost"),i=n.pathname;if(i==="/health")return{status:200,body:{status:"ok",version:"0.3.
|
|
706
|
+
${l("Name",r)} ${l("Description",a)} File`),u(p);for(let d of o)u(` ${l(d.name,r)} ${l(d.description,a)} ${d.file}`);u("")}import{createServer as Pc}from"http";Ce();import{readFile as _c,writeFile as Rc}from"fs/promises";import{join as Qn}from"path";async function Yn(e,t,s){let n=new URL(e,"http://localhost"),i=n.pathname;if(i==="/health")return{status:200,body:{status:"ok",version:"0.3.1"}};if(i==="/codebase/query"&&t==="GET"){let o=n.searchParams.get("path");if(!o)return{status:400,body:{error:"Missing 'path' query parameter"}};let r=await zt(s);return r?{status:200,body:Ae(r,o)??null}:{status:404,body:{error:"No manifest. POST /codebase/scan first."}}}if(i==="/codebase/scan"&&t==="POST"){let o=await W(s,{quiet:!0});return await Rc(Qn(s,".codebase.json"),JSON.stringify(o,null,2),"utf-8"),{status:200,body:o}}if(i==="/codebase"&&t==="GET"){let o=await zt(s);return o?{status:200,body:o}:{status:404,body:{error:"No manifest. POST /codebase/scan first."}}}if(i.startsWith("/codebase/")&&t==="GET"){let o=i.split("/")[2],r=await zt(s);if(!r)return{status:404,body:{error:"No manifest."}};let a=r[o];return a===void 0?{status:404,body:{error:`Category '${o}' not found.`}}:{status:200,body:a}}return{status:404,body:{error:"Not found"}}}async function zt(e){try{let t=await _c(Qn(e,".codebase.json"),"utf-8");return JSON.parse(t)}catch{return null}}function Xn(e,t){let s=Pc(async(n,i)=>{if(i.setHeader("Access-Control-Allow-Origin","*"),i.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),i.setHeader("Access-Control-Allow-Headers","Content-Type"),i.setHeader("Content-Type","application/json"),n.method==="OPTIONS"){i.writeHead(200),i.end();return}try{let o=await Yn(n.url||"/",n.method||"GET",e);i.writeHead(o.status),i.end(JSON.stringify(o.body,null,2))}catch{i.writeHead(500),i.end(JSON.stringify({error:"Internal server error"}))}});s.listen(t,()=>{console.log(`codebase server running on http://localhost:${t}`),console.log(`
|
|
707
707
|
Endpoints:`),console.log(" GET /health Health check"),console.log(" GET /codebase Full manifest"),console.log(" GET /codebase/:category Single category"),console.log(" GET /codebase/query?path=stack.languages"),console.log(" POST /codebase/scan Trigger re-scan")}),process.on("SIGINT",()=>{s.close(),process.exit(0)}),process.on("SIGTERM",()=>{s.close(),process.exit(0)})}var pe=es(process.argv.slice(2));ee(pe.quiet);Qt(pe.verbose);pe.helpCommand&&pe.command&&ts(pe.command);var Dc={scan:Ge,init:bn,brief:yn,next:wn,setup:Tt,query:vn,issue:En,status:Rn,mcp:Ln,doctor:qn,fix:Un,release:Bn,plan:zn,skills:Vn,serve:e=>(Xn(e.path,e.port??3e3),Promise.resolve()),"scan-only":Ge};os().catch(()=>{});var[Ac]=process.versions.node.split(".").map(Number);Ac<20&&(console.error(`Error: Node.js 20 or higher is required. You are running v${process.versions.node}.`),console.error("Upgrade: https://nodejs.org"),process.exit(1));var Zn=Dc[pe.command];Zn||(v(`Unknown command: ${pe.command}`),h(`Run ${w("codebase --help")} to see all commands.`),process.exit(1));Zn(pe).catch(e=>{v(`Error: ${e.message}`);let t=e.message.toLowerCase();t.includes("not a git repository")?h(`Initialize git first: ${w("git init")}`):t.includes("permission denied")?h("Check file permissions or run with appropriate access"):t.includes("enoent")&&t.includes("gh")?h(`GitHub CLI (gh) is not installed. Install it: ${w("brew install gh && gh auth login")}`):t.includes("no such file")?h("Check that the path is correct"):t.includes("github")&&(h(`Ensure GitHub CLI is installed: ${w("gh --version")}`),h(`Authenticate: ${w("gh auth login")}`)),process.exit(1)});
|
|
708
708
|
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
package/skills/cx-review.skill
CHANGED
|
Binary file
|
package/skills/dx-review.skill
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|