codebase-ai 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/build.md +163 -42
- package/commands/review.md +45 -1
- package/commands/simulate.md +220 -37
- package/dist/index.js +269 -193
- package/package.json +8 -3
- package/skills/arch-review.skill +0 -0
- package/skills/cx-review.skill +0 -0
- package/skills/dx-review.skill +0 -0
- package/skills/nextjs-declutter.skill +0 -0
- package/skills/py-declutter.skill +0 -0
- package/skills/vibeloop.skill +0 -0
package/dist/index.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
${
|
|
4
|
-
`),i=!1,o=[];for(let a of n){let c=a.trim();if(c.startsWith("#")){if(i)break;continue}if(!c||c.startsWith("![")||c.startsWith("[![")||c.startsWith("<")){if(i)break;continue}i=!0,o.push(c)}return o.join(" ").slice(0,300)||null}var
|
|
5
|
-
`).map(s=>s.trim().replace(/^origin\//,"")).filter(s=>s&&s!=="HEAD").filter((s,n,i)=>i.indexOf(s)===n).slice(0,10):[]}async function
|
|
2
|
+
var Wn=Object.defineProperty;var D=(e,t)=>()=>(e&&(t=e(e=0)),t);var Gt=(e,t)=>{for(var s in t)Wn(e,s,{get:t[s],enumerable:!0})};function Q(e){ae=e}function Ut(e){Kn=e}function u(e){ae||console.log(e)}function y(e){ae||console.log(` ${T.green}[\u2713]${T.reset} ${e}`)}function C(e){console.error(` ${T.red}[\u2717]${T.reset} ${e}`)}function S(e){ae||console.log(` ${T.yellow}[!]${T.reset} ${e}`)}function k(e){ae||console.log(` ${T.cyan}[i]${T.reset} ${e}`)}function Bt(e){ae||console.log(`${T.dim}${e}${T.reset}`)}function E(e){return`${T.bold}${e}${T.reset}`}function _(e){ae||console.log(`
|
|
3
|
+
${T.bold}${e}${T.reset}`)}function ze(e,t){return process.stdout.isTTY&&!V?`\x1B]8;;${t}\x1B\\${e}\x1B]8;;\x1B\\`:`${e} (${t})`}function W(e){return`${T.dim}${e}${T.reset}`}function $(e){return`${T.cyan}${e}${T.reset}`}var V,T,ae,Kn,M=D(()=>{"use strict";V=!!process.env.NO_COLOR,T={reset:V?"":"\x1B[0m",green:V?"":"\x1B[32m",red:V?"":"\x1B[31m",yellow:V?"":"\x1B[33m",cyan:V?"":"\x1B[36m",blue:V?"":"\x1B[34m",magenta:V?"":"\x1B[35m",dim:V?"":"\x1B[2m",bold:V?"":"\x1B[1m"},ae=!1,Kn=!1});function es(e,t){let s=ui(t);return e.filter(n=>s.test(n))}function ui(e){let t="^",s=0;for(;s<e.length;){let n=e[s];if(n==="*")e[s+1]==="*"?e[s+2]==="/"?(t+="(?:.*/)?",s+=3):(t+=".*",s+=2):(t+="[^/]*",s++);else if(n==="?")t+="[^/]",s++;else if(n==="{"){let i=e.indexOf("}",s);if(i!==-1){let o=e.slice(s+1,i).split(",");t+="(?:"+o.map(wt).join("|")+")",s=i+1}else t+=wt(n),s++}else t+=wt(n),s++}return t+="$",new RegExp(t)}function wt(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var ts=D(()=>{"use strict"});import{readdir as di,readFile as pi}from"fs/promises";import{existsSync as fi}from"fs";import{join as vt,relative as mi}from"path";import{execFile as gi}from"child_process";async function ss(e,t={}){let s=new Set([...hi,...t.ignore??[]]),n=await ns(e,e,s,t.depth??10),i=new Set(n);return{root:e,files:n,async readFile(o){try{return await pi(vt(e,o),"utf-8")}catch{return""}},fileExists(o){return i.has(o)?!0:fi(vt(e,o))},glob(o){return es(n,o)},exec(o,r){return new Promise(a=>{gi(o,r,{cwd:e,timeout:1e4},(c,l)=>{a(c?"":l.trim())})})}}}async function ns(e,t,s,n,i=0){if(i>n)return[];let o=[];try{let r=await di(t,{withFileTypes:!0});for(let a of r){if(s.has(a.name)||a.isDirectory()&&a.name.startsWith(".")&&!new Set([".github",".husky",".circleci"]).has(a.name))continue;let c=vt(t,a.name),l=mi(e,c);if(a.isDirectory()){o.push(l+"/");let p=await ns(e,c,s,n,i+1);o.push(...p)}else o.push(l)}}catch{}return o}var hi,is=D(()=>{"use strict";ts();hi=new Set(["node_modules",".git","dist","build",".next",".nuxt",".output","__pycache__","vendor",".venv","venv","target","coverage",".cache",".turbo",".vercel",".netlify",".parcel-cache",".svelte-kit",".angular","out","bin","obj"])});async function bi(e){let t=await e.readFile("package.json");if(t)try{let r=JSON.parse(t);if(r.name)return r.name}catch{}let s=await e.readFile("Cargo.toml");if(s){let r=s.match(/^name\s*=\s*"([^"]+)"/m);if(r)return r[1]}let n=await e.readFile("pyproject.toml");if(n){let r=n.match(/^name\s*=\s*"([^"]+)"/m);if(r)return r[1]}let i=await e.readFile("go.mod");if(i){let r=i.match(/^module\s+(\S+)/m);if(r)return r[1].split("/").pop()||r[1]}let o=await e.exec("git",["remote","get-url","origin"]);return o?o.replace(/.*[:/]/,"").replace(/\.git$/,""):e.root.split("/").pop()||"unknown"}async function yi(e){let t=await e.readFile("package.json");if(t)try{let i=JSON.parse(t);if(i.description)return i.description}catch{}let s=await e.readFile("Cargo.toml");if(s){let i=s.match(/^description\s*=\s*"([^"]+)"/m);if(i)return i[1]}let n=await e.readFile("pyproject.toml");if(n){let i=n.match(/^description\s*=\s*"([^"]+)"/m);if(i)return i[1]}return null}async function ki(e){let t=["README.md","readme.md","README","README.txt","README.rst"],s="";for(let a of t)if(s=await e.readFile(a),s)break;if(!s)return null;let n=s.split(`
|
|
4
|
+
`),i=!1,o=[];for(let a of n){let c=a.trim();if(c.startsWith("#")){if(i)break;continue}if(!c||c.startsWith("![")||c.startsWith("[![")||c.startsWith("<")){if(i)break;continue}i=!0,o.push(c)}return o.join(" ").slice(0,300)||null}var os,rs=D(()=>{"use strict";os={name:"project",category:"project",async detect(e){let[t,s,n]=await Promise.all([bi(e),yi(e),ki(e)]);return{name:t,description:s||n||null}}}});async function wi(e){return await e.exec("git",["remote","get-url","origin"])||null}async function vi(e){let t=await e.exec("git",["symbolic-ref","refs/remotes/origin/HEAD"]);if(t)return t.replace("refs/remotes/origin/","");let s=await e.exec("git",["branch","--list","main","master"]);return s.includes("main")?"main":s.includes("master")?"master":await e.exec("git",["branch","--show-current"])||null}async function $i(e){let t=await e.exec("git",["branch","-a","--sort=-committerdate","--format=%(refname:short)"]);return t?t.split(`
|
|
5
|
+
`).map(s=>s.trim().replace(/^origin\//,"")).filter(s=>s&&s!=="HEAD").filter((s,n,i)=>i.indexOf(s)===n).slice(0,10):[]}async function xi(e){let t=await e.readFile("package.json");if(t)try{if(JSON.parse(t).workspaces)return!0}catch{}return e.fileExists("pnpm-workspace.yaml")||e.fileExists("lerna.json")||e.fileExists("turbo.json")||e.fileExists("nx.json")||e.fileExists("rush.json")}async function ji(e){if(e.fileExists("turbo.json"))return"turborepo";if(e.fileExists("nx.json"))return"nx";if(e.fileExists("lerna.json"))return"lerna";if(e.fileExists("rush.json"))return"rush";if(e.fileExists("pnpm-workspace.yaml"))return"pnpm";let t=await e.readFile("package.json");if(t)try{if(JSON.parse(t).workspaces)return"npm/yarn"}catch{}return null}var as,cs=D(()=>{"use strict";as={name:"repo",category:"repo",async detect(e){let[t,s,n,i,o]=await Promise.all([wi(e),vi(e),$i(e),xi(e),ji(e)]);return{url:t,default_branch:s,is_monorepo:i,workspace_manager:i?o:null,active_branches:n}}}});import{existsSync as Ci}from"fs";import{join as Ei}from"path";function Ri(e,t){let s={},n=[];for(let o of e){let a=o.replace(/\/$/,"").split("/");if(a.length===1&&!o.endsWith("/")){n.push(a[0]);continue}if(a.length<2)continue;let c=a[0]+"/";a.length===2&&!o.endsWith("/")?(s[c]||(s[c]=new Set),s[c].add(a[1])):a.length>=3&&(s[c]||(s[c]=new Set),s[c].add(a[1]+"/"))}let i={};if(n.length>0){let o=n.sort();i["./"]=o.length>15?[...o.slice(0,13),`... (${o.length} files)`]:o}for(let[o,r]of Object.entries(s)){let a=[...r].sort();i[o]=a.length>20?[...a.slice(0,18),`... (${a.length} items)`]:a}return i}var Si,_i,ls,us=D(()=>{"use strict";Si=["src/index.ts","src/index.js","src/main.ts","src/main.js","src/app.ts","src/app.js","src/server.ts","src/server.js","src/app/layout.tsx","src/app/page.tsx","app/layout.tsx","pages/_app.tsx","pages/_app.js","pages/index.tsx","index.ts","index.js","main.ts","main.js","app/main.py","main.py","app.py","manage.py","main.go","cmd/main.go","src/main.rs","src/lib.rs","lib/main.dart","Program.cs"],_i=["dist","build",".next","out","target","bin","obj",".output",".nuxt",".svelte-kit",".vercel"],ls={name:"structure",category:"structure",async detect(e){let t=Si.filter(i=>e.fileExists(i)),s=_i.filter(i=>Ci(Ei(e.root,i))),n=Ri(e.files,4);return{entry_points:t,build_output:s,tree:n}}}});function Li(e){let t={};for(let s of e.files){if(s.endsWith("/"))continue;let n="."+s.split(".").pop(),i=Pi[n];i&&(t[i]=(t[i]||0)+1)}return Object.entries(t).sort((s,n)=>n[1]-s[1]).map(([s])=>s)}async function Fi(e){let t=await e.readFile("package.json");if(!t)return{};try{let s=JSON.parse(t);return{...s.dependencies||{},...s.devDependencies||{}}}catch{return{}}}function Mi(e){let t=[];for(let[n,i]of Object.entries(e)){let o=Di[n];if(o){let r=i.replace(/^[\^~>=<]+/,"").split(".").slice(0,2).join(".");t.push(`${o}@${r}`)}}let s=qi(e);return t.push(...s),[...new Set(t)]}function qi(e){let t=[],s=Object.keys(e).join(" ");if(s.includes("next")){let n=e.next?.replace(/^[\^~>=<]+/,"").split(".").slice(0,2).join("."),i=[];n&&(parseFloat(n)>=13&&i.push("app-router available"),i.push(n)),t.push(i.length>0?`next.js@${i.join(" ")}`:"next.js")}if(s.includes("vue")){let n=e.vue?.replace(/^[\^~>=<]+/,"");if(n){let i=parseInt(n.split(".")[0],10);t.push(i>=3?`vue@${n}`:`vue@${n}`)}else t.push("vue");if(s.includes("nuxt")){let i=e.nuxt?.replace(/^[\^~>=<]+/,"");if(i){let o=parseInt(i.split(".")[0],10);t.push(o>=3?`nuxt@${i} (Nuxt 3)`:`nuxt@${i} (Nuxt 2)`)}else t.push("nuxt")}}if(s.includes("@sveltejs/kit")){let n=e["@sveltejs/kit"]?.replace(/^[\^~>=<]+/,"");t.push(n?`sveltekit@${n}`:"sveltekit")}if(s.includes("astro")){let n=e.astro?.replace(/^[\^~>=<]+/,""),i=[];e["@astrojs/react"]&&i.push("react"),e["@astrojs/vue"]&&i.push("vue"),e["@astrojs/svelte"]&&i.push("svelte"),e["@astrojs/preact"]&&i.push("preact"),e["@astrojs/solid-js"]&&i.push("solid"),i.length>0?t.push(n?`astro@${n} (${i.join(", ")})`:`astro (${i.join(", ")})`):t.push(n?`astro@${n}`:"astro")}if(s.includes("@remix-run/react")||s.includes("@remix-run/node")){let n=e["@remix-run/react"]?.replace(/^[\^~>=<]+/,"")||e["@remix-run/node"]?.replace(/^[\^~>=<]+/,"");t.push(n?`remix@${n}`:"remix")}if(s.includes("@angular/core")){let n=e["@angular/core"]?.replace(/^[\^~>=<]+/,"").split(".").slice(0,2).join(".");t.push(n?`angular@${n}`:"angular")}if(s.includes("gatsby")){let n=e.gatsby?.replace(/^[\^~>=<]+/,"");t.push(n?`gatsby@${n}`:"gatsby")}return t}function Ti(e,t){return e.fileExists("pnpm-lock.yaml")?"pnpm":e.fileExists("yarn.lock")?"yarn":e.fileExists("bun.lockb")||e.fileExists("bun.lock")?"bun":e.fileExists("package-lock.json")?"npm":e.fileExists("Cargo.lock")?"cargo":e.fileExists("poetry.lock")?"poetry":e.fileExists("Pipfile.lock")?"pipenv":e.fileExists("go.sum")?"go modules":e.fileExists("Gemfile.lock")?"bundler":e.fileExists("composer.lock")?"composer":Object.keys(t).length>0?"npm":null}function $t(e,t){for(let s of Object.keys(e))if(t[s])return t[s];return null}function Hi(e,t){let s=new Set;for(let n of Object.keys(e))t[n]&&s.add(t[n]);return[...s]}async function Gi(e){let t=await e.readFile("prisma/schema.prisma");if(!t)return null;let s=t.match(/datasource\s+\w+\s*\{([^}]+)\}/);if(!s)return null;let n=s[1].match(/provider\s*=\s*"(.*?)"/);if(!n)return null;let i=n[1].toLowerCase();return i==="postgresql"||i==="postgres"?"postgresql":i==="mysql"?"mysql":i==="sqlite"?"sqlite":i==="sqlserver"?"sqlserver":i==="mongodb"?"mongodb":i==="cockroachdb"?"cockroachdb":i}async function Ui(e){let t=[],s=["migrations/","prisma/migrations/","db/migrate/","database/migrations/","src/migrations/","server/migrations/","api/migrations/","migrate/","sql/","db/sql/"];for(let r of s)if(e.files.some(a=>a.startsWith(r))){let a=await Bi(e,r);a&&!t.includes(a)&&t.push(a)}let n=await Ji(e);for(let r of n)t.includes(r)||t.push(r);let i=await Wi(e);for(let r of i)t.includes(r)||t.push(r);let o=await Ki(e);for(let r of o)t.includes(r)||t.push(r);return t}async function Bi(e,t){let s=e.files.filter(n=>n.startsWith(t));for(let n of s){let i=await e.readFile(n);if(!i)continue;let o=i.toLowerCase();if(o.includes("create table")||o.includes("alter table")){if(o.includes("postgresql")||o.includes("serial")||o.includes("bigserial"))return"postgresql";if(o.includes("mysql")||o.includes("engine=innodb"))return"mysql";if(o.includes("sqlite"))return"sqlite";if(o.includes("mongodb")||o.includes("mongoose"))return"mongodb";if(o.includes("redis"))return"redis";if(o.includes("elasticsearch"))return"elasticsearch"}}return null}async function Ji(e){let t=[],s=["docker-compose.yml","docker-compose.yaml","docker-compose.dev.yml","docker-compose.prod.yml","compose.yml","compose.yaml"];for(let n of s){if(!e.fileExists(n))continue;let i=await e.readFile(n);if(!i)continue;let o=i.toLowerCase();(o.includes("postgres")||o.includes("postgresql"))&&t.push("postgresql"),o.includes("mysql")&&t.push("mysql"),o.includes("mariadb")&&t.push("mariadb"),(o.includes("mongodb")||o.includes("mongo"))&&t.push("mongodb"),o.includes("redis")&&t.push("redis"),o.includes("elasticsearch")&&t.push("elasticsearch"),o.includes("cassandra")&&t.push("cassandra"),o.includes("couchdb")&&t.push("couchdb"),o.includes("neo4j")&&t.push("neo4j"),o.includes("rabbitmq")&&t.push("rabbitmq"),o.includes("dynamodb")&&t.push("dynamodb")}return t}async function Wi(e){let t=[],s=await e.readFile("ormconfig.json")||await e.readFile("ormconfig.js")||await e.readFile("src/data-source.ts");if(s){let r=s.toLowerCase();(r.includes("postgres")||r.includes("pg"))&&t.push("postgresql"),r.includes("mysql")&&t.push("mysql"),r.includes("sqlite")&&t.push("sqlite"),r.includes("mongodb")&&t.push("mongodb")}let n=[".sequelizerc","config/database.js","config/config.js"];for(let r of n){let a=await e.readFile(r);if(a){let c=a.toLowerCase();c.includes("postgres")&&t.push("postgresql"),c.includes("mysql")&&t.push("mysql"),c.includes("sqlite")&&t.push("sqlite"),c.includes("mariadb")&&t.push("mariadb")}}let i=await e.readFile("mikro-orm.config.ts")||await e.readFile("mikro-orm.config.js");if(i){let r=i.toLowerCase();r.includes("postgres")&&t.push("postgresql"),r.includes("mysql")&&t.push("mysql"),r.includes("sqlite")&&t.push("sqlite"),r.includes("mongodb")&&t.push("mongodb")}let o=["drizzle.config.ts","drizzle.config.js","drizzle.config.json"];for(let r of o){let a=await e.readFile(r);if(a){let c=a.toLowerCase();(c.includes("postgres")||c.includes("pg"))&&t.push("postgresql"),c.includes("mysql")&&t.push("mysql"),c.includes("sqlite")&&t.push("sqlite")}}return t}async function Ki(e){let t=[],s=e.files.filter(n=>n.endsWith(".sql")||n.includes("schema")||n.includes("migrate")||n.includes("migration"));for(let n of s){let i=await e.readFile(n);if(!i)continue;let o=i.toLowerCase();(o.includes("serial")||o.includes("bigserial")||o.includes("text[]")||o.includes("jsonb")||o.includes("create extension")||o.includes("pg_"))&&(t.includes("postgresql")||t.push("postgresql")),(o.includes("engine=innodb")||o.includes("auto_increment")||o.includes("tinyint")||o.includes("mediumint")||o.includes("enum("))&&(t.includes("mysql")||t.push("mysql")),(o.includes("autoincrement")||o.includes("integer primary key"))&&(t.includes("sqlite")||t.push("sqlite"))}return t}async function zi(e){let t=await e.readFile("pyproject.toml"),s=await e.readFile("requirements.txt"),n=await e.readFile("setup.py"),i=t+`
|
|
6
6
|
`+s+`
|
|
7
|
-
`+n;if(i.includes("fastapi")){let o=
|
|
7
|
+
`+n;if(i.includes("fastapi")){let o=ge(s,"fastapi")||ge(t,"fastapi");return o?`fastapi@${o}`:"fastapi"}if(i.includes("django")){let o=ge(s,"django")||ge(t,"django"),r=[];o&&r.push(o);let a=await Vi(e);a.length>0&&r.push(`apps: ${a.join(", ")}`);let c=await Qi(e);return c&&r.push(c),r.length>0?`django@${r.join(" ")}`:o?`django@${o}`:"django"}if(i.includes("flask")){let o=ge(s,"flask")||ge(t,"flask");return o?`flask@${o}`:"flask"}return i.includes("starlette")?"starlette":i.includes("tornado")?"tornado":i.includes("aiohttp")?"aiohttp":i.includes("sanic")?"sanic":i.includes("pyramid")?"pyramid":i.includes("bottle")?"bottle":i.includes("cherrypy")?"cherrypy":i.includes("falcon")?"falcon":i.includes("masonite")?"masonite":i.includes("torch")||i.includes("pytorch")?"pytorch":i.includes("tensorflow")?"tensorflow":i.includes("keras")?"keras":i.includes("scikit-learn")?"scikit-learn":i.includes("pandas")?"pandas":i.includes("numpy")?"numpy":i.includes("celery")?"celery":i.includes("rq")?"rq":null}async function Vi(e){let t=[],s=e.files.filter(n=>n.includes("settings.py")||n.includes("settings/")||n.match(/settings.*\.py$/));for(let n of s.slice(0,3))try{let i=await e.readFile(n);if(!i)continue;let o=i.match(/INSTALLED_APPS\s*=\s*\[([\s\S]*?)\]/);if(o){let r=o[1],a=r.match(/'([^']+)'/g)||r.match(/"([^"]+)"/g)||[];for(let c of a){let l=c.replace(/['"]/g,"");!l.startsWith("django.")&&l.includes(".")&&t.push(l.split(".")[0])}}}catch{}return[...new Set(t)].slice(0,5)}async function Qi(e){let t=e.files.some(i=>i.endsWith("settings.py")),s=e.files.some(i=>i.includes("settings/")&&i.endsWith(".py"));return e.files.some(i=>i.includes("settings_dev.py")||i.includes("settings.dev"))?"settings:dev":s?"settings:dir":t?"settings:py":null}async function Yi(e){let t=await e.readFile("go.mod");if(!t)return null;let s=[];if(t.includes("github.com/gin-gonic/gin")){let n=Ce(t,"github.com/gin-gonic/gin");s.push(n?`gin@${n}`:"gin")}if(t.includes("github.com/gofiber/fiber")){let n=Ce(t,"github.com/gofiber/fiber");s.push(n?`fiber@${n}`:"fiber")}if(t.includes("github.com/labstack/echo")){let n=Ce(t,"github.com/labstack/echo");s.push(n?`echo@${n}`:"echo")}if(t.includes("github.com/gorilla/mux")){let n=Ce(t,"github.com/gorilla/mux");s.push(n?`gorilla/mux@${n}`:"gorilla/mux")}if(t.includes("go-chi/chi")){let n=Ce(t,"go-chi/chi");s.push(n?`chi@${n}`:"chi")}return t.includes("grpc")&&s.push("grpc"),t.includes("net/http")&&s.push("net/http (std)"),s.length>0?s.join(", "):null}async function Xi(e){let t=await e.readFile("Cargo.toml");if(!t)return null;let s=[];if(t.includes("actix-web")){let n=Qe(t,"actix-web");s.push(n?`actix-web@${n}`:"actix-web")}if(t.includes("axum")){let n=Qe(t,"axum");s.push(n?`axum@${n}`:"axum")}if(t.includes("rocket")){let n=Qe(t,"rocket");s.push(n?`rocket@${n}`:"rocket")}if(t.includes("warp")&&s.push("warp"),t.includes("tokio")){let n=Qe(t,"tokio");s.push(n?`tokio@${n}`:"tokio")}return t.includes("hyper")&&s.push("hyper"),t.includes("tonic")&&s.push("tonic (grpc)"),s.length>0?s.join(", "):null}async function Zi(e){let t=await e.readFile("pom.xml"),s=await e.readFile("build.gradle"),n=await e.readFile("build.gradle.kts"),i=t+`
|
|
8
8
|
`+s+`
|
|
9
|
-
`+n;if(i.includes("spring-boot")){let o=
|
|
10
|
-
`+s;if(n.includes("rails")){let i=
|
|
11
|
-
`)){let i=n.match(/^([a-zA-Z_-]+)\s*:/);i&&s.add(i[1])}return{dev:s.has("dev")?"make dev":s.has("run")?"make run":null,build:s.has("build")?"make build":null,test:s.has("test")?"make test":null,lint:s.has("lint")?"make lint":null,format:s.has("format")?"make format":s.has("fmt")?"make fmt":null}}async function
|
|
12
|
-
`)){let n=s.trim();if(!n||n.startsWith("#"))continue;let i=n.match(/^([a-zA-Z0-9_-]+)\s*=/);i&&t.push(i[1].toLowerCase())}return t}function
|
|
13
|
-
`)){let n=s.trim();if(!n||n.startsWith("#")||n.startsWith("-"))continue;let i=n.split(/[>=<!;\[]/)[0].trim().toLowerCase();i&&t.push(i)}return t}function
|
|
14
|
-
`)){let r=o.trim();if(!r||r.startsWith("//"))continue;let a=r.split(/\s+/);a[0]&&t.push(a[0])}let n=e.matchAll(/^require\s+(\S+)[ \t]+\S+/gm);for(let i of n)t.push(i[1]);return t}async function
|
|
15
|
-
`)){let o=i.match(/gem\s+["']([^"']+)["']/);o&&(s.push(o[1]),
|
|
9
|
+
`+n;if(i.includes("spring-boot")){let o=Ye(t,"spring-boot-starter-parent")||Xe(s,"org.springframework.boot");return o?`spring boot@${o}`:"spring boot"}if(i.includes("spring-framework")||i.includes("spring-core")){let o=Ye(t,"spring-framework")||Xe(s,"org.springframework");return o?`spring@${o}`:"spring"}if(i.includes("micronaut")){let o=Ye(t,"micronaut")||Xe(s,"io.micronaut");return o?`micronaut@${o}`:"micronaut"}if(i.includes("quarkus")){let o=Ye(t,"quarkus")||Xe(s,"io.quarkus");return o?`quarkus@${o}`:"quarkus"}return i.includes("jakarta")?"jakarta ee":i.includes("javax")?"java ee":i.includes("vertx")?"vert.x":i.includes("kafka")?"kafka":null}async function eo(e){let t=await e.readFile("Gemfile"),s=await e.readFile(".gemspec"),n=t+`
|
|
10
|
+
`+s;if(n.includes("rails")){let i=ds(n,"rails"),o=[];i&&o.push(i);let r=await to(e);return r.length>0&&o.push(r.join(", ")),o.length>0?`rails@${o.join(" ")}`:`rails@${i||"unknown"}`}if(n.includes("sinatra")){let i=ds(n,"sinatra");return i?`sinatra@${i}`:"sinatra"}return n.includes("grape")?"grape":n.includes("hanami")?"hanami":n.includes("roda")?"roda":n.includes("padrino")?"padrino":n.includes("sidekiq")?"sidekiq":n.includes("resque")?"resque":n.includes("puma")?"puma":n.includes("unicorn")?"unicorn":null}async function to(e){let t=[],s=await e.readFile("Gemfile");return s&&(s.includes("devise")&&t.push("devise"),s.includes("pundit")&&t.push("pundit"),s.includes("cancancan")&&t.push("cancancan"),s.includes("rspec-rails")&&t.push("rspec"),s.includes("minitest")&&t.push("minitest"),s.includes("factory_bot_rails")&&t.push("factory_bot"),s.includes("faker")&&t.push("faker"),s.includes("sidekiq")&&t.push("sidekiq"),(s.includes("redis")||s.includes("redis-rails"))&&t.push("redis"),s.includes("pg")&&t.push("postgresql"),s.includes("mysql2")&&t.push("mysql"),s.includes("sqlite3")&&t.push("sqlite"),s.includes("aws-sdk")&&t.push("aws"),s.includes("bootstrap")&&t.push("bootstrap"),s.includes("tailwindcss-rails")&&t.push("tailwind")),t.slice(0,5)}async function so(e){let t=await e.readFile("composer.json");if(!t)return null;try{let s=JSON.parse(t),n={...s.require||{},...s["require-dev"]||{}},i=Object.keys(n).join(" ");if(i.includes("laravel")){let o=n["laravel/framework"]||n["laravel/lumen"];return o?`laravel@${o.replace(/^[\^~>=<]+/,"")}`:"laravel"}if(i.includes("symfony")){let o=n["symfony/framework-bundle"];return o?`symfony@${o.replace(/^[\^~>=<]+/,"")}`:"symfony"}if(i.includes("slim")){let o=n["slim/slim"];return o?`slim@${o.replace(/^[\^~>=<]+/,"")}`:"slim"}if(i.includes("codeigniter"))return"codeigniter";if(i.includes("cakephp"))return"cakephp";if(i.includes("yii")){let o=n["yiisoft/yii2"];return o?`yii@${o.replace(/^[\^~>=<]+/,"")}`:"yii"}if(i.includes("lumen"))return"lumen"}catch{}return null}async function no(e){let t=e.files.filter(n=>n.endsWith(".csproj"));if(t.length===0)return null;let s=[];for(let n of t){let i=await e.readFile(n);if(i.includes("Microsoft.AspNetCore")){let o=io(i,"Microsoft.AspNetCore.App");s.push(o?`asp.net core@${o}`:"asp.net core")}i.includes("EntityFramework")&&s.push("entity framework"),i.includes("NUnit")&&s.push("nunit"),i.includes("xUnit")&&s.push("xunit"),i.includes("Moq")&&s.push("moq")}return s.length>0?s.join(", "):null}function ge(e,t){if(!e)return null;let s=[new RegExp(`${t}===?\\s*([\\d.]+)`),new RegExp(`${t}>=?\\s*([\\d.]+)`),new RegExp(`${t}~=?\\s*([\\d.]+)`),new RegExp(`${t}@([\\d.]+)`),new RegExp(`"${t}":\\s*"([\\d.]+)"`),new RegExp(`'${t}':\\s*'([\\d.]+)'`)];for(let n of s){let i=e.match(n);if(i)return i[1]}return null}function Ce(e,t){let s=new RegExp(`${t}\\s+v([\\d.]+)`),n=e.match(s);return n?n[1]:null}function Qe(e,t){let s=new RegExp(`${t}\\s*=\\s*"([\\d.]+)"`),n=e.match(s);return n?n[1]:null}function Ye(e,t){if(!e)return null;let s=new RegExp(`<artifactId>${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}</artifactId>[\\s\\S]*?<version>([\\d.]+)</version>`),n=e.match(s);return n?n[1]:null}function Xe(e,t){if(!e)return null;let s=[new RegExp(`${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}:[^:]*:([\\d.]+)`),new RegExp(`${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}:([\\d.]+)`)];for(let n of s){let i=e.match(n);if(i)return i[1]}return null}function ds(e,t){let s=new RegExp(`gem\\s+['"]${t}['"][^,]*,\\s*['"]~?>?\\s*([\\d.]+)['"]`),n=e.match(s);return n?n[1]:null}function io(e,t){let s=new RegExp(`<PackageReference\\s+Include="${t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}"[^>]*Version="([\\d.]+)"`),n=e.match(s);return n?n[1]:null}var Pi,Di,Ai,Oi,Ii,Ni,ps,fs=D(()=>{"use strict";Pi={".ts":"typescript",".tsx":"typescript-react",".js":"javascript",".jsx":"javascript-react",".mjs":"javascript",".cjs":"javascript",".py":"python",".pyi":"python",".go":"go",".rs":"rust",".java":"java",".kt":"kotlin",".kts":"kotlin",".cs":"csharp",".rb":"ruby",".php":"php",".swift":"swift",".dart":"dart",".ex":"elixir",".exs":"elixir",".zig":"zig",".scala":"scala",".sc":"scala",".cpp":"c++",".cc":"c++",".cxx":"c++",".hpp":"c++",".h":"c++",".c":"c",".sh":"shell",".bash":"shell",".zsh":"shell",".fish":"shell",".ps1":"powershell",".lua":"lua",".r":"r",".R":"r",".m":"matlab",".mlx":"matlab",".jl":"julia",".nim":"nim",".cr":"crystal",".v":"v",".wasm":"webassembly",".wat":"webassembly",".graphql":"graphql",".gql":"graphql",".sol":"solidity",".move":"move",".mo":"motoko",".toml":"toml",".yaml":"yaml",".yml":"yaml",".json":"json",".xml":"xml",".md":"markdown"},Di={next:"next.js",react:"react","react-dom":"react",vue:"vue",nuxt:"nuxt","@angular/core":"angular",svelte:"svelte","@sveltejs/kit":"sveltekit",express:"express",fastify:"fastify",hono:"hono",koa:"koa",nestjs:"nestjs","@nestjs/core":"nestjs",remix:"remix","@remix-run/react":"remix",astro:"astro",gatsby:"gatsby",electron:"electron",tauri:"tauri","react-native":"react-native",expo:"expo","@trpc/server":"trpc","@trpc/client":"trpc"},Ai={pg:"postgresql",postgres:"postgresql","pg-promise":"postgresql",mysql2:"mysql",mysql:"mysql","@mysql/xdevapi":"mysql","better-sqlite3":"sqlite",sqlite3:"sqlite","sql.js":"sqlite",mongodb:"mongodb",mongoose:"mongodb",mongoodb:"mongodb",redis:"redis",ioredis:"redis","@redis/client":"redis","redis-mock":"redis","cassandra-driver":"cassandra","express-cassandra":"cassandra",elasticsearch:"elasticsearch","@elastic/elasticsearch":"elasticsearch","@elastic/elasticsearch-ng":"elasticsearch","neo4j-driver":"neo4j",neo4j:"neo4j",couchbase:"couchbase",ottoman:"couchbase",rethinkdb:"rethinkdb",rethinkdbdash:"rethinkdb",level:"leveldb",levelup:"leveldb","aws-sdk":"dynamodb","@aws-sdk/client-dynamodb":"dynamodb",mssql:"mssql",tedious:"mssql",msnodesqlv8:"mssql",oracledb:"oracle","node-oracledb":"oracle","pg-copy-streams":"postgresql","pg-pool":"postgresql","pg-native":"postgresql"," knex":"knex",minio:"minio",firebird:"firebird","node-firebird":"firebird","hdb-pool":"sap-hana","snowflake-sdk":"snowflake","cassandra-client":"scylladb"},Oi={prisma:"prisma","@prisma/client":"prisma","drizzle-orm":"drizzle",typeorm:"typeorm",sequelize:"sequelize","@mikro-orm/core":"mikro-orm",knex:"knex",mongoose:"mongoose"},Ii={tailwindcss:"tailwindcss","styled-components":"styled-components","@emotion/react":"emotion",sass:"sass","@chakra-ui/react":"chakra-ui","@mui/material":"material-ui","@mantine/core":"mantine"},Ni={vite:"vite",webpack:"webpack",esbuild:"esbuild",tsup:"tsup",rollup:"rollup",parcel:"parcel",turbopack:"turbopack",unbuild:"unbuild",pkgroll:"pkgroll","@swc/core":"swc",snowpack:"snowpack"},ps={name:"stack",category:"stack",async detect(e){let t=Li(e),s=await Fi(e),n=Mi(s),i=Ti(e,s),o=Hi(s,Ai),r=$t(s,Oi),a=$t(s,Ii),c=$t(s,Ni);if(r==="prisma"){let j=await Gi(e);j&&!o.includes(j)&&o.unshift(j)}let l=await Ui(e);for(let j of l)o.includes(j)||o.push(j);let[p,d,f,m,h,v,x]=await Promise.all([zi(e),Yi(e),Xi(e),Zi(e),eo(e),so(e),no(e)]);return p&&n.push(p),d&&n.push(d),f&&n.push(f),m&&n.push(m),h&&n.push(h),v&&n.push(v),x&&n.push(x),{languages:[...new Set(t)],frameworks:[...new Set(n)],package_manager:i,database:o.length>1?o.join(" + "):o[0]||null,orm:r,styling:a,build_tool:c}}}});async function oo(e){let t=await e.readFile("package.json");if(!t)return Se();try{let n=JSON.parse(t).scripts||{},i="npm run";e.fileExists("pnpm-lock.yaml")?i="pnpm":e.fileExists("yarn.lock")?i="yarn":(e.fileExists("bun.lockb")||e.fileExists("bun.lock"))&&(i="bun run");let o={dev:Ee(n,["dev","start","serve"],i),build:Ee(n,["build","compile"],i),test:Ee(n,["test","test:unit","test:run"],i),lint:Ee(n,["lint","lint:check"],i),format:Ee(n,["format","fmt","prettier"],i)},r=["typecheck","check","deploy","preview","clean","db:migrate","db:seed","generate","codegen","storybook"];for(let a of r)n[a]&&(o[a]=`${i} ${a}`);return o}catch{return Se()}}function Ee(e,t,s){for(let n of t)if(e[n])return`${s} ${n}`;return null}async function ro(e){let t=await e.readFile("Makefile");if(!t)return Se();let s=new Set;for(let n of t.split(`
|
|
11
|
+
`)){let i=n.match(/^([a-zA-Z_-]+)\s*:/);i&&s.add(i[1])}return{dev:s.has("dev")?"make dev":s.has("run")?"make run":null,build:s.has("build")?"make build":null,test:s.has("test")?"make test":null,lint:s.has("lint")?"make lint":null,format:s.has("format")?"make format":s.has("fmt")?"make fmt":null}}async function ao(e){if(e.fileExists("Cargo.toml"))return{dev:"cargo run",build:"cargo build",test:"cargo test",lint:"cargo clippy",format:"cargo fmt"};if(e.fileExists("go.mod"))return{dev:"go run .",build:"go build .",test:"go test ./...",lint:e.fileExists(".golangci.yml")||e.fileExists(".golangci.yaml")?"golangci-lint run":null,format:"go fmt ./..."};if(e.fileExists("pyproject.toml")||e.fileExists("requirements.txt")||e.fileExists("setup.py")){let s=e.fileExists("poetry.lock")?"poetry run":e.fileExists("Pipfile.lock")?"pipenv run":e.fileExists("uv.lock")?"uv run":"python -m",n=e.files.some(d=>d.includes("pytest")||d.includes("test_"))||e.fileExists("pytest.ini"),i=e.fileExists("ruff.toml")||e.fileExists(".ruff.toml")||e.fileExists("pyproject.toml"),o=e.fileExists("pyproject.toml")||e.fileExists(".black"),r=e.fileExists("mypy.ini")||e.fileExists(".mypy.ini"),a=e.fileExists("manage.py"),c=e.files.some(d=>d.includes("main.py")||d.includes("app.py")),l=null;a?l=`${s} python manage.py runserver`:c?l=`${s} uvicorn main:app --reload`:e.fileExists("vite.config.ts")&&(l=`${s} vite`);let p=null;return e.fileExists("pyproject.toml")&&(p=`${s} build`),{dev:l,build:p,test:n?`${s} pytest`:`${s} unittest`,lint:i?`${s} ruff check .`:r?`${s} mypy .`:null,format:i?`${s} ruff format .`:o?`${s} black .`:null}}if(e.fileExists("pom.xml"))return{dev:"mvn spring-boot:run",build:"mvn compile",test:"mvn test",lint:"mvn checkstyle:check",format:null};if(e.fileExists("build.gradle")||e.fileExists("build.gradle.kts"))return{dev:"./gradlew bootRun",build:"./gradlew build",test:"./gradlew test",lint:"./gradlew checkstyleMain",format:null};if(e.fileExists("build.gradle.kts"))return{dev:"./gradlew run",build:"./gradlew build",test:"./gradlew test",lint:"./gradlew ktlintCheck",format:"./gradlew ktlintFormat"};if(e.files.some(s=>s.endsWith(".csproj")||s.endsWith(".sln")))return{dev:"dotnet run",build:"dotnet build",test:"dotnet test",lint:null,format:"dotnet format"};if(e.fileExists("Gemfile")){let s="bundle exec",n=e.fileExists("bin/rails")||e.files.some(o=>o.includes("config/application.rb")),i=e.fileExists("Rakefile");return{dev:n?`${s} rails server`:null,build:null,test:n?`${s} rails test`:i?`${s} rake test`:`${s} rspec`,lint:e.fileExists(".rubocop.yml")?`${s} rubocop`:null,format:e.fileExists(".rubocop.yml")?`${s} rubocop -a`:null}}if(e.fileExists("composer.json")){let s="composer",n=e.fileExists("artisan")||e.files.some(o=>o.includes("config/app.php")),i=e.files.some(o=>o.includes("symfony"));return{dev:n?"php artisan serve":i?"symfony server:start":"php -S localhost:8000",build:`${s} install`,test:n?"php artisan test":`${s} test`,lint:e.fileExists("phpunit.xml")||e.fileExists("phpunit.xml.dist")?`${s} phpunit`:null,format:e.fileExists(".php-cs-fixer.php")?"vendor/bin/php-cs-fixer fix":null}}if(e.fileExists("Package.swift")||e.files.some(s=>s.endsWith(".xcodeproj")))return{dev:"swift run",build:"swift build",test:"swift test",lint:null,format:"swift format ."};if(e.fileExists("pubspec.yaml"))return{dev:e.fileExists("lib/main.dart")?"flutter run":"dart run",build:e.fileExists("lib/main.dart")?"flutter build":"dart compile exe",test:"flutter test",lint:"flutter analyze",format:"dart format ."};if(e.fileExists("mix.exs"))return{dev:"mix phx.server",build:"mix compile",test:"mix test",lint:"mix format --check-formatted",format:"mix format"};if(e.fileExists("build.sbt"))return{dev:"sbt run",build:"sbt compile",test:"sbt test",lint:"sbt scalafmtCheck",format:"sbt scalafmt"};if(e.fileExists("CMakeLists.txt"))return{dev:null,build:"cmake --build build",test:"ctest --test-dir build",lint:null,format:null};let t=e.fileExists("Cargo.toml")||e.fileExists("go.mod")||e.fileExists("pyproject.toml")||e.fileExists("requirements.txt")||e.fileExists("setup.py")||e.fileExists("pom.xml")||e.fileExists("build.gradle")||e.fileExists("build.gradle.kts")||e.fileExists("Gemfile")||e.fileExists("composer.json")||e.fileExists("Package.swift")||e.fileExists("pubspec.yaml")||e.fileExists("mix.exs")||e.fileExists("build.sbt")||e.fileExists("CMakeLists.txt");return e.fileExists("Makefile")&&!t?Se():e.files.some(s=>s.endsWith(".sh"))?{dev:null,build:null,test:null,lint:"shellcheck *.sh",format:"shfmt -w *.sh"}:Se()}function Se(){return{dev:null,build:null,test:null,lint:null,format:null}}var ms,gs=D(()=>{"use strict";ms={name:"commands",category:"commands",async detect(e){let t=await oo(e);if(Object.values(t).some(Boolean))return t;let s=await ro(e);return Object.values(s).some(Boolean)?s:await ao(e)}}});function Ze(e,t){return e.filter(s=>t.has(s)).sort()}function uo(e){let t=[],s=[],n=e.match(/\[project\]\s[\s\S]*?dependencies\s*=\s*\[([\s\S]*?)\]/);n&&t.push(...bs(n[1]));let i=e.match(/\[project\.optional-dependencies\]\s*[\s\S]*?(?=\n\[|$)/);if(i){let a=i[0].matchAll(/\w+\s*=\s*\[([\s\S]*?)\]/g);for(let c of a)s.push(...bs(c[1]))}let o=e.match(/\[tool\.poetry\.dependencies\]\s*\n([\s\S]*?)(?=\n\[|$)/);if(o){let a=et(o[1]);t.push(...a.filter(c=>c!=="python"))}let r=e.match(/\[tool\.poetry\.(?:group\.dev\.|dev-)dependencies\]\s*\n([\s\S]*?)(?=\n\[|$)/);return r&&s.push(...et(r[1])),t.length===0&&s.length===0?null:{direct:t,dev:s}}function bs(e){let t=[],s=e.matchAll(/"([^"]+)"|'([^']+)'/g);for(let n of s){let o=(n[1]||n[2]).split(/[>=<!;\[]/)[0].trim().toLowerCase();o&&t.push(o)}return t}function et(e){let t=[];for(let s of e.split(`
|
|
12
|
+
`)){let n=s.trim();if(!n||n.startsWith("#"))continue;let i=n.match(/^([a-zA-Z0-9_-]+)\s*=/);i&&t.push(i[1].toLowerCase())}return t}function po(e){let t=[];for(let s of e.split(`
|
|
13
|
+
`)){let n=s.trim();if(!n||n.startsWith("#")||n.startsWith("-"))continue;let i=n.split(/[>=<!;\[]/)[0].trim().toLowerCase();i&&t.push(i)}return t}function fo(e){let t=[],s=[],n=e.match(/\[dependencies\]\s*\n([\s\S]*?)(?=\n\[|$)/);n&&t.push(...et(n[1]));let i=e.match(/\[dev-dependencies\]\s*\n([\s\S]*?)(?=\n\[|$)/);return i&&s.push(...et(i[1])),{direct:t,dev:s}}function mo(e){let t=[],s=e.matchAll(/require\s*\(([\s\S]*?)\)/g);for(let i of s)for(let o of i[1].split(`
|
|
14
|
+
`)){let r=o.trim();if(!r||r.startsWith("//"))continue;let a=r.split(/\s+/);a[0]&&t.push(a[0])}let n=e.matchAll(/^require\s+(\S+)[ \t]+\S+/gm);for(let i of n)t.push(i[1]);return t}async function go(e){let t=await e.readFile("Gemfile");if(!t)return{direct_count:0,dev_count:0,notable:[]};let s=[],n=[];for(let i of t.split(`
|
|
15
|
+
`)){let o=i.match(/gem\s+["']([^"']+)["']/);o&&(s.push(o[1]),he.has(o[1])&&n.push(o[1]))}return{direct_count:s.length,dev_count:0,notable:[...new Set(n)].sort()}}async function ho(e){let t=await e.readFile("composer.json");if(!t)return{direct_count:0,dev_count:0,notable:[]};try{let s=JSON.parse(t),n=s.require||{},i=s["require-dev"]||{},o={...n,...i},r=Object.keys(o).filter(a=>he.has(a)).sort();return{direct_count:Object.keys(n).length,dev_count:Object.keys(i).length,notable:r}}catch{return{direct_count:0,dev_count:0,notable:[]}}}async function bo(e){let t=await e.readFile("pom.xml"),s=await e.readFile("build.gradle"),n=await e.readFile("build.gradle.kts"),i=(t||"")+`
|
|
16
16
|
`+(s||"")+`
|
|
17
|
-
`+(n||"");if(!i.trim())return{direct_count:0,dev_count:0,notable:[]};let o=[],r=[],a=/<artifactId>([^<]+)<\/artifactId>/g,c;for(;(c=a.exec(i))!==null;)o.push(c[1]),
|
|
18
|
-
`),i="";for(let o of n){let r=o.trim();if(!r)continue;if(r.startsWith("#")){i+=(i?" ":"")+r.slice(1).trim();continue}let a=r.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(a){let[,c,
|
|
19
|
-
`).filter(Boolean):[]}async function
|
|
20
|
-
`).map(s=>s.replace(/^\s*\d+\s+/,"").trim()).filter(Boolean):[]}async function Ki(e){return(await e.exec("git status --porcelain 2>/dev/null")).length>0}var ns,is=C(()=>{"use strict";ns={name:"git",category:"git",async detect(e){let[t,s,n]=await Promise.all([Ji(e),Wi(e),Ki(e)]);return{recent_commits:t,last_committers:s,uncommitted_changes:n}}}});async function zi(e){if(e.glob("vitest.config.*").length>0)return"vitest";if(e.glob("jest.config.*").length>0)return"jest";if(e.fileExists(".mocharc.yml")||e.fileExists(".mocharc.json"))return"mocha";if(e.glob("playwright.config.*").length>0)return"playwright";if(e.glob("cypress.config.*").length>0)return"cypress";let t=await e.readFile("package.json");if(t)try{let s=JSON.parse(t),n={...s.dependencies||{},...s.devDependencies||{}},o=(s.scripts||{}).test||"";if(n.vitest||o.includes("vitest"))return"vitest";if(n.jest||o.includes("jest"))return"jest";if(n.mocha||o.includes("mocha"))return"mocha";if(n["@playwright/test"]||o.includes("playwright"))return"playwright";if(n.cypress)return"cypress";if(n.ava)return"ava";if(n.tap)return"tap"}catch{}if(e.fileExists("pytest.ini")||e.fileExists("pyproject.toml")||e.fileExists("setup.cfg")||e.fileExists("tox.ini")){let s=await e.readFile("pyproject.toml"),n=await e.readFile("setup.cfg"),i=await e.readFile("pytest.ini");if(s?.includes("pytest")||n?.includes("pytest")||i||e.files.some(o=>o.includes("test_")||o.includes("_test.py")))return"pytest";if(s?.includes("unittest")||n?.includes("unittest"))return"unittest";if(s?.includes("nose"))return"nose"}if(e.files.some(s=>s.endsWith("_test.go")))return"go test";if(e.files.some(s=>s.includes("/tests/")||s.startsWith("tests/")||s.endsWith("tests.rs")||s.match(/mod\s+tests/)))return"cargo test";if(e.fileExists("spec/spec_helper.rb")||e.fileExists(".rspec")||e.files.some(s=>s.includes("/spec/")&&s.endsWith("_spec.rb")))return"rspec";if(e.fileExists("test/minitest_helper.rb"))return"minitest";if(e.files.some(s=>s.endsWith("Test.java")||s.endsWith("Tests.java")))return"junit";if(e.fileExists("pom.xml")){let s=await e.readFile("pom.xml");if(s?.includes("junit")||s?.includes("testng"))return s?.includes("testng")?"testng":"junit"}if(e.fileExists("phpunit.xml")||e.fileExists("phpunit.xml.dist")||e.files.some(s=>s.includes("tests/")&&s.endsWith(".php")))return"phpunit";if(e.files.some(s=>s.endsWith("Test.cs")||s.endsWith("Tests.cs")))return"nunit";if(e.fileExists("build.sbt")){let s=await e.readFile("build.sbt");if(s?.includes("scalatest"))return"scalatest";if(s?.includes("specs2"))return"specs2"}return e.files.some(s=>s.endsWith("Tests.swift")||s.endsWith("XCTest.swift"))?"xctest":null}async function Vi(e){if(e.fileExists("eslint.config.js")||e.fileExists("eslint.config.mjs")||e.fileExists("eslint.config.ts")||e.glob(".eslintrc*").length>0)return"eslint";if(e.fileExists("biome.json")||e.fileExists("biome.jsonc"))return"biome";if(e.fileExists("ruff.toml")||e.fileExists(".ruff.toml"))return"ruff";if(e.fileExists(".pylintrc")||e.fileExists("pylintrc"))return"pylint";if(e.fileExists(".flake8")||e.fileExists("setup.cfg")||e.fileExists(".flake8rc"))return"flake8";if(e.fileExists(".golangci.yml")||e.fileExists(".golangci.yaml")||e.fileExists(".golangci-lint.yml"))return"golangci-lint";if(e.fileExists("clippy.toml"))return"clippy";if(e.fileExists(".rubocop.yml")||e.fileExists(".rubocop.yaml"))return"rubocop";if(e.fileExists(".php_cs")||e.fileExists("phpstan.neon")||e.fileExists("phpunit.xml"))return"php-cs-fixer";if(e.fileExists("psalm.xml"))return"psalm";if(e.fileExists(".swiftlint.yml")||e.fileExists(".swiftlint.yaml"))return"swiftlint";if(e.fileExists(".kotlinlint.xml"))return"ktlint";if(e.fileExists("detekt.yml")||e.fileExists("detekt.yaml"))return"detekt";if(e.fileExists("checkstyle.xml"))return"checkstyle";if(e.fileExists("pmd.xml"))return"pmd";if(e.fileExists(".scalafix.conf"))return"scalafix";let t=await e.readFile("pyproject.toml");if(t){if(t.includes("ruff"))return"ruff";if(t.includes("pylint"))return"pylint";if(t.includes("flake8"))return"flake8";if(t.includes("mypy"))return"mypy";if(t.includes("black"))return"black"}let s=await e.readFile("package.json");if(s)try{let i=JSON.parse(s),o={...i.dependencies||{},...i.devDependencies||{}},a=(i.scripts||{}).lint||"";if(o.eslint||a.includes("eslint"))return"eslint";if(o["@biomejs/biome"]||a.includes("biome"))return"biome";if(o.oxlint||a.includes("oxlint"))return"oxlint";if(o.standard)return"standard";if(o.xo)return"xo";if(o["@typescript-eslint/eslint-plugin"])return"eslint";if(o.dprint)return"dprint"}catch{}return e.fileExists("golangci-lint.yml")||e.fileExists(".golangci.yml")?"golangci-lint":(await e.readFile("Cargo.toml"))?.includes("clippy")?"clippy":e.fileExists(".rubocop.yml")?"rubocop":e.fileExists("phpstan.neon")?"phpstan":e.fileExists("ecs.php")||e.fileExists("easy-coding-standard.yml")?"ecs":null}async function Qi(e){if(e.glob(".prettierrc*").length>0||e.fileExists("prettier.config.js")||e.fileExists("prettier.config.mjs")||e.fileExists("prettier.config.cjs")||e.fileExists("prettier.config.ts"))return"prettier";if(e.fileExists("biome.json")||e.fileExists("biome.jsonc"))return"biome";if(e.fileExists("ruff.toml")||e.fileExists(".ruff.toml"))return"ruff";if(e.fileExists("rustfmt.toml")||e.fileExists(".rustfmt.toml"))return"rustfmt";if(e.fileExists("dprint.json")||e.fileExists("dprint.jsonc"))return"dprint";if(e.fileExists(".editorconfig"))return"editorconfig";if(e.fileExists(".gofmt")||e.fileExists("gofmt.toml"))return"gofmt";if(e.fileExists(".scalafmt.conf"))return"scalafmt";if(e.fileExists(".black")||e.fileExists("pyproject.toml"))return"black";if(e.fileExists(".isort.cfg")||e.fileExists("pyproject.toml"))return"isort";if(e.fileExists(".swiftformat"))return"swiftformat";if(e.fileExists(".php-cs-fixer.php")||e.fileExists(".php-cs-fixer.dist.php"))return"php-cs-fixer";if(e.fileExists(".rubocop.yml"))return"rubocop";if(e.fileExists("prettier.config.ts")||e.fileExists(".prettierignore"))return"prettier";let t=await e.readFile("pyproject.toml");if(t){if(t.includes("black"))return"black";if(t.includes("isort"))return"isort";if(t.includes("autopep8"))return"autopep8";if(t.includes("yapf"))return"yapf"}let s=await e.readFile("package.json");if(s)try{let n=JSON.parse(s),i={...n.dependencies||{},...n.devDependencies||{}},o=n.scripts||{},r=(o.format||"")+(o.fmt||"");if(i.prettier||r.includes("prettier"))return"prettier";if(i["@biomejs/biome"]||r.includes("biome"))return"biome";if(i.dprint)return"dprint"}catch{}return e.fileExists(".gofmtrc")||e.fileExists("gofmt.toml")?"gofmt":e.fileExists("rustfmt.toml")?"rustfmt":e.fileExists(".rubocop.yml")?"rubocop":e.fileExists(".swiftformat")?"swiftformat":e.fileExists(".scalafmt.conf")?"scalafmt":null}function Yi(e){return e.files.some(t=>t.startsWith(".github/workflows/"))?"github-actions":e.fileExists(".gitlab-ci.yml")||e.fileExists(".gitlab-ci.yaml")?"gitlab-ci":e.fileExists("Jenkinsfile")||e.fileExists("Jenkinsfile")?"jenkins":e.files.some(t=>t.startsWith(".circleci/"))?"circleci":e.fileExists("bitbucket-pipelines.yml")?"bitbucket-pipelines":e.fileExists(".travis.yml")?"travis-ci":e.fileExists("azure-pipelines.yml")||e.fileExists("azure-pipelines.yaml")?"azure-pipelines":e.fileExists("buildspec.yml")?"aws-codebuild":e.fileExists("cloudbuild.yaml")||e.fileExists("cloudbuild.yml")?"google-cloud-build":e.fileExists(".drone.yml")?"drone-ci":e.fileExists("workflow.yml")?"gsuite-actions":e.fileExists("now.json")||e.fileExists(".vercelignore")?"vercel":e.fileExists("netlify.toml")?"netlify":e.fileExists(".github/workflows/ci.yml")||e.fileExists(".github/workflows/cd.yml")?"github-actions":e.fileExists("procfile")||e.fileExists("Procfile")?"heroku":e.fileExists("appveyor.yml")?"appveyor":e.fileExists("codeship-services.yml")||e.fileExists("codeship-steps.yml")?"codeship":e.fileExists("semantic.yml")?"semantic-release":e.fileExists(".rerun.yaml")||e.fileExists(".rerun.yml")?"rerun":e.fileExists("woodpecker.yml")?"woodpecker-ci":e.fileExists(".forgejo")?"forgejo":null}function Xi(e){return!!(e.files.some(t=>t.startsWith(".husky/"))||e.fileExists(".pre-commit-config.yaml")||e.fileExists(".pre-commit-config.yml")||e.fileExists(".lintstagedrc")||e.fileExists("lint-staged.config.js")||e.fileExists("lint-staged.config.mjs")||e.fileExists("lint-staged.config.ts")||e.fileExists("lefthook.yml")||e.fileExists("lefthook.yaml")||e.fileExists("lefthook-local.yml")||e.fileExists(".git/hooks/pre-commit")||e.fileExists(".simple-git-hooks.cjs")||e.fileExists(".simple-git-hooks.js")||e.fileExists(".yorkielerc")||e.fileExists(".yorkie")||e.fileExists(".huskyrc")||e.fileExists(".huskyrc.json")||e.fileExists(".huskyrc.js")||e.fileExists(".pre-commit-hook.json"))}var os,rs=C(()=>{"use strict";os={name:"quality",category:"quality",async detect(e){let[t,s,n]=await Promise.all([zi(e),Vi(e),Qi(e)]);return{test_framework:t,linter:s,formatter:n,ci:Yi(e),pre_commit_hooks:Xi(e)}}}});function Zi(e){return e.files.some(t=>t.match(/^(src\/)?app\/layout\.(tsx?|jsx?)$/))?"app-router":e.files.some(t=>t.match(/^(src\/)?pages\/_app\./))?"pages-router":e.files.some(t=>t.includes("/controllers/"))&&e.files.some(t=>t.includes("/models/"))?"mvc":e.files.some(t=>t.startsWith("src/features/"))?"feature-sliced":e.files.some(t=>t.startsWith("src/modules/"))?"modular":e.files.some(t=>t.includes("/services/"))&&e.files.some(t=>t.includes("/repositories/"))?"layered":e.files.some(t=>t.startsWith("src/routes/"))?"file-based-routing":e.files.some(t=>t.startsWith("src/commands/")||t.startsWith("cmd/"))?"command-based":e.files.some(t=>t.startsWith("src/detectors/")||t.startsWith("src/plugins/"))?"plugin-based":e.files.some(t=>t.includes("/domain/"))&&e.files.some(t=>t.includes("/infra/")||t.includes("/infrastructure/"))?"hexagonal":e.files.some(t=>t.includes("/services/"))&&e.files.some(t=>t.includes("/handlers/")||t.includes("/controllers/"))?"layered":e.files.some(t=>t.match(/^internal\/.+\/.+/))?"package-per-feature":null}async function eo(e){let t=await e.readFile("package.json");if(!t)return null;try{let s=JSON.parse(t),n={...s.dependencies||{},...s.devDependencies||{}},i=[];return n.zustand&&i.push("zustand"),(n["@reduxjs/toolkit"]||n.redux)&&i.push("redux"),n.mobx&&i.push("mobx"),n.jotai&&i.push("jotai"),n.recoil&&i.push("recoil"),n.pinia&&i.push("pinia"),n.vuex&&i.push("vuex"),n["@tanstack/react-query"]&&i.push("react-query"),n["@tanstack/vue-query"]&&i.push("vue-query"),n.swr&&i.push("swr"),i.length>0?i.join(" + "):null}catch{return null}}async function to(e){let t=await e.readFile("package.json"),s=[];if(t)try{let n=JSON.parse(t),i={...n.dependencies||{},...n.devDependencies||{}};(i["@trpc/server"]||i["@trpc/client"])&&s.push("trpc"),(i.graphql||i["@apollo/server"])&&s.push("graphql")}catch{}return e.glob("**/*.proto").length>0&&s.push("grpc"),e.files.some(n=>n.match(/\/api\/.*route\.(ts|js)$/))&&s.push("route-handlers"),e.files.some(n=>n.includes("/routes/")||n.includes("/controllers/"))&&s.push("rest"),e.files.some(n=>n.match(/\/actions?\.(ts|js)$/))&&s.push("server-actions"),s.length>0?s.join(" + "):null}function so(e){let t={},s=new Set;for(let i of e.files){let o=i.match(/^src\/([^/]+)\//);o&&s.add(o[1])}for(let i of s){let o=as[i];o&&(t[`src/${i}/`]=o)}let n=new Set;for(let i of e.files){let o=i.match(/^([^/]+)\//);o&&!o[1].startsWith(".")&&o[1]!=="src"&&o[1]!=="node_modules"&&n.add(o[1])}for(let i of n){let o=as[i];o&&!t[`src/${i}/`]&&(t[`${i}/`]=o)}return t}var as,cs,ls=C(()=>{"use strict";as={app:"routes and pages",api:"API routes",pages:"page components",components:"reusable UI components",lib:"shared utilities",utils:"utility functions",helpers:"helper functions",hooks:"React hooks",services:"business logic / services",models:"data models",controllers:"request handlers",middleware:"middleware",routes:"routing",store:"state management",stores:"state stores",types:"type definitions",interfaces:"interface definitions",schemas:"validation schemas",config:"configuration",constants:"constants",assets:"static assets",styles:"stylesheets",tests:"test files",__tests__:"test files",test:"test files",spec:"test specifications",features:"feature modules",modules:"application modules",plugins:"plugin system",providers:"context providers",contexts:"React contexts",commands:"CLI commands",cmd:"CLI commands",cli:"CLI interface",detectors:"detection / analysis modules",scanners:"scanning modules",scanner:"scanning engine",integrations:"third-party integrations",adapters:"adapters / connectors",handlers:"event / request handlers",resolvers:"GraphQL resolvers",guards:"auth / route guards",pipes:"data transform pipes",decorators:"decorators",validators:"validation logic",migrations:"database migrations",seeds:"database seed data",fixtures:"test fixtures",mocks:"test mocks",stubs:"test stubs",github:"GitHub integration",git:"git integration",mcp:"MCP server / protocol",server:"HTTP / API server",client:"client-side code",core:"core business logic",domain:"domain logic",infra:"infrastructure",db:"database layer",database:"database layer",auth:"authentication / authorization",email:"email handling",notifications:"notification system",jobs:"background jobs / workers",workers:"background workers",queues:"job / message queues",events:"event system",shared:"shared / cross-cutting code",common:"common utilities",internal:"internal modules",pkg:"packages / library code",proto:"protobuf definitions",generated:"auto-generated code",scripts:"build / utility scripts",tools:"development tools",docs:"documentation"},cs={name:"patterns",category:"patterns",async detect(e){return{architecture:Zi(e),state_management:await eo(e),api_style:await to(e),key_modules:so(e)}}}});async function no(e){let t=["openapi.json","openapi.yaml","openapi.yml","swagger.json","swagger.yaml","swagger.yml","api-specs/openapi.json","api-specs/openapi.yaml","docs/openapi.json","docs/openapi.yaml","spec/openapi.json","spec/openapi.yaml","api/openapi.json","api/openapi.yaml"];for(let s of t)if(e.fileExists(s)){let n=await e.readFile(s);if(n)try{let i=JSON.parse(n);if(i.openapi||i.swagger)return{version:i.openapi||i.swagger,title:i.info?.title||null,file:s,type:i.openapi?"openapi":"swagger"}}catch{if(n.includes("openapi:")||n.includes("swagger:"))return{version:ot(n,"openapi")||ot(n,"swagger"),title:ot(n,"title"),file:s,type:n.includes("openapi:")?"openapi":"swagger"}}}return null}async function io(e){let t=e.files.filter(i=>i.endsWith(".graphql")||i.endsWith(".gql")||i.includes("/graphql/")||i.includes("/schema/"));if(t.length===0)return null;let s=[],n=[];for(let i of t){let o=await e.readFile(i);o&&((o.includes("type Query")||o.includes("type Mutation")||o.includes("type Subscription"))&&s.push(i),(o.includes("Query:")||o.includes("Mutation:")||o.includes("resolver"))&&n.push(i))}return s.length===0&&n.length===0?null:{schema_files:s,resolver_files:n,total_files:t.length}}async function oo(e){let t=e.files.filter(n=>n.endsWith(".proto"));if(t.length===0)return null;let s=[];for(let n of t){let i=await e.readFile(n);i&&i.includes("service ")&&s.push(n)}return{proto_files:t,service_definitions:s}}async function ro(e){let t=e.files.filter(n=>n.includes("postman")&&(n.endsWith(".json")||n.endsWith(".json.backup")));if(t.length===0)return null;let s=[];for(let n of t){let i=await e.readFile(n);if(i)try{let o=JSON.parse(i);o.info?.schema?.includes("postman")&&s.push({file:n,name:o.info?.name||null})}catch{}}return s.length===0?null:{collections:s}}function ot(e,t){let s=new RegExp(`^${t}:\\s*(.+)$`,"m"),n=e.match(s);return n?n[1].trim():null}var us,ds=C(()=>{"use strict";us={name:"api-docs",category:"config",async detect(e){let[t,s,n,i]=await Promise.all([no(e),io(e),oo(e),ro(e)]);return{openapi:t,graphql:s,grpc:n,postman:i}}}});var rt,ps=C(()=>{"use strict";Ht();Ut();Jt();zt();Qt();es();ss();is();rs();ls();ds();rt=[Tt,Gt,Bt,Kt,Vt,Zt,ts,ns,os,cs,us]});import{execFile as fs}from"child_process";async function be(e,t,s={}){return new Promise(n=>{let i=["api","graphql","-f",`query=${t}`,"-H","Accept: application/vnd.github.v3+json"];for(let[o,r]of Object.entries(s))i.push("-f",`${o}=${JSON.stringify(r)}`);fs("gh",i,{cwd:e,timeout:3e4},(o,r,a)=>{if(o){n(null);return}try{let c=JSON.parse(r.trim());if(c.errors&&c.errors.length>0){n(null);return}n(c.data||null)}catch{n(null)}})})}function fo(e){let t=[/github\.com[:/]([^/]+)\/(.+?)(\.git)?$/,/github\.com[:/]([^/]+)\/(.+)$/];for(let s of t){let n=e.match(s);if(n)return{owner:n[1],repo:n[2].replace(/\.git$/,"")}}return null}function mo(e){let t=e.labels?.nodes||[],s=e.assignees?.nodes||[],n=e.milestone,i=e.reactions||{},o=e.comments,r=e.timelineItems;return{number:e.number,title:e.title,state:e.state?.toLowerCase()==="open"?"open":"closed",url:e.url||void 0,labels:t.map(a=>a.name),assignee:s[0]?.login||null,milestone:n?.title||null,created_at:e.createdAt,updated_at:e.updatedAt,comments_count:o?.totalCount||0,reactions:{thumbs_up:i.thumbsUp||0,thumbs_down:i.thumbsDown||0,laugh:i.laugh||0,hooray:i.hooray||0,confused:i.confused||0,heart:i.heart||0,rocket:i.rocket||0,eyes:i.eyes||0},timeline_events:r?.totalCount||0}}function go(e){let t=e.labels?.nodes||[],s=e.reviewRequests?.nodes||[],n=e.author,i=e.statusCheckRollup,o=e.comments,r;if(i?.state){let u=i.state.toLowerCase();u==="success"||u==="completed"?r="passing":u==="failure"||u==="error"?r="failing":r="pending"}let a=e.mergeable==="MERGEABLE",c=e.mergeable==="CONFLICTING";return{number:e.number,title:e.title,state:(e.state||"open").toLowerCase(),url:e.url||void 0,author:n?.login||"unknown",branch:e.headRefName||"",labels:t.map(u=>u.name),reviewers:s.map(u=>u.requestedReviewer?.login||"").filter(Boolean),created_at:e.createdAt,updated_at:e.updatedAt,checks_status:r,mergeable:a,merge_conflicts:c,additions:e.additions||0,deletions:e.deletions||0,comments_count:o?.totalCount||0,review_decision:e.review_decision?.toLowerCase()==="approved"?"approved":e.review_decision?.toLowerCase()==="changes_requested"?"changes_requested":e.review_decision?.toLowerCase()==="review_required"?"review_required":null}}async function ms(e,t,s={}){let{includeIssues:n=!0,includePRs:i=!0,includeMilestones:o=!0,includeReleases:r=!0,includeProjects:a=!0,limit:c=50}=s,u=fo(t);if(!u)return{};let{owner:g,repo:f}=u,p={};if(n)try{let d=await be(e,ao,{owner:g,repo:f,limit:c});d?.repository?.issues?.nodes&&(p.issues=d.repository.issues.nodes.map(mo))}catch{}if(i)try{let d=await be(e,co,{owner:g,repo:f,limit:Math.min(c,30)});d?.repository?.pullRequests?.nodes&&(p.pull_requests=d.repository.pullRequests.nodes.map(go))}catch{}if(o)try{let d=await be(e,lo,{owner:g,repo:f});d?.repository?.milestones?.nodes&&(p.milestones=d.repository.milestones.nodes.map(m=>{let E=m.issues?.nodes||[],D=m.closedIssues?.totalCount||0,_=m.issues?.totalCount||E.length,S=_-D;return{title:m.title,description:m.description||"",due_date:m.dueOn||null,progress:{open:S,closed:D,percent:_>0?Math.round(D/_*100):0},issues:E.map(q=>q.number)}}))}catch{}if(r)try{let d=await be(e,uo,{owner:g,repo:f,limit:10});d?.repository?.releases?.nodes&&(p.releases=d.repository.releases.nodes.map(m=>({tag_name:m.tagName,name:m.name||m.tagName,created_at:m.createdAt,url:m.url,author:m.author?.login||"unknown",prerelease:!!m.isPrerelease})))}catch{}if(a)try{let d=await be(e,po,{owner:g,repo:f});d?.repository?.projectsV2?.nodes&&(p.project_boards=d.repository.projectsV2.nodes.filter(m=>m!==null).map(m=>{let E=m.columns?.nodes||[],D=m.items?.totalCount||0;return{number:m.number,title:m.title,state:(m.state||"open").toLowerCase(),url:m.url,columns:E.map(_=>({name:_.name,cards_count:D}))}}))}catch{}return p}async function gs(e){return new Promise(t=>{fs("gh",["--version"],{cwd:e,timeout:5e3},(s,n)=>{if(s){t(!1);return}let i=n.match(/gh version (\d+)\.(\d+)/);if(i){let o=parseInt(i[1],10),r=parseInt(i[2],10);t(o>2||o===2&&r>=0)}else t(!1)})})}var ao,co,lo,uo,po,hs=C(()=>{"use strict";ao=`
|
|
17
|
+
`+(n||"");if(!i.trim())return{direct_count:0,dev_count:0,notable:[]};let o=[],r=[],a=/<artifactId>([^<]+)<\/artifactId>/g,c;for(;(c=a.exec(i))!==null;)o.push(c[1]),he.has(c[1])&&r.push(c[1]);let l=/(?:implementation|compile|api)\s+['"]([^:'"]+)/g;for(;(c=l.exec(i))!==null;){let p=c[1].split(":").pop();p&&(o.push(p),he.has(p)&&r.push(p))}return{direct_count:[...new Set(o)].length,dev_count:0,notable:[...new Set(r)].sort()}}async function yo(e){let t=e.files.filter(i=>i.endsWith(".csproj"));if(t.length===0)return{direct_count:0,dev_count:0,notable:[]};let s=[],n=[];for(let i of t){let o=await e.readFile(i),r=/<PackageReference\s+Include="([^"]+)"/g,a;for(;(a=r.exec(o))!==null;){s.push(a[1]);let c=a[1].split(".")[0].toLowerCase();he.has(c)&&n.push(a[1])}}return{direct_count:[...new Set(s)].length,dev_count:0,notable:[...new Set(n)].sort()}}function ko(e){return e.fileExists("pnpm-lock.yaml")?"pnpm-lock.yaml":e.fileExists("yarn.lock")?"yarn.lock":e.fileExists("package-lock.json")?"package-lock.json":e.fileExists("bun.lockb")||e.fileExists("bun.lock")?"bun.lock":e.fileExists("Cargo.lock")?"Cargo.lock":e.fileExists("poetry.lock")?"poetry.lock":e.fileExists("Pipfile.lock")?"Pipfile.lock":e.fileExists("uv.lock")?"uv.lock":e.fileExists("go.sum")?"go.sum":e.fileExists("Gemfile.lock")?"Gemfile.lock":e.fileExists("composer.lock")?"composer.lock":e.fileExists(".mvn/jvm.config")?"maven":e.fileExists(".gradle")?"gradle":e.fileExists("Package.resolved")?"swift":e.fileExists("pubspec.lock")?"pubspec.lock":e.fileExists("mix.lock")?"mix.lock":e.fileExists("project/target/resolution-cache")?"sbt":e.fileExists("packages.lock.json")?"nuget":null}var he,hs,co,lo,ys,ks=D(()=>{"use strict";he=new Set(["next","react","vue","angular","svelte","nuxt","remix","astro","gatsby","express","fastify","hono","nestjs","koa","solid","solid-js","qwik","prisma","@prisma/client","drizzle-orm","typeorm","sequelize","mongoose","knex","zustand","redux","@reduxjs/toolkit","mobx","jotai","recoil","pinia","vuex","@tanstack/react-query","@swr/core","react-query","zod","joi","yup","ajv","class-validator","@trpc/server","graphql","apollo-server","@apollo/client","graphql-yoga","jest","vitest","mocha","playwright","@playwright/test","cypress","msw","webpack","vite","esbuild","rollup","turbo","nx","tsup","unbuild","pkgroll","tailwindcss","styled-components","@emotion/react","@chakra-ui/react","@mui/material","@mantine/core","next-auth","@auth/core","passport","jsonwebtoken","lucia-auth","@vercel/node","@netlify/functions","serverless","sst","fastapi","django","flask","starlette","tornado","aiohttp","sqlalchemy","alembic","pydantic","typer","click","pytest","black","ruff","mypy","pylint","celery","redis","pymongo","psycopg2","numpy","pandas","torch","tensorflow","scikit-learn","gin-gonic","gorilla/mux","go-chi/chi","labstack/echo","gofiber/fiber","gorm","sqlx","lib/pq","go-redis","testify","stretchr","grpc","protobuf","cobra","actix-web","axum","rocket","warp","tokio","serde","diesel","sqlx","sea-orm","clap","anyhow","thiserror","tracing","rails","sinatra","grape","hanami","roda","activerecord","pg","mysql2","redis","sidekiq","rspec","rubocop","pry","byebug","laravel","symfony","slim","guzzlehttp","illuminate","doctrine/orm","ramsey/uuid","phpunit","mockery","spring-boot","spring-framework","micronaut","quarkus","hibernate","jakarta.persistence","junit","mockito","testng","Microsoft.AspNetCore","EntityFramework","Newtonsoft","NUnit","xUnit","Moq","docker","typescript","kubernetes"]),hs=new Set(["django","flask","fastapi","starlette","tornado","aiohttp","sqlalchemy","alembic","pydantic","celery","redis","pytest","numpy","pandas","scipy","scikit-learn","tensorflow","torch","transformers","langchain","requests","httpx","boto3"]),co=new Set(["serde","tokio","axum","actix-web","rocket","warp","hyper","sqlx","diesel","sea-orm","clap","tracing","anyhow","thiserror","reqwest","tonic","prost"]),lo=new Set(["gin","echo","fiber","chi","mux","gorm","sqlx","cobra","viper","zap","testify","grpc","protobuf","wire"]),ys={name:"dependencies",category:"dependencies",async detect(e){let t=ko(e),s=await e.readFile("package.json");if(s)try{let d=JSON.parse(s),f=d.dependencies||{},m=d.devDependencies||{},h={...f,...m},v=Object.keys(h).filter(x=>he.has(x)).sort();return{direct_count:Object.keys(f).length,dev_count:Object.keys(m).length,lock_file:t,notable:v}}catch{}let n=await e.readFile("pyproject.toml");if(n){let d=uo(n);if(d){let f=Ze([...d.direct,...d.dev],hs);return{direct_count:d.direct.length,dev_count:d.dev.length,lock_file:t,notable:f}}}let i=await e.readFile("requirements.txt");if(i){let d=po(i),f=Ze(d,hs);return{direct_count:d.length,dev_count:0,lock_file:t,notable:f}}let o=await e.readFile("Cargo.toml");if(o){let d=fo(o),f=Ze([...d.direct,...d.dev],co);return{direct_count:d.direct.length,dev_count:d.dev.length,lock_file:t,notable:f}}let r=await e.readFile("go.mod");if(r){let d=mo(r),f=d.map(h=>h.split("/").pop()),m=Ze(f,lo);return{direct_count:d.length,dev_count:0,lock_file:t,notable:m}}let a=await go(e);if(a.direct_count>0)return{...a,lock_file:t};let c=await ho(e);if(c.direct_count>0)return{...c,lock_file:t};let l=await bo(e);if(l.direct_count>0)return{...l,lock_file:t};let p=await yo(e);return p.direct_count>0?{...p,lock_file:t}:{direct_count:0,dev_count:0,lock_file:t,notable:[]}}}});async function $o(e){let t=await e.readFile("package.json");if(!t)return null;try{let s=JSON.parse(t),n={...s.dependencies||{},...s.devDependencies||{}};for(let[i,o]of Object.entries(vo))if(n[i])return o}catch{}return null}async function xo(e){let t={},s=await e.readFile(".env.example");s&&tt(s,t,!1);let n=await e.readFile(".env");n&&tt(n,t,!0);let i=await e.readFile(".env.sample");i&&tt(i,t,!1);let o=await e.readFile(".env.template");return o&&tt(o,t,!1),t}function tt(e,t,s){let n=e.split(`
|
|
18
|
+
`),i="";for(let o of n){let r=o.trim();if(!r)continue;if(r.startsWith("#")){i+=(i?" ":"")+r.slice(1).trim();continue}let a=r.match(/^([A-Z_][A-Z0-9_]*)\s*=\s*(.*)$/);if(a){let[,c,l]=a,p=l==='""'||l==="''"||l==="";t[c]={description:i||void 0,required:s||p},i=""}}}var wo,vo,ws,vs=D(()=>{"use strict";wo=["tsconfig.json","jsconfig.json","tsup.config.ts","tsup.config.js","next.config.js","next.config.mjs","next.config.ts","vite.config.ts","vite.config.js","vite.config.mjs","webpack.config.js","webpack.config.ts","rollup.config.js","rollup.config.mjs","esbuild.config.js","esbuild.config.mjs","turbo.json","nx.json","tailwind.config.js","tailwind.config.ts","tailwind.config.mjs","postcss.config.js","postcss.config.mjs","postcss.config.ts","babel.config.js","babel.config.json",".babelrc","swc.config.json",".swcrc","jest.config.js","jest.config.ts","vitest.config.ts","vitest.config.js","vitest.config.mts","playwright.config.ts","playwright.config.js","cypress.config.ts","cypress.config.js",".prettierrc",".prettierrc.js",".prettierrc.json","prettier.config.js","prettier.config.mjs",".eslintrc.js",".eslintrc.json",".eslintrc.yml","eslint.config.js","eslint.config.mjs","eslint.config.ts","biome.json","biome.jsonc","dprint.json",".editorconfig","docker-compose.yml","docker-compose.yaml","compose.yml","compose.yaml","Dockerfile","fly.toml","render.yaml","vercel.json","netlify.toml","pyproject.toml","setup.cfg","setup.py","tox.ini","ruff.toml",".ruff.toml","go.mod","Cargo.toml","Gemfile","composer.json","Makefile","Taskfile.yml",".nvmrc",".node-version",".python-version",".ruby-version",".tool-versions"],vo={"launchdarkly-node-server-sdk":"launchdarkly","@unleash/proxy-client-react":"unleash",flagsmith:"flagsmith","@growthbook/growthbook-react":"growthbook"},ws={name:"config",category:"config",async detect(e){let t=e.files.filter(o=>o.match(/^\.env(\..+)?$/)||o.match(/^\.env\./)),s=wo.filter(o=>e.fileExists(o)),n=await $o(e),i=await xo(e);return{env_files:t,config_files:s,feature_flags:n,env_vars:i}}}});async function jo(e){let t=await e.exec("git",["log","--oneline","-5","--format=%s"]);return t?t.split(`
|
|
19
|
+
`).filter(Boolean):[]}async function Co(e){let t=await e.exec("git",["shortlog","-sn","--no-merges","-5"]);return t?t.split(`
|
|
20
|
+
`).map(s=>s.replace(/^\s*\d+\s+/,"").trim()).filter(Boolean):[]}async function Eo(e){return(await e.exec("git",["status","--porcelain"])).length>0}var $s,xs=D(()=>{"use strict";$s={name:"git",category:"git",async detect(e){let[t,s,n]=await Promise.all([jo(e),Co(e),Eo(e)]);return{recent_commits:t,last_committers:s,uncommitted_changes:n}}}});async function So(e){if(e.glob("vitest.config.*").length>0)return"vitest";if(e.glob("jest.config.*").length>0)return"jest";if(e.fileExists(".mocharc.yml")||e.fileExists(".mocharc.json"))return"mocha";if(e.glob("playwright.config.*").length>0)return"playwright";if(e.glob("cypress.config.*").length>0)return"cypress";let t=await e.readFile("package.json");if(t)try{let s=JSON.parse(t),n={...s.dependencies||{},...s.devDependencies||{}},o=(s.scripts||{}).test||"";if(n.vitest||o.includes("vitest"))return"vitest";if(n.jest||o.includes("jest"))return"jest";if(n.mocha||o.includes("mocha"))return"mocha";if(n["@playwright/test"]||o.includes("playwright"))return"playwright";if(n.cypress)return"cypress";if(n.ava)return"ava";if(n.tap)return"tap"}catch{}if(e.fileExists("pytest.ini")||e.fileExists("pyproject.toml")||e.fileExists("setup.cfg")||e.fileExists("tox.ini")){let s=await e.readFile("pyproject.toml"),n=await e.readFile("setup.cfg"),i=await e.readFile("pytest.ini");if(s?.includes("pytest")||n?.includes("pytest")||i||e.files.some(o=>o.includes("test_")||o.includes("_test.py")))return"pytest";if(s?.includes("unittest")||n?.includes("unittest"))return"unittest";if(s?.includes("nose"))return"nose"}if(e.files.some(s=>s.endsWith("_test.go")))return"go test";if(e.files.some(s=>s.includes("/tests/")||s.startsWith("tests/")||s.endsWith("tests.rs")||s.match(/mod\s+tests/)))return"cargo test";if(e.fileExists("spec/spec_helper.rb")||e.fileExists(".rspec")||e.files.some(s=>s.includes("/spec/")&&s.endsWith("_spec.rb")))return"rspec";if(e.fileExists("test/minitest_helper.rb"))return"minitest";if(e.files.some(s=>s.endsWith("Test.java")||s.endsWith("Tests.java")))return"junit";if(e.fileExists("pom.xml")){let s=await e.readFile("pom.xml");if(s?.includes("junit")||s?.includes("testng"))return s?.includes("testng")?"testng":"junit"}if(e.fileExists("phpunit.xml")||e.fileExists("phpunit.xml.dist")||e.files.some(s=>s.includes("tests/")&&s.endsWith(".php")))return"phpunit";if(e.files.some(s=>s.endsWith("Test.cs")||s.endsWith("Tests.cs")))return"nunit";if(e.fileExists("build.sbt")){let s=await e.readFile("build.sbt");if(s?.includes("scalatest"))return"scalatest";if(s?.includes("specs2"))return"specs2"}return e.files.some(s=>s.endsWith("Tests.swift")||s.endsWith("XCTest.swift"))?"xctest":null}async function _o(e){if(e.fileExists("eslint.config.js")||e.fileExists("eslint.config.mjs")||e.fileExists("eslint.config.ts")||e.glob(".eslintrc*").length>0)return"eslint";if(e.fileExists("biome.json")||e.fileExists("biome.jsonc"))return"biome";if(e.fileExists("ruff.toml")||e.fileExists(".ruff.toml"))return"ruff";if(e.fileExists(".pylintrc")||e.fileExists("pylintrc"))return"pylint";if(e.fileExists(".flake8")||e.fileExists("setup.cfg")||e.fileExists(".flake8rc"))return"flake8";if(e.fileExists(".golangci.yml")||e.fileExists(".golangci.yaml")||e.fileExists(".golangci-lint.yml"))return"golangci-lint";if(e.fileExists("clippy.toml"))return"clippy";if(e.fileExists(".rubocop.yml")||e.fileExists(".rubocop.yaml"))return"rubocop";if(e.fileExists(".php_cs")||e.fileExists("phpstan.neon")||e.fileExists("phpunit.xml"))return"php-cs-fixer";if(e.fileExists("psalm.xml"))return"psalm";if(e.fileExists(".swiftlint.yml")||e.fileExists(".swiftlint.yaml"))return"swiftlint";if(e.fileExists(".kotlinlint.xml"))return"ktlint";if(e.fileExists("detekt.yml")||e.fileExists("detekt.yaml"))return"detekt";if(e.fileExists("checkstyle.xml"))return"checkstyle";if(e.fileExists("pmd.xml"))return"pmd";if(e.fileExists(".scalafix.conf"))return"scalafix";let t=await e.readFile("pyproject.toml");if(t){if(t.includes("ruff"))return"ruff";if(t.includes("pylint"))return"pylint";if(t.includes("flake8"))return"flake8";if(t.includes("mypy"))return"mypy";if(t.includes("black"))return"black"}let s=await e.readFile("package.json");if(s)try{let i=JSON.parse(s),o={...i.dependencies||{},...i.devDependencies||{}},a=(i.scripts||{}).lint||"";if(o.eslint||a.includes("eslint"))return"eslint";if(o["@biomejs/biome"]||a.includes("biome"))return"biome";if(o.oxlint||a.includes("oxlint"))return"oxlint";if(o.standard)return"standard";if(o.xo)return"xo";if(o["@typescript-eslint/eslint-plugin"])return"eslint";if(o.dprint)return"dprint"}catch{}return e.fileExists("golangci-lint.yml")||e.fileExists(".golangci.yml")?"golangci-lint":(await e.readFile("Cargo.toml"))?.includes("clippy")?"clippy":e.fileExists(".rubocop.yml")?"rubocop":e.fileExists("phpstan.neon")?"phpstan":e.fileExists("ecs.php")||e.fileExists("easy-coding-standard.yml")?"ecs":null}async function Ro(e){if(e.glob(".prettierrc*").length>0||e.fileExists("prettier.config.js")||e.fileExists("prettier.config.mjs")||e.fileExists("prettier.config.cjs")||e.fileExists("prettier.config.ts"))return"prettier";if(e.fileExists("biome.json")||e.fileExists("biome.jsonc"))return"biome";if(e.fileExists("ruff.toml")||e.fileExists(".ruff.toml"))return"ruff";if(e.fileExists("rustfmt.toml")||e.fileExists(".rustfmt.toml"))return"rustfmt";if(e.fileExists("dprint.json")||e.fileExists("dprint.jsonc"))return"dprint";if(e.fileExists(".editorconfig"))return"editorconfig";if(e.fileExists(".gofmt")||e.fileExists("gofmt.toml"))return"gofmt";if(e.fileExists(".scalafmt.conf"))return"scalafmt";if(e.fileExists(".black")||e.fileExists("pyproject.toml"))return"black";if(e.fileExists(".isort.cfg")||e.fileExists("pyproject.toml"))return"isort";if(e.fileExists(".swiftformat"))return"swiftformat";if(e.fileExists(".php-cs-fixer.php")||e.fileExists(".php-cs-fixer.dist.php"))return"php-cs-fixer";if(e.fileExists(".rubocop.yml"))return"rubocop";if(e.fileExists("prettier.config.ts")||e.fileExists(".prettierignore"))return"prettier";let t=await e.readFile("pyproject.toml");if(t){if(t.includes("black"))return"black";if(t.includes("isort"))return"isort";if(t.includes("autopep8"))return"autopep8";if(t.includes("yapf"))return"yapf"}let s=await e.readFile("package.json");if(s)try{let n=JSON.parse(s),i={...n.dependencies||{},...n.devDependencies||{}},o=n.scripts||{},r=(o.format||"")+(o.fmt||"");if(i.prettier||r.includes("prettier"))return"prettier";if(i["@biomejs/biome"]||r.includes("biome"))return"biome";if(i.dprint)return"dprint"}catch{}return e.fileExists(".gofmtrc")||e.fileExists("gofmt.toml")?"gofmt":e.fileExists("rustfmt.toml")?"rustfmt":e.fileExists(".rubocop.yml")?"rubocop":e.fileExists(".swiftformat")?"swiftformat":e.fileExists(".scalafmt.conf")?"scalafmt":null}function Po(e){return e.files.some(t=>t.startsWith(".github/workflows/"))?"github-actions":e.fileExists(".gitlab-ci.yml")||e.fileExists(".gitlab-ci.yaml")?"gitlab-ci":e.fileExists("Jenkinsfile")||e.fileExists("Jenkinsfile")?"jenkins":e.files.some(t=>t.startsWith(".circleci/"))?"circleci":e.fileExists("bitbucket-pipelines.yml")?"bitbucket-pipelines":e.fileExists(".travis.yml")?"travis-ci":e.fileExists("azure-pipelines.yml")||e.fileExists("azure-pipelines.yaml")?"azure-pipelines":e.fileExists("buildspec.yml")?"aws-codebuild":e.fileExists("cloudbuild.yaml")||e.fileExists("cloudbuild.yml")?"google-cloud-build":e.fileExists(".drone.yml")?"drone-ci":e.fileExists("workflow.yml")?"gsuite-actions":e.fileExists("now.json")||e.fileExists(".vercelignore")?"vercel":e.fileExists("netlify.toml")?"netlify":e.fileExists(".github/workflows/ci.yml")||e.fileExists(".github/workflows/cd.yml")?"github-actions":e.fileExists("procfile")||e.fileExists("Procfile")?"heroku":e.fileExists("appveyor.yml")?"appveyor":e.fileExists("codeship-services.yml")||e.fileExists("codeship-steps.yml")?"codeship":e.fileExists("semantic.yml")?"semantic-release":e.fileExists(".rerun.yaml")||e.fileExists(".rerun.yml")?"rerun":e.fileExists("woodpecker.yml")?"woodpecker-ci":e.fileExists(".forgejo")?"forgejo":null}function Do(e){return!!(e.files.some(t=>t.startsWith(".husky/"))||e.fileExists(".pre-commit-config.yaml")||e.fileExists(".pre-commit-config.yml")||e.fileExists(".lintstagedrc")||e.fileExists("lint-staged.config.js")||e.fileExists("lint-staged.config.mjs")||e.fileExists("lint-staged.config.ts")||e.fileExists("lefthook.yml")||e.fileExists("lefthook.yaml")||e.fileExists("lefthook-local.yml")||e.fileExists(".git/hooks/pre-commit")||e.fileExists(".simple-git-hooks.cjs")||e.fileExists(".simple-git-hooks.js")||e.fileExists(".yorkielerc")||e.fileExists(".yorkie")||e.fileExists(".huskyrc")||e.fileExists(".huskyrc.json")||e.fileExists(".huskyrc.js")||e.fileExists(".pre-commit-hook.json"))}var js,Cs=D(()=>{"use strict";js={name:"quality",category:"quality",async detect(e){let[t,s,n]=await Promise.all([So(e),_o(e),Ro(e)]);return{test_framework:t,linter:s,formatter:n,ci:Po(e),pre_commit_hooks:Do(e)}}}});function Ao(e){return e.files.some(t=>t.match(/^(src\/)?app\/layout\.(tsx?|jsx?)$/))?"app-router":e.files.some(t=>t.match(/^(src\/)?pages\/_app\./))?"pages-router":e.files.some(t=>t.includes("/controllers/"))&&e.files.some(t=>t.includes("/models/"))?"mvc":e.files.some(t=>t.startsWith("src/features/"))?"feature-sliced":e.files.some(t=>t.startsWith("src/modules/"))?"modular":e.files.some(t=>t.includes("/services/"))&&e.files.some(t=>t.includes("/repositories/"))?"layered":e.files.some(t=>t.startsWith("src/routes/"))?"file-based-routing":e.files.some(t=>t.startsWith("src/commands/")||t.startsWith("cmd/"))?"command-based":e.files.some(t=>t.startsWith("src/detectors/")||t.startsWith("src/plugins/"))?"plugin-based":e.files.some(t=>t.includes("/domain/"))&&e.files.some(t=>t.includes("/infra/")||t.includes("/infrastructure/"))?"hexagonal":e.files.some(t=>t.includes("/services/"))&&e.files.some(t=>t.includes("/handlers/")||t.includes("/controllers/"))?"layered":e.files.some(t=>t.match(/^internal\/.+\/.+/))?"package-per-feature":null}async function Oo(e){let t=await e.readFile("package.json");if(!t)return null;try{let s=JSON.parse(t),n={...s.dependencies||{},...s.devDependencies||{}},i=[];return n.zustand&&i.push("zustand"),(n["@reduxjs/toolkit"]||n.redux)&&i.push("redux"),n.mobx&&i.push("mobx"),n.jotai&&i.push("jotai"),n.recoil&&i.push("recoil"),n.pinia&&i.push("pinia"),n.vuex&&i.push("vuex"),n["@tanstack/react-query"]&&i.push("react-query"),n["@tanstack/vue-query"]&&i.push("vue-query"),n.swr&&i.push("swr"),i.length>0?i.join(" + "):null}catch{return null}}async function Io(e){let t=await e.readFile("package.json"),s=[];if(t)try{let n=JSON.parse(t),i={...n.dependencies||{},...n.devDependencies||{}};(i["@trpc/server"]||i["@trpc/client"])&&s.push("trpc"),(i.graphql||i["@apollo/server"])&&s.push("graphql")}catch{}return e.glob("**/*.proto").length>0&&s.push("grpc"),e.files.some(n=>n.match(/\/api\/.*route\.(ts|js)$/))&&s.push("route-handlers"),e.files.some(n=>n.includes("/routes/")||n.includes("/controllers/"))&&s.push("rest"),e.files.some(n=>n.match(/\/actions?\.(ts|js)$/))&&s.push("server-actions"),s.length>0?s.join(" + "):null}function No(e){let t={},s=new Set;for(let i of e.files){let o=i.match(/^src\/([^/]+)\//);o&&s.add(o[1])}for(let i of s){let o=Es[i];o&&(t[`src/${i}/`]=o)}let n=new Set;for(let i of e.files){let o=i.match(/^([^/]+)\//);o&&!o[1].startsWith(".")&&o[1]!=="src"&&o[1]!=="node_modules"&&n.add(o[1])}for(let i of n){let o=Es[i];o&&!t[`src/${i}/`]&&(t[`${i}/`]=o)}return t}var Es,Ss,_s=D(()=>{"use strict";Es={app:"routes and pages",api:"API routes",pages:"page components",components:"reusable UI components",lib:"shared utilities",utils:"utility functions",helpers:"helper functions",hooks:"React hooks",services:"business logic / services",models:"data models",controllers:"request handlers",middleware:"middleware",routes:"routing",store:"state management",stores:"state stores",types:"type definitions",interfaces:"interface definitions",schemas:"validation schemas",config:"configuration",constants:"constants",assets:"static assets",styles:"stylesheets",tests:"test files",__tests__:"test files",test:"test files",spec:"test specifications",features:"feature modules",modules:"application modules",plugins:"plugin system",providers:"context providers",contexts:"React contexts",commands:"CLI commands",cmd:"CLI commands",cli:"CLI interface",detectors:"detection / analysis modules",scanners:"scanning modules",scanner:"scanning engine",integrations:"third-party integrations",adapters:"adapters / connectors",handlers:"event / request handlers",resolvers:"GraphQL resolvers",guards:"auth / route guards",pipes:"data transform pipes",decorators:"decorators",validators:"validation logic",migrations:"database migrations",seeds:"database seed data",fixtures:"test fixtures",mocks:"test mocks",stubs:"test stubs",github:"GitHub integration",git:"git integration",mcp:"MCP server / protocol",server:"HTTP / API server",client:"client-side code",core:"core business logic",domain:"domain logic",infra:"infrastructure",db:"database layer",database:"database layer",auth:"authentication / authorization",email:"email handling",notifications:"notification system",jobs:"background jobs / workers",workers:"background workers",queues:"job / message queues",events:"event system",shared:"shared / cross-cutting code",common:"common utilities",internal:"internal modules",pkg:"packages / library code",proto:"protobuf definitions",generated:"auto-generated code",scripts:"build / utility scripts",tools:"development tools",docs:"documentation"},Ss={name:"patterns",category:"patterns",async detect(e){return{architecture:Ao(e),state_management:await Oo(e),api_style:await Io(e),key_modules:No(e)}}}});async function Lo(e){let t=["openapi.json","openapi.yaml","openapi.yml","swagger.json","swagger.yaml","swagger.yml","api-specs/openapi.json","api-specs/openapi.yaml","docs/openapi.json","docs/openapi.yaml","spec/openapi.json","spec/openapi.yaml","api/openapi.json","api/openapi.yaml"];for(let s of t)if(e.fileExists(s)){let n=await e.readFile(s);if(n)try{let i=JSON.parse(n);if(i.openapi||i.swagger)return{version:i.openapi||i.swagger,title:i.info?.title||null,file:s,type:i.openapi?"openapi":"swagger"}}catch{if(n.includes("openapi:")||n.includes("swagger:"))return{version:xt(n,"openapi")||xt(n,"swagger"),title:xt(n,"title"),file:s,type:n.includes("openapi:")?"openapi":"swagger"}}}return null}async function Fo(e){let t=e.files.filter(i=>i.endsWith(".graphql")||i.endsWith(".gql")||i.includes("/graphql/")||i.includes("/schema/"));if(t.length===0)return null;let s=[],n=[];for(let i of t){let o=await e.readFile(i);o&&((o.includes("type Query")||o.includes("type Mutation")||o.includes("type Subscription"))&&s.push(i),(o.includes("Query:")||o.includes("Mutation:")||o.includes("resolver"))&&n.push(i))}return s.length===0&&n.length===0?null:{schema_files:s,resolver_files:n,total_files:t.length}}async function Mo(e){let t=e.files.filter(n=>n.endsWith(".proto"));if(t.length===0)return null;let s=[];for(let n of t){let i=await e.readFile(n);i&&i.includes("service ")&&s.push(n)}return{proto_files:t,service_definitions:s}}async function qo(e){let t=e.files.filter(n=>n.includes("postman")&&(n.endsWith(".json")||n.endsWith(".json.backup")));if(t.length===0)return null;let s=[];for(let n of t){let i=await e.readFile(n);if(i)try{let o=JSON.parse(i);o.info?.schema?.includes("postman")&&s.push({file:n,name:o.info?.name||null})}catch{}}return s.length===0?null:{collections:s}}function xt(e,t){let s=new RegExp(`^${t}:\\s*(.+)$`,"m"),n=e.match(s);return n?n[1].trim():null}var Rs,Ps=D(()=>{"use strict";Rs={name:"api-docs",category:"config",async detect(e){let[t,s,n,i]=await Promise.all([Lo(e),Fo(e),Mo(e),qo(e)]);return{openapi:t,graphql:s,grpc:n,postman:i}}}});var jt,Ds=D(()=>{"use strict";rs();cs();us();fs();gs();ks();vs();xs();Cs();_s();Ps();jt=[os,as,ls,ps,ms,ys,ws,$s,js,Ss,Rs]});function L(e,t){return e?String(e).slice(0,t):""}var Ct=D(()=>{"use strict"});import{execFile as As}from"child_process";async function _e(e,t,s={}){return new Promise(n=>{let i=["api","graphql","-f",`query=${t}`,"-H","Accept: application/vnd.github.v3+json"];for(let[o,r]of Object.entries(s))i.push("-f",`${o}=${JSON.stringify(r)}`);As("gh",i,{cwd:e,timeout:3e4},(o,r,a)=>{if(o){n(null);return}try{let c=JSON.parse(r.trim());if(c.errors&&c.errors.length>0){n(null);return}n(c.data||null)}catch{n(null)}})})}function Jo(e){let t=[/github\.com[:/]([^/]+)\/(.+?)(\.git)?$/,/github\.com[:/]([^/]+)\/(.+)$/];for(let s of t){let n=e.match(s);if(n)return{owner:n[1],repo:n[2].replace(/\.git$/,"")}}return null}function Wo(e){let t=e.labels?.nodes||[],s=e.assignees?.nodes||[],n=e.milestone,i=e.reactions||{},o=e.comments,r=e.timelineItems;return{number:e.number,title:L(e.title,200),state:e.state?.toLowerCase()==="open"?"open":"closed",url:e.url||void 0,labels:t.map(a=>L(a.name,50)).filter(Boolean),assignee:L(s[0]?.login,100)||null,milestone:n?.title||null,created_at:e.createdAt,updated_at:e.updatedAt,comments_count:o?.totalCount||0,reactions:{thumbs_up:i.thumbsUp||0,thumbs_down:i.thumbsDown||0,laugh:i.laugh||0,hooray:i.hooray||0,confused:i.confused||0,heart:i.heart||0,rocket:i.rocket||0,eyes:i.eyes||0},timeline_events:r?.totalCount||0,body:L(e.body||"",2e3)}}function Ko(e){let t=e.labels?.nodes||[],s=e.reviewRequests?.nodes||[],n=e.author,i=e.statusCheckRollup,o=e.comments,r;if(i?.state){let l=i.state.toLowerCase();l==="success"||l==="completed"?r="passing":l==="failure"||l==="error"?r="failing":r="pending"}let a=e.mergeable==="MERGEABLE",c=e.mergeable==="CONFLICTING";return{number:e.number,title:L(e.title,200),state:(e.state||"open").toLowerCase(),url:e.url||void 0,author:L(n?.login,100)||"unknown",branch:L(e.headRefName,200),labels:t.map(l=>L(l.name,50)).filter(Boolean),reviewers:s.map(l=>L(l.requestedReviewer?.login,100)).filter(Boolean),created_at:e.createdAt,updated_at:e.updatedAt,checks_status:r,mergeable:a,merge_conflicts:c,additions:e.additions||0,deletions:e.deletions||0,comments_count:o?.totalCount||0,review_decision:e.reviewDecision?.toLowerCase()==="approved"?"approved":e.reviewDecision?.toLowerCase()==="changes_requested"?"changes_requested":e.reviewDecision?.toLowerCase()==="review_required"?"review_required":null}}async function Os(e,t,s={}){let{includeIssues:n=!0,includePRs:i=!0,includeMilestones:o=!0,includeReleases:r=!0,includeProjects:a=!0,limit:c=50}=s,l=Jo(t);if(!l)return{};let{owner:p,repo:d}=l,f={},[m,h,v,x,j]=await Promise.all([n?_e(e,To,{owner:p,repo:d,limit:c}).catch(g=>(S(`GitHub issues query failed: ${g instanceof Error?g.message:String(g)}`),null)):Promise.resolve(null),i?_e(e,Ho,{owner:p,repo:d,limit:Math.min(c,30)}).catch(g=>(S(`GitHub pull requests query failed: ${g instanceof Error?g.message:String(g)}`),null)):Promise.resolve(null),o?_e(e,Go,{owner:p,repo:d}).catch(g=>(S(`GitHub milestones query failed: ${g instanceof Error?g.message:String(g)}`),null)):Promise.resolve(null),r?_e(e,Uo,{owner:p,repo:d,limit:10}).catch(g=>(S(`GitHub releases query failed: ${g instanceof Error?g.message:String(g)}`),null)):Promise.resolve(null),a?_e(e,Bo,{owner:p,repo:d}).catch(g=>(S(`GitHub projects query failed: ${g instanceof Error?g.message:String(g)}`),null)):Promise.resolve(null)]);return m?.repository?.issues?.nodes&&(f.issues=m.repository.issues.nodes.map(Wo)),h?.repository?.pullRequests?.nodes&&(f.pull_requests=h.repository.pullRequests.nodes.map(Ko)),v?.repository?.milestones?.nodes&&(f.milestones=v.repository.milestones.nodes.map(g=>{let G=g.issues?.nodes||[],w=g.closedIssues?.totalCount||0,A=g.issues?.totalCount||G.length,b=A-w;return{title:g.title,description:g.description||"",due_date:g.dueOn||null,progress:{open:b,closed:w,percent:A>0?Math.round(w/A*100):0},issues:G.map(P=>P.number)}})),x?.repository?.releases?.nodes&&(f.releases=x.repository.releases.nodes.map(g=>({tag_name:g.tagName,name:g.name||g.tagName,created_at:g.createdAt,url:g.url,author:g.author?.login||"unknown",prerelease:!!g.isPrerelease}))),j?.repository?.projectsV2?.nodes&&(f.project_boards=j.repository.projectsV2.nodes.filter(g=>g!==null).map(g=>{let G=g.columns?.nodes||[],w=g.items?.totalCount||0;return{number:g.number,title:g.title,state:(g.state||"open").toLowerCase(),url:g.url,columns:G.map(A=>({name:A.name,cards_count:w}))}})),f}async function Is(e){return new Promise(t=>{As("gh",["--version"],{cwd:e,timeout:5e3},(s,n)=>{if(s){t(!1);return}let i=n.match(/gh version (\d+)\.(\d+)/);if(i){let o=parseInt(i[1],10),r=parseInt(i[2],10);t(o>2||o===2&&r>=0)}else t(!1)})})}var To,Ho,Go,Uo,Bo,Ns=D(()=>{"use strict";M();Ct();To=`
|
|
21
21
|
query($owner: String!, $repo: String!, $limit: Int) {
|
|
22
22
|
repository(owner: $owner, name: $repo) {
|
|
23
23
|
issues(first: $limit, orderBy: {field: UPDATED_AT, direction: DESC}) {
|
|
@@ -29,6 +29,7 @@ query($owner: String!, $repo: String!, $limit: Int) {
|
|
|
29
29
|
labels(first: 10) { nodes { name } }
|
|
30
30
|
assignees(first: 1) { nodes { login } }
|
|
31
31
|
milestone { title }
|
|
32
|
+
body
|
|
32
33
|
createdAt
|
|
33
34
|
updatedAt
|
|
34
35
|
comments { totalCount }
|
|
@@ -47,7 +48,7 @@ query($owner: String!, $repo: String!, $limit: Int) {
|
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
|
-
`,
|
|
51
|
+
`,Ho=`
|
|
51
52
|
query($owner: String!, $repo: String!, $limit: Int) {
|
|
52
53
|
repository(owner: $owner, name: $repo) {
|
|
53
54
|
pullRequests(first: $limit, orderBy: {field: UPDATED_AT, direction: DESC}) {
|
|
@@ -74,7 +75,7 @@ query($owner: String!, $repo: String!, $limit: Int) {
|
|
|
74
75
|
}
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
|
-
`,
|
|
78
|
+
`,Go=`
|
|
78
79
|
query($owner: String!, $repo: String!) {
|
|
79
80
|
repository(owner: $owner, name: $repo) {
|
|
80
81
|
milestones(first: 20, orderBy: {field: DUE_DATE, direction: ASC}) {
|
|
@@ -91,7 +92,7 @@ query($owner: String!, $repo: String!) {
|
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
|
-
`,
|
|
95
|
+
`,Uo=`
|
|
95
96
|
query($owner: String!, $repo: String!, $limit: Int) {
|
|
96
97
|
repository(owner: $owner, name: $repo) {
|
|
97
98
|
releases(first: $limit, orderBy: {field: CREATED_AT, direction: DESC}) {
|
|
@@ -106,7 +107,7 @@ query($owner: String!, $repo: String!, $limit: Int) {
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
|
-
`,
|
|
110
|
+
`,Bo=`
|
|
110
111
|
query($owner: String!, $repo: String!) {
|
|
111
112
|
repository(owner: $owner, name: $repo) {
|
|
112
113
|
projectsV2(first: 10) {
|
|
@@ -134,18 +135,18 @@ query($owner: String!, $repo: String!) {
|
|
|
134
135
|
}
|
|
135
136
|
}
|
|
136
137
|
}
|
|
137
|
-
`});import{execFile as
|
|
138
|
-
`).filter(Boolean).map(n=>{let i=JSON.parse(n),o=i.open_issues||0,r=i.closed_issues||0,a=o+r;return{title:i.title,description:i.description||"",due_date:i.due_on||null,progress:{open:o,closed:r,percent:a>0?Math.round(r/a*100):0},issues:[]}})}catch{return[]}}async function
|
|
139
|
-
`).filter(s=>s.trim());for(let s=0;s<t.length;s++)if(t[s].match(/^#+\s*(decision|why|rationale)/i))return t.slice(s+1,s+4).join(" ").trim().slice(0,200);return t[0]?.slice(0,200)||""}function
|
|
140
|
-
`).slice(0,5).find(c=>c.startsWith("#"))?.replace(/^#+\s*/,"")||i;n.push({title:a,summary:"",date:"",source:i})}catch{}return n}function
|
|
141
|
-
Written: .codebase.json (${o} KB)`)}function
|
|
138
|
+
`});import{execFile as Ls}from"child_process";import{readdirSync as zo,readFileSync as Vo,existsSync as Qo}from"fs";import{join as Et}from"path";async function be(e){if(!await ye(e,["--version"]))return null;let s=await Yo(e,"git",["remote","get-url","origin"]);if(!(!!s&&(s.includes("github.com")||s.includes("github."))))return{status:{synced_at:new Date().toISOString(),github_available:!1,issues:[],pull_requests:[],kanban:{backlog:[],in_progress:[],needs_verify:[],done:[]},priorities:[]},roadmap:{milestones:[]},decisions:{from_prs:[],from_adrs:[],manual:[]}};if(!await Xo(e))return null;let o=await Is(e),r=[],a=[],c=[],l=[],p=[],d=!1;if(o)try{let x=await Os(e,s,{includeIssues:!0,includePRs:!0,includeMilestones:!0,includeReleases:!0,includeProjects:!0,limit:50});r=x.issues||[],a=x.pull_requests||[],c=x.milestones||[],l=x.releases||[],p=x.project_boards||[],d=!0}catch{}d||(r=await Zo(e),a=await sr(e),c=await or(e));let[f]=await Promise.all([rr(e)]),m=lr(r),h=ur(r),v=cr(e);return{status:{synced_at:new Date().toISOString(),github_available:!0,issues:r,pull_requests:a,kanban:m,priorities:h,releases:l,project_boards:p},roadmap:{milestones:c},decisions:{from_prs:f,from_adrs:v,manual:[]}}}function ye(e,t){return new Promise(s=>{Ls("gh",t,{cwd:e,timeout:3e4},(n,i)=>{s(n?"":i.trim())})})}function Yo(e,t,s){return new Promise(n=>{Ls(t,s,{cwd:e,timeout:1e4},(i,o)=>{n(i?"":o.trim())})})}async function Xo(e){try{let t=await ye(e,["api","rate_limit"]);return t?(JSON.parse(t).resources?.core?.remaining??100)>10:!0}catch{return!0}}async function Zo(e){let t=await ye(e,["issue","list","--limit","50","--state","all","--json","number,title,state,labels,assignees,milestone,createdAt,updatedAt"]);if(!t)return[];try{return JSON.parse(t).map(er)}catch{return[]}}function er(e){let t=e.labels||[],s=e.assignees||[],n=e.milestone,i=e.body||"";return{number:e.number,title:L(e.title,200),state:e.state?.toLowerCase()==="open"?"open":"closed",labels:t.map(o=>L(o.name,50)).filter(Boolean),assignee:L(s[0]?.login,100)||null,milestone:L(n?.title,200)||null,created_at:e.createdAt,updated_at:e.updatedAt,effort:tr(i),body:L(e.body||"",2e3)}}function tr(e){let t=e.match(/\*\*Effort:\*\*\s*([SML])\b/i);if(!t)return;let s=t[1].toUpperCase();if(s==="S"||s==="M"||s==="L")return s}async function sr(e){let t=await ye(e,["pr","list","--limit","30","--state","all","--json","number,title,state,author,headRefName,labels,reviewRequests,createdAt,updatedAt"]);if(!t)return[];try{return JSON.parse(t).map(ir)}catch{return[]}}function ir(e){let t=e.labels||[],s=e.reviewRequests||[],n=e.author;return{number:e.number,title:L(e.title,200),state:(e.state||"open").toLowerCase(),author:L(n?.login,100)||"unknown",branch:L(e.headRefName,nr),labels:t.map(i=>L(i.name,50)).filter(Boolean),reviewers:s.map(i=>L(i.login||i.name,100)).filter(Boolean),created_at:e.createdAt,updated_at:e.updatedAt}}async function or(e){let t=await ye(e,["api","repos/{owner}/{repo}/milestones","--jq",".[] | {title,description,due_on,open_issues,closed_issues}"]);if(!t)return[];try{return t.split(`
|
|
139
|
+
`).filter(Boolean).map(n=>{let i=JSON.parse(n),o=i.open_issues||0,r=i.closed_issues||0,a=o+r;return{title:i.title,description:i.description||"",due_date:i.due_on||null,progress:{open:o,closed:r,percent:a>0?Math.round(r/a*100):0},issues:[]}})}catch{return[]}}async function rr(e){let t=await ye(e,["pr","list","--limit","20","--state","merged","--json","number,title,body,mergedAt,url"]);if(!t)return[];try{return JSON.parse(t).filter(n=>{let i=n.body||"";return i.toLowerCase().includes("decision")||i.toLowerCase().includes("why:")||i.toLowerCase().includes("rationale")||i.toLowerCase().includes("chose")||i.toLowerCase().includes("trade-off")}).map(n=>({title:L(n.title,200),summary:ar(n.body||""),date:n.mergedAt,source:`PR #${n.number}`,url:n.url}))}catch{return[]}}function ar(e){let t=e.split(`
|
|
140
|
+
`).filter(s=>s.trim());for(let s=0;s<t.length;s++)if(t[s].match(/^#+\s*(decision|why|rationale)/i))return t.slice(s+1,s+4).join(" ").trim().slice(0,200);return t[0]?.slice(0,200)||""}function cr(e){let t=["docs/adr","docs/decisions","adr","decisions","docs/architecture/decisions"],s=[];for(let i of t){let o=Et(e,i);if(Qo(o))try{let r=zo(o).filter(a=>a.endsWith(".md")).map(a=>Et(i,a));s.push(...r)}catch{}}let n=[];for(let i of s.slice(0,20))try{let a=Vo(Et(e,i),"utf-8").split(`
|
|
141
|
+
`).slice(0,5).find(c=>c.startsWith("#"))?.replace(/^#+\s*/,"")||i;n.push({title:a,summary:"",date:"",source:i})}catch{}return n}function lr(e){let t=e.filter(c=>c.state==="open"),s=e.filter(c=>c.state==="closed"),n=["in-progress","in progress","doing","wip"],i=t.filter(c=>c.labels.some(l=>n.includes(l.toLowerCase()))),o=["status:needs-verify","needs-verify","needs-verification"],r=t.filter(c=>!i.includes(c)&&c.labels.some(l=>o.includes(l.toLowerCase())));return{backlog:t.filter(c=>!i.includes(c)&&!r.includes(c)),in_progress:i,needs_verify:r,done:s.slice(0,20)}}function Pe(e){let t=n=>{let i=5;for(let o of n.labels){let r=o.toLowerCase();r.startsWith("status:")||(r.includes("p0")||r.includes("critical")||r.includes("urgent")?i=Math.min(i,0):r==="vibekit"||r.includes("p1")||r.includes("high")||r.includes("bug")?i=Math.min(i,1):r.includes("p2")||r.includes("medium")||r==="arch"?i=Math.min(i,2):r.includes("p3")||r.includes("low")?i=Math.min(i,3):r.includes("feature")&&(i=Math.min(i,4)))}return i},s=n=>{switch(n.effort){case"S":return 0;case"M":return 1;case"L":return 2;default:return 1}};return[...e].sort((n,i)=>{let o=t(n),r=t(i);return o!==r?o-r:s(n)-s(i)})}function ur(e){return Pe(e.filter(t=>t.state==="open"))}var nr,De=D(()=>{"use strict";Ns();Ct();nr=200});import{readFileSync as dr,statSync as pr}from"fs";import{writeFile as fr,rename as mr}from"fs/promises";import{execFile as gr}from"child_process";import{join as st}from"path";async function Ms(e){return new Promise(t=>{gr("git",["rev-parse","HEAD"],{cwd:e,timeout:5e3},(s,n)=>{if(s){t(null);return}t(n.trim())})})}function qs(e){try{let t=dr(st(e,St),"utf-8"),s=JSON.parse(t);return s.cache_version!==Fs?null:s}catch{return null}}async function Ts(e,t,s){let n={cache_version:Fs,timestamp:new Date().toISOString(),git_sha:await Ms(e),file_count:t,file_mtimes:Gs(e),manifest:s};try{let i=st(e,St+".tmp");await fr(i,JSON.stringify(n),"utf-8"),await mr(i,st(e,St))}catch{}}async function Hs(e,t,s){let n=await Ms(e);if(n&&t.git_sha)return n===t.git_sha;if(t.file_count!==s)return!1;let i=Gs(e);for(let o of Object.keys({...t.file_mtimes,...i}))if((t.file_mtimes[o]??0)!==(i[o]??0))return!1;return!0}function Gs(e){let t={};for(let s of hr)try{let n=pr(st(e,s));t[s]=n.mtimeMs}catch{}return t}var St,Fs,hr,Us=D(()=>{"use strict";St=".codebase.cache.json",Fs=2,hr=["package.json","package-lock.json","pnpm-lock.yaml","yarn.lock","tsconfig.json","tsconfig.build.json","Cargo.toml","Cargo.lock","pyproject.toml","requirements.txt","poetry.lock","go.mod","go.sum","Makefile","Dockerfile","docker-compose.yml"]});async function K(e,t={}){let s=await ss(e,{depth:t.depth});if(t.incremental){let a=qs(e);if(a&&await Hs(e,a,s.files.length))return a.manifest}let n=jt;t.categories?.length&&(n=jt.filter(a=>t.categories.includes(a.category)));let i=await Promise.allSettled(n.map(async a=>({category:a.category,data:await a.detect(s)}))),o={version:"1.0",generated_at:new Date().toISOString()},r=[];for(let a of i)if(a.status==="fulfilled")o[a.value.category]=a.value.data;else{let c=`Detector failed: ${a.reason instanceof Error?a.reason.message:String(a.reason)}`;r.push(c),t.quiet||S(c)}if(r.length>0&&(o._warnings=r),t.sync)try{let a=await be(e);a&&(o.status=a.status,o.roadmap=a.roadmap,o.decisions=a.decisions)}catch{t.quiet||S("GitHub sync failed (is `gh` CLI installed and authenticated?)")}return t.incremental&&await Ts(e,s.files.length,o),o}function nt(e,t){switch(e){case"project":{let s=t.name,n=t.description;return n?`${s} \u2014 ${n.slice(0,60)}`:s||"unknown"}case"repo":{let s=t.url,n=t.default_branch;return`${s?s.replace(/.*[:/]/,"").replace(/\.git$/,""):"local"}, ${n||"unknown branch"}`}case"structure":{let s=t.entry_points,n=t.tree,i=t.build_output,o=Object.keys(n||{}).filter(a=>a!=="./"),r=[];return s?.length&&r.push(`${s.length} entry points`),o.length&&r.push(`${o.length} top-level dirs`),i?.length&&r.push(`build: ${i.join(", ")}`),r.join(", ")||"empty"}case"stack":{let s=t.languages,n=t.frameworks,i=t.build_tool,o=[...s||[],...n||[]];return i&&o.push(i),o.join(", ")||"unknown"}case"commands":return Object.entries(t).filter(([,n])=>n).map(([n])=>n).join(", ")||"none detected";case"dependencies":{let s=t.direct_count,n=t.dev_count,i=t.lock_file,o=[];return s&&o.push(`${s} direct`),n&&o.push(`${n} dev`),!s&&!n&&o.push("0 deps"),i&&o.push(i),o.join(", ")}case"config":return`${t.env_files?.length||0} env files`;case"git":{let s=t.recent_commits,n=t.uncommitted_changes;return`${s?.length||0} recent commits${n?", uncommitted changes":""}`}case"quality":{let s=[];return t.test_framework&&s.push(t.test_framework),t.linter&&s.push(t.linter),t.ci&&s.push(t.ci),s.join(", ")||"none detected"}case"patterns":{let s=t.architecture,n=t.state_management;return[s,n].filter(Boolean).join(", ")||"unknown"}case"status":{let s=t.issues||[],n=t.pull_requests||[];return`${s.length} issues, ${n.length} PRs`}default:return JSON.stringify(t).slice(0,60)}}var Ae=D(()=>{"use strict";is();Ds();De();M();Us()});import{resolve as br,join as yr}from"path";import{writeFile as kr}from"fs/promises";async function Oe(e){Q(e.quiet);let t=br(e.path);u(`Scanning ${t}...`);let s=await K(t,{depth:e.depth,categories:e.categories.length?e.categories:void 0,incremental:e.incremental,quiet:e.quiet,sync:e.sync});for(let[r,a]of Object.entries(s))r==="version"||r==="generated_at"||typeof a!="object"||a===null||y(`${wr(r)} (${nt(r,a)})`);let n=yr(t,".codebase.json"),i=JSON.stringify(s,null,2);await kr(n,i,"utf-8");let o=(Buffer.byteLength(i)/1024).toFixed(1);u(`
|
|
142
|
+
Written: .codebase.json (${o} KB)`)}function wr(e){return e.charAt(0).toUpperCase()+e.slice(1)}var _t=D(()=>{"use strict";Ae();M()});import{readFileSync as Rt,writeFileSync as Bs,existsSync as Pt}from"fs";import{join as it}from"path";function jr(e){try{let t=Rt(it(e,".codebase.json"),"utf-8"),s=JSON.parse(t);return{name:s.project?.name||"Unknown",description:s.project?.description||null,languages:s.stack?.languages||[],frameworks:s.stack?.frameworks||[],commands:s.commands||{}}}catch{return null}}function Cr(e){let t=jr(e);if(!t)return xr;let s=[...t.languages,...t.frameworks].filter(Boolean),n=s.length?s.join(", "):"unknown",o=Object.entries(t.commands).filter(([,a])=>a).map(([a,c])=>`| \`${a}\` | \`${c}\` |`).join(`
|
|
142
143
|
`),r=o?`
|
|
143
144
|
### Project Commands
|
|
144
145
|
| Task | Command |
|
|
145
146
|
|---|---|
|
|
146
147
|
${o}
|
|
147
148
|
`:"";return`
|
|
148
|
-
${
|
|
149
|
+
${Ie}
|
|
149
150
|
## Project Context (auto-generated by codebase)
|
|
150
151
|
|
|
151
152
|
**${t.name}**${t.description?` \u2014 ${t.description}`:""}
|
|
@@ -169,11 +170,19 @@ Returns: project identity, tech stack, commands, structure, current status, next
|
|
|
169
170
|
| \`npx codebase issue create "title"\` | Track a bug, feature, or TODO |
|
|
170
171
|
| \`npx codebase issue close <n> --reason "why"\` | Close an issue after fixing it |
|
|
171
172
|
|
|
173
|
+
### Maintenance
|
|
174
|
+
| Command | What it does |
|
|
175
|
+
|---|---|
|
|
176
|
+
| \`codebase doctor\` | Health check \u2014 diagnose broken setup |
|
|
177
|
+
| \`codebase fix\` | Auto-repair issues found by doctor |
|
|
178
|
+
| \`codebase skills\` | List installed skills and their capabilities |
|
|
179
|
+
|
|
172
180
|
### Rules
|
|
173
181
|
- **Never explore the codebase to discover stack/commands/structure** \u2014 it's already in \`brief\`
|
|
174
182
|
- **Check \`next\` before starting work** \u2014 don't duplicate in-progress tasks
|
|
175
183
|
- **Create issues for bugs/TODOs you find** \u2014 keep the project brain alive
|
|
176
184
|
- **Close issues when you fix them** \u2014 with a reason so the team knows why
|
|
185
|
+
- **If any command fails, run \`codebase doctor\` then \`codebase fix\`** \u2014 self-heal before asking for help
|
|
177
186
|
|
|
178
187
|
### Vibekit Workflow
|
|
179
188
|
\`\`\`
|
|
@@ -183,17 +192,20 @@ Returns: project identity, tech stack, commands, structure, current status, next
|
|
|
183
192
|
- \`/build\` \u2014 Implements architectural issues autonomously. Runs until all \`arch\`+\`vibekit\` issues are closed.
|
|
184
193
|
- \`/launch\` \u2014 Gates on open bugs, generates GTM artifacts, creates GitHub release, merges to main.
|
|
185
194
|
|
|
195
|
+
### MCP Tools (for IDE/agent integrations)
|
|
196
|
+
If using MCP instead of CLI: call \`project_brief\` (not \`npx codebase brief\`), \`get_next_task\`, \`refresh_status\`, \`list_skills\`. Full tool list via \`list_commands\` and \`list_skills\`.
|
|
197
|
+
|
|
186
198
|
### Browser Automation (agent-browser)
|
|
187
199
|
Commands: \`open <url>\`, \`snapshot -i\` (\u2192 \`@e1\`/\`@e2\` refs), \`click @e1\`, \`fill @e2 "text"\`, \`screenshot\`, \`auth save/login <profile>\`, \`state save/load <name>\`.
|
|
188
|
-
${
|
|
200
|
+
${ke}`}function Js(e,t){return Pt(it(e,t))}function Ws(e,t){let s=it(e,t),n=Pt(s)?Rt(s,"utf-8"):"";if(n.includes(Ie)){let i=n.indexOf(Ie),o=n.indexOf(ke);i!==-1&&o!==-1&&(n=n.slice(0,i)+n.slice(o+ke.length),n=n.replace(/\n{3,}/g,`
|
|
189
201
|
|
|
190
|
-
`).trimEnd())}
|
|
191
|
-
`+
|
|
192
|
-
`,"utf-8")}function
|
|
202
|
+
`).trimEnd())}Bs(s,n.trimEnd()+`
|
|
203
|
+
`+Cr(e)+`
|
|
204
|
+
`,"utf-8")}function Ks(e,t){let s=it(e,t);if(!Pt(s))return;let n=Rt(s,"utf-8"),i=n.indexOf(Ie),o=n.indexOf(ke);i!==-1&&o!==-1&&(n=n.slice(0,i)+n.slice(o+ke.length),n=n.replace(/\n{3,}/g,`
|
|
193
205
|
|
|
194
206
|
`).trim()+`
|
|
195
|
-
`,
|
|
196
|
-
${
|
|
207
|
+
`,Bs(s,n,"utf-8"))}var Ie,ke,vr,$r,xr,Ll,zs=D(()=>{"use strict";Ie="<!-- codebase:start -->",ke="<!-- codebase:end -->",vr="# codebase:start",$r="# codebase:end",xr=`
|
|
208
|
+
${Ie}
|
|
197
209
|
## Project Context (auto-generated by codebase)
|
|
198
210
|
|
|
199
211
|
**This project uses \`codebase\` for AI context. Run commands below instead of exploring files.**
|
|
@@ -214,11 +226,19 @@ Returns: project identity, tech stack, commands, structure, current status, next
|
|
|
214
226
|
| \`npx codebase issue create "title"\` | Track a bug, feature, or TODO |
|
|
215
227
|
| \`npx codebase issue close <n> --reason "why"\` | Close an issue after fixing it |
|
|
216
228
|
|
|
229
|
+
### Maintenance
|
|
230
|
+
| Command | What it does |
|
|
231
|
+
|---|---|
|
|
232
|
+
| \`codebase doctor\` | Health check \u2014 diagnose broken setup |
|
|
233
|
+
| \`codebase fix\` | Auto-repair issues found by doctor |
|
|
234
|
+
| \`codebase skills\` | List installed skills and their capabilities |
|
|
235
|
+
|
|
217
236
|
### Rules
|
|
218
237
|
- **Never explore the codebase to discover stack/commands/structure** \u2014 it's already in \`brief\`
|
|
219
238
|
- **Check \`next\` before starting work** \u2014 don't duplicate in-progress tasks
|
|
220
239
|
- **Create issues for bugs/TODOs you find** \u2014 keep the project brain alive
|
|
221
240
|
- **Close issues when you fix them** \u2014 with a reason so the team knows why
|
|
241
|
+
- **If any command fails, run \`codebase doctor\` then \`codebase fix\`** \u2014 self-heal before asking for help
|
|
222
242
|
|
|
223
243
|
### Vibekit Workflow
|
|
224
244
|
\`\`\`
|
|
@@ -228,10 +248,13 @@ Returns: project identity, tech stack, commands, structure, current status, next
|
|
|
228
248
|
- \`/build\` \u2014 Implements architectural issues autonomously. Runs until all \`arch\`+\`vibekit\` issues are closed.
|
|
229
249
|
- \`/launch\` \u2014 Gates on open bugs, generates GTM artifacts, creates GitHub release, merges to main.
|
|
230
250
|
|
|
251
|
+
### MCP Tools (for IDE/agent integrations)
|
|
252
|
+
If using MCP instead of CLI: call \`project_brief\` (not \`npx codebase brief\`), \`get_next_task\`, \`refresh_status\`, \`list_skills\`. Full tool list via \`list_commands\` and \`list_skills\`.
|
|
253
|
+
|
|
231
254
|
### Browser Automation (agent-browser)
|
|
232
255
|
Commands: \`open <url>\`, \`snapshot -i\` (\u2192 \`@e1\`/\`@e2\` refs), \`click @e1\`, \`fill @e2 "text"\`, \`screenshot\`, \`auth save/login <profile>\`, \`state save/load <name>\`.
|
|
233
|
-
${
|
|
234
|
-
${
|
|
256
|
+
${ke}`,Ll=`
|
|
257
|
+
${vr}
|
|
235
258
|
# Project Context (auto-generated by codebase)
|
|
236
259
|
#
|
|
237
260
|
# This project uses \`codebase\` for AI context. Run commands instead of exploring files.
|
|
@@ -247,17 +270,26 @@ ${Mo}
|
|
|
247
270
|
# npx codebase issue create "title" \u2192 Track bugs/features/TODOs
|
|
248
271
|
# npx codebase issue close <n> --reason "why" \u2192 Close after fixing
|
|
249
272
|
#
|
|
273
|
+
# MAINTENANCE:
|
|
274
|
+
# codebase doctor \u2192 Health check \u2014 diagnose broken setup
|
|
275
|
+
# codebase fix \u2192 Auto-repair issues found by doctor
|
|
276
|
+
# codebase skills \u2192 List installed skills and their capabilities
|
|
277
|
+
#
|
|
250
278
|
# RULES:
|
|
251
279
|
# - Never explore codebase to discover stack/commands \u2014 it's in brief
|
|
252
280
|
# - Check next before starting work \u2014 don't duplicate in-progress tasks
|
|
253
281
|
# - Create issues for bugs/TODOs \u2014 keep the project brain alive
|
|
254
282
|
# - Close issues when fixed \u2014 with a reason
|
|
255
|
-
|
|
283
|
+
# - If any command fails, run doctor then fix \u2014 self-heal before asking for help
|
|
284
|
+
#
|
|
285
|
+
# MCP TOOLS (for IDE/agent integrations):
|
|
286
|
+
# If using MCP: call project_brief, get_next_task, refresh_status, list_skills
|
|
287
|
+
${$r}`});var Vs={};Gt(Vs,{claudeIntegration:()=>te});var te,Ne=D(()=>{"use strict";zs();te={name:"claude",detect:e=>Js(e,"CLAUDE.md"),async inject(e){try{return Ws(e,"CLAUDE.md"),{ok:!0}}catch(t){return{ok:!1,message:t.message}}},remove:e=>Ks(e,"CLAUDE.md")}});import{readFileSync as Er,writeFileSync as Sr,existsSync as _r}from"fs";import{join as Rr}from"path";function we(e){let t=Rr(e,".gitignore"),s=_r(t)?Er(t,"utf-8"):"",n=!s.includes(Qs),i=!s.includes(Ys);if(!n&&!i)return;let o="";(n||i)&&(o+=`
|
|
256
288
|
# AI context manifest
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
${
|
|
289
|
+
`,n&&(o+=`${Qs}
|
|
290
|
+
`),i&&(o+=`${Ys}
|
|
291
|
+
`)),Sr(t,s.trimEnd()+o,"utf-8")}var Qs,Ys,ot=D(()=>{"use strict";Qs=".codebase.json",Ys=".codebase.cache.json"});import{readFileSync as Dt,writeFileSync as Fe,existsSync as ve,mkdirSync as en,chmodSync as tn,unlinkSync as Ul}from"fs";import{join as $e}from"path";function xe(e,t=!1){if(!ve($e(e,".git")))return!1;let n=`npx --yes codebase scan-only --incremental --quiet${t?" --sync":""}`;return Zs(e,"post-commit",n),Zs(e,"post-checkout",n),Pr(e),!0}function Pr(e){let t=$e(e,".git","hooks"),s=$e(t,"pre-commit");ve(t)||en(t,{recursive:!0});let n=$e(e,"package.json");if(!ve(n))return;let i=!1,o=!1,r=!1;try{let l=JSON.parse(Dt(n,"utf-8"));i=!!l.scripts?.check,o=!!l.scripts?.typecheck,r=!!l.scripts?.lint}catch{return}if(!i&&!o&&!r)return;let a;if(i)a="npm run check --silent";else{let l=[];o&&l.push("npm run typecheck --silent"),r&&l.push("npm run lint --silent"),a=l.join(" && ")}let c=`#!/bin/sh
|
|
292
|
+
${Xs}
|
|
261
293
|
# Run typecheck + lint before every commit. Fix errors before committing.
|
|
262
294
|
if [ -f package.json ]; then
|
|
263
295
|
${a} || {
|
|
@@ -268,21 +300,21 @@ if [ -f package.json ]; then
|
|
|
268
300
|
exit 1
|
|
269
301
|
}
|
|
270
302
|
fi
|
|
271
|
-
`;if(
|
|
303
|
+
`;if(ve(s)){let l=Dt(s,"utf-8");l.includes(Xs)||Fe(s,l.trimEnd()+`
|
|
272
304
|
|
|
273
|
-
`+c,"utf-8")}else
|
|
274
|
-
${s}`);
|
|
305
|
+
`+c,"utf-8")}else Fe(s,c,"utf-8");tn(s,493)}function Zs(e,t,s){let n=$e(e,".git","hooks"),i=$e(n,t);if(ve(n)||en(n,{recursive:!0}),ve(i)){let o=Dt(i,"utf-8");if(o.includes(Le)){let r=o.replace(new RegExp(`${Le}\\n.*`,"m"),`${Le}
|
|
306
|
+
${s}`);Fe(i,r,"utf-8");return}Fe(i,o.trimEnd()+`
|
|
275
307
|
|
|
276
|
-
${
|
|
308
|
+
${Le}
|
|
277
309
|
${s}
|
|
278
|
-
`,"utf-8")}else
|
|
310
|
+
`,"utf-8")}else Fe(i,`#!/bin/sh
|
|
279
311
|
|
|
280
|
-
${
|
|
312
|
+
${Le}
|
|
281
313
|
${s}
|
|
282
|
-
`,"utf-8");
|
|
283
|
-
`,"utf-8"),
|
|
284
|
-
Done! Your project is wired for AI + autonomous loop.`),
|
|
285
|
-
1. Review docs/PRODUCT.md and fill in any [INFERRED] sections
|
|
314
|
+
`,"utf-8");tn(i,493)}var Le,Xs,rt=D(()=>{"use strict";Le="# codebase-auto-update";Xs="# codebase-pre-commit"});var lt={};Gt(lt,{installClaudeCommandsForFix:()=>Ar,installClaudeHooksForFix:()=>Ir,installClaudeSkillsForFix:()=>Or,runSetup:()=>It});import{resolve as Dr,dirname as sn,join as I}from"path";import{writeFileSync as se,existsSync as J,mkdirSync as Me,readFileSync as ne,chmodSync as Ot,readdirSync as nn,copyFileSync as at}from"fs";import{execFile as ue}from"child_process";async function It(e){let t=Dr(e.path);await Oe({...e,sync:!0}),_("Claude Code Integration"),J(I(t,"CLAUDE.md"))||se(I(t,"CLAUDE.md"),`# Project Rules
|
|
315
|
+
`,"utf-8"),te.inject(t),y("CLAUDE.md - added .codebase.json reference"),_("Git Hooks"),xe(t,!1)?(y("post-commit hook (auto-updates .codebase.json)"),y("pre-commit hook (runs typecheck + lint before every commit)"),Nr(t),y("commit-msg hook (blocks direct commits to main/master)")):k("Not a git repository - skipping hooks"),_("Claude Code Hooks"),an(t),_("Browser Automation"),await Fr(),_("Claude Commands"),await Mr()?on(t):(S("Claude Code CLI not detected \u2014 skipping slash commands"),S("Install Claude Code then re-run: codebase setup")),_("Claude Skills"),rn(t),we(t),Lr(t,[".vibekit/daemon.lock",".vibekit/daemon.log",".vibekit/build.lock",".vibekit/milestone.env",".mcp.json"]),y(".gitignore updated"),_("Vibekit Bootstrap");let i=I(t,".vibekit");J(i)?k(".vibekit/ already exists"):(Me(i,{recursive:!0}),y(".vibekit/ directory created")),_("GitHub Labels"),await qr()?(await Tr(t),await Hr(t)):(S("gh CLI not authenticated \u2014 skipping label/issue setup"),S("Run: gh auth login then codebase setup")),_("Product Brief");let r=I(t,"docs");J(r)||Me(r,{recursive:!0});let a=I(r,"PRODUCT.md");J(a)?k("docs/PRODUCT.md already exists \u2014 skipping (delete to regenerate)"):(Gr(t,a),y("docs/PRODUCT.md generated \u2014 review and fill in [INFERRED] sections")),u(`
|
|
316
|
+
Done! Your project is wired for AI + autonomous loop.`),u(`
|
|
317
|
+
0. codebase brief \u2014 load project context (AI agents: call this first)`),u(" 1. Review docs/PRODUCT.md and fill in any [INFERRED] sections"),u(" 2. /simulate \u2014 AI customer journeys find & fix bugs"),u(" 3. /build \u2014 implement architectural issues autonomously"),u(" 4. /launch \u2014 gate check, release, merge to main")}function Ar(e){on(e)}function on(e){let t=I(sn(new URL(import.meta.url).pathname),"..","commands");if(!J(t)){S("Claude commands not found in package \u2014 skipping");return}let s=nn(t).filter(r=>r.endsWith(".md")),n=[{dir:I(e,".claude","commands"),label:".claude/commands/"},{dir:I(process.env.HOME??"~",".claude","commands"),label:"~/.claude/commands/"}],i=0,o=0;for(let{dir:r,label:a}of n){Me(r,{recursive:!0});let c=0,l=0,p=0;for(let f of s){let m=I(t,f),h=I(r,f);if(J(h)){let v=ne(m,"utf-8"),x=ne(h,"utf-8");v!==x?(at(m,h),l++):p++}else at(m,h),c++}let d=[];c>0&&d.push(`${c} new`),l>0&&d.push(`${l} updated`),p>0&&d.push(`${p} unchanged`),c>0||l>0?y(`Claude commands \u2192 ${a} (${d.join(", ")})`):k(`Claude commands up to date \u2192 ${a}`),i+=c,o+=l}(i>0||o>0)&&(k("Available: /setup /simulate /build /launch /review /vibeloop"),k("Tip: commit .claude/commands/ to share these with your team"))}function Or(e){rn(e)}function rn(e){let t=I(sn(new URL(import.meta.url).pathname),"..","skills");if(!J(t)){S("Skills not found in package \u2014 skipping");return}let s=nn(t).filter(a=>a.endsWith(".skill"));if(s.length===0){k("No skill files found in package");return}let n=[{dir:I(e,".claude","skills"),label:".claude/skills/"},{dir:I(process.env.HOME??"~",".claude","skills"),label:"~/.claude/skills/"}],i=0,o=0;for(let{dir:a,label:c}of n){Me(a,{recursive:!0});let l=0,p=0,d=0;for(let m of s){let h=I(t,m),v=I(a,m);if(J(v)){let x=ne(h),j=ne(v);x.equals(j)?d++:(at(h,v),p++)}else at(h,v),l++}let f=[];l>0&&f.push(`${l} new`),p>0&&f.push(`${p} updated`),d>0&&f.push(`${d} unchanged`),l>0||p>0?y(`Skills \u2192 ${c} (${f.join(", ")})`):k(`Skills up to date \u2192 ${c}`),i+=l,o+=p}let r=s.map(a=>a.replace(/\.skill$/,"")).join(", ");i>0||o>0?(k(`Available: ${r}`),k("Tip: commit .claude/skills/ to share these with your team")):k(`Available: ${r}`)}function Ir(e){an(e)}function an(e){let t=I(e,".claude","hooks");Me(t,{recursive:!0});let s=I(t,"git-guard.sh");se(s,`#!/bin/bash
|
|
286
318
|
# codebase git-guard \u2014 PreToolUse hook
|
|
287
319
|
# Reads Claude tool input JSON from stdin, enforces git safety rules.
|
|
288
320
|
|
|
@@ -349,7 +381,7 @@ if echo "$CMD" | grep -qE "^git commit|&& git commit| git commit"; then
|
|
|
349
381
|
fi
|
|
350
382
|
|
|
351
383
|
exit 0
|
|
352
|
-
`,"utf-8"),
|
|
384
|
+
`,"utf-8"),Ot(s,493),y(".claude/hooks/git-guard.sh (PreToolUse \u2014 blocks unsafe git ops)");let i=I(t,"git-post.sh");se(i,`#!/bin/bash
|
|
353
385
|
# codebase git-post \u2014 PostToolUse hook
|
|
354
386
|
# Reads Claude tool input JSON from stdin. Reminds to raise PR after branch push.
|
|
355
387
|
|
|
@@ -371,8 +403,8 @@ if echo "$CMD" | grep -qE "git push origin [a-zA-Z0-9/_-]+"; then
|
|
|
371
403
|
fi
|
|
372
404
|
|
|
373
405
|
exit 0
|
|
374
|
-
`,"utf-8"),
|
|
375
|
-
`,"utf-8"),
|
|
406
|
+
`,"utf-8"),Ot(i,493),y(".claude/hooks/git-post.sh (PostToolUse \u2014 PR reminder after branch push)");let r=I(e,".claude","settings.json"),a={};if(J(r))try{a=JSON.parse(ne(r,"utf-8"))}catch{}let c=a.hooks??{},l="bash .claude/hooks/git-guard.sh",p="bash .claude/hooks/git-post.sh",d=c.PreToolUse??[];JSON.stringify(d).includes("git-guard")||d.push({matcher:"Bash",hooks:[{type:"command",command:l}]}),c.PreToolUse=d;let m=c.PostToolUse??[];JSON.stringify(m).includes("git-post")||m.push({matcher:"Bash",hooks:[{type:"command",command:p}]}),c.PostToolUse=m,a.hooks=c,se(r,JSON.stringify(a,null,2)+`
|
|
407
|
+
`,"utf-8"),y(".claude/settings.json (PreToolUse + PostToolUse hooks registered)")}function Nr(e){let t=I(e,".git","hooks"),s=I(t,"commit-msg"),n="# codebase-branch-check",i=`#!/bin/sh
|
|
376
408
|
${n}
|
|
377
409
|
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
378
410
|
if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
|
|
@@ -383,18 +415,18 @@ if [ "$BRANCH" = "main" ] || [ "$BRANCH" = "master" ]; then
|
|
|
383
415
|
echo ""
|
|
384
416
|
exit 1
|
|
385
417
|
fi
|
|
386
|
-
`;if(
|
|
418
|
+
`;if(J(s)){let o=ne(s,"utf-8");o.includes(n)||se(s,o.trimEnd()+`
|
|
387
419
|
|
|
388
|
-
`+i,"utf-8")}else
|
|
389
|
-
`);i&&
|
|
420
|
+
`+i,"utf-8")}else se(s,i,"utf-8");Ot(s,493)}function Lr(e,t){let s=I(e,".gitignore"),n=J(s)?ne(s,"utf-8"):"",i=t.filter(o=>!n.includes(o)).join(`
|
|
421
|
+
`);i&&se(s,n.trimEnd()+`
|
|
390
422
|
`+i+`
|
|
391
|
-
`,"utf-8")}function
|
|
392
|
-
`).filter(Boolean)),n=0;for(let o of
|
|
423
|
+
`,"utf-8")}function ct(e,t){return new Promise(s=>{ue("gh",t,{cwd:e,timeout:15e3},(n,i)=>{s({ok:!n,stdout:(i||"").trim()})})})}async function Fr(){if(await new Promise(i=>{ue("agent-browser",["--version"],{timeout:5e3},o=>i(!o))})){k("agent-browser already installed");return}if(u("Installing agent-browser..."),!await new Promise(i=>{ue("npm",["install","-g","agent-browser"],{timeout:12e4},o=>i(!o))})){S("agent-browser install failed \u2014 run: npm install -g agent-browser");return}await new Promise(i=>{ue("agent-browser",["install"],{timeout:3e5},o=>i(!o))})?y("agent-browser installed (Chrome for Testing downloaded)"):S("agent-browser installed but Chrome download failed \u2014 run: agent-browser install"),await new Promise(i=>{ue("agent-browser",["--version"],{timeout:5e3},o=>i(!o))})||S("agent-browser validation failed \u2014 it may not be on PATH. Try: npm install -g agent-browser")}async function Mr(){return new Promise(e=>{ue("claude",["--version"],{timeout:5e3},t=>e(!t))})}async function qr(){return new Promise(e=>{ue("gh",["auth","status"],{timeout:5e3},t=>e(!t))})}async function Tr(e){let{stdout:t}=await ct(e,["label","list","--limit","100","--json","name","--jq",".[].name"]),s=new Set(t.split(`
|
|
424
|
+
`).filter(Boolean)),n=0;for(let o of At){if(s.has(o.name))continue;let{ok:r}=await ct(e,["label","create",o.name,"--color",o.color,"--description",o.description]);r&&n++}let i=At.length-n;n>0?y(`${n} GitHub labels created (${i} already existed)`):k(`All ${At.length} labels already exist`)}async function Hr(e){let{stdout:t}=await ct(e,["issue","list","--search","Highlights Index","--state","all","--limit","1","--json","number","--jq",".[0].number // empty"]);if(t){k("Highlights Index issue already exists");return}let s=`# Product Highlights Index
|
|
393
425
|
|
|
394
426
|
Tracks positive signals from /simulate cycles. Updated automatically \u2014 do not edit manually.
|
|
395
427
|
|
|
396
428
|
## Index
|
|
397
|
-
<!-- /simulate appends here -->`,{ok:n}=await
|
|
429
|
+
<!-- /simulate appends here -->`,{ok:n}=await ct(e,["issue","create","--title","Highlights Index","--label","highlight","--body",s]);n?y("Highlights Index issue created on GitHub"):S("Could not create Highlights Index issue")}function Gr(e,t){let s=I(e,".codebase.json"),n=null;if(J(s))try{n=JSON.parse(ne(s,"utf-8"))}catch{}let i=n?.project?.name??"[INFERRED: project name]",o=n?.project?.description??"[INFERRED: one-line description]",r=(n?.stack?.languages??[]).join(", ")||"[INFERRED]",a=(n?.stack?.frameworks??[]).join(", ")||"[INFERRED]",c=n?.commands?.dev??"[INFERRED]",l=n?.commands?.build??"[INFERRED]",p=n?.commands?.test??"[INFERRED]";se(t,`# PRODUCT.md \u2014 ${i}
|
|
398
430
|
|
|
399
431
|
> Auto-generated by \`codebase setup\`. Fill in any [INFERRED] sections.
|
|
400
432
|
|
|
@@ -432,8 +464,8 @@ ${o}
|
|
|
432
464
|
- **Languages:** ${r}
|
|
433
465
|
- **Frameworks:** ${a}
|
|
434
466
|
- **Dev command:** \`${c}\`
|
|
435
|
-
- **Build command:** \`${
|
|
436
|
-
- **Test command:** \`${
|
|
467
|
+
- **Build command:** \`${l}\`
|
|
468
|
+
- **Test command:** \`${p}\`
|
|
437
469
|
|
|
438
470
|
## Dev Credentials
|
|
439
471
|
|
|
@@ -443,127 +475,130 @@ ${o}
|
|
|
443
475
|
## Known Constraints
|
|
444
476
|
|
|
445
477
|
- [INFERRED: e.g. multi-tenant, RBAC, GDPR]
|
|
446
|
-
`,"utf-8")}var
|
|
447
|
-
${
|
|
478
|
+
`,"utf-8")}var At,qe=D(()=>{"use strict";_t();Ne();ot();rt();M();At=[{name:"bug",color:"d73a4a",description:"Something isn't working"},{name:"arch",color:"0075ca",description:"Architectural change needed"},{name:"sim",color:"e4e669",description:"Found by simulation"},{name:"carry",color:"ff6b35",description:"Bug surviving 2+ cycles"},{name:"cycle",color:"c5def5",description:"Simulation cycle summary"},{name:"critical",color:"b60205",description:"Critical severity"},{name:"high",color:"d93f0b",description:"High severity"},{name:"medium",color:"e99695",description:"Medium severity"},{name:"low",color:"fef2c0",description:"Low severity"},{name:"highlight",color:"0e8a16",description:"Positive product signal"},{name:"vibekit",color:"7057ff",description:"Queued for autonomous build"},{name:"performance",color:"ff8c00",description:"Performance issue"},{name:"review",color:"1d76db",description:"Found by code review"}]});M();var zn={scan:{description:"Scan project and update .codebase.json manifest (lightweight \u2014 no AI tool injection)",usage:"codebase scan [path] [options]",examples:[{command:"codebase scan",description:"Scan current directory"},{command:"codebase scan ./my-project",description:"Scan specific directory"},{command:"codebase scan --depth 6",description:"Include deeper directory structure"},{command:"codebase scan --categories stack,commands",description:"Scan only specific categories"}],options:[{flag:"--path <dir>",description:"Target project directory (default: current)"},{flag:"--depth <n>",description:"Directory tree depth (default: 4)"},{flag:"--categories <list>",description:"Comma-separated categories to scan"},{flag:"--incremental",description:"Only re-scan changed areas"},{flag:"--quiet",description:"Suppress stdout output"},{flag:"--sync",description:"Sync GitHub data (requires gh CLI)"}]},init:{description:"Initialize codebase with full setup (scan + AI tools + hooks)",usage:"codebase init [options]",examples:[{command:"codebase init",description:"One-time setup for current project"},{command:"codebase init --dry-run",description:"Preview changes without modifying files"},{command:"codebase init --sync",description:"Include GitHub data sync"}],options:[{flag:"--dry-run",description:"Preview changes without applying"},{flag:"--sync",description:"Sync GitHub data (requires gh CLI)"},{flag:"--quiet",description:"Suppress output"}],seeAlso:["scan","setup"]},setup:{description:"Wire .codebase.json into Claude Code and install slash commands",usage:"codebase setup [options]",examples:[{command:"codebase setup",description:"Configure Claude Code, git hooks, and slash commands"}],options:[{flag:"--dry-run",description:"Preview changes"}]},brief:{description:"Get comprehensive project briefing (AI-facing)",usage:"codebase brief",examples:[{command:"codebase brief",description:"Full project overview in one call"},{command:"codebase brief | jq '.stack'",description:"Extract specific section"}],seeAlso:["next","status"]},next:{description:"Show highest-priority task and what's in progress",usage:"codebase next",examples:[{command:"codebase next",description:"Show next task to work on"}],seeAlso:["brief","status"]},status:{description:"Show kanban board, priorities, and milestones",usage:"codebase status",examples:[{command:"codebase status",description:"Full project status"},{command:"codebase status --mine",description:"Show only my assigned tasks"}],options:[{flag:"--mine",description:"Show only your assigned items"}],seeAlso:["brief","next"]},query:{description:"Query specific field from manifest using dot-path",usage:"codebase query <path> [options]",examples:[{command:"codebase query stack.languages",description:'Get: ["typescript"]'},{command:"codebase query commands.test --force | sh",description:"Run test command"},{command:"codebase query dependencies.notable",description:"List notable packages"}],options:[{flag:"--force",description:"Plain text output (no JSON)"}]},issue:{description:"Manage GitHub issues",usage:"codebase issue <subcommand> [args]",examples:[{command:'codebase issue create "Fix auth bug"',description:"Create new issue"},{command:'codebase issue close 42 --reason "Fixed in PR #123"',description:"Close with reason"},{command:'codebase issue comment 42 --message "Fixed by refactoring auth flow"',description:"Add comment"},{command:"codebase issue list",description:"List all issues"},{command:"codebase issue list --mine",description:"List your issues"}],options:[{flag:"--message <text>",description:"Issue body (for create) or comment text"},{flag:"-m <text>",description:"Shorthand for --message"},{flag:"--reason <text>",description:"Close reason"}]},mcp:{description:"Start MCP server for AI tool integration",usage:"codebase mcp",examples:[{command:"codebase mcp",description:"Start stdio MCP server"}]},skills:{description:"List installed Claude skills",usage:"codebase skills",examples:[{command:"codebase skills",description:"List all installed skills with descriptions"}],seeAlso:["setup"]},doctor:{description:"Diagnose setup and configuration issues",usage:"codebase doctor",examples:[{command:"codebase doctor",description:"Run health check"}],seeAlso:["fix"]},fix:{description:"Auto-repair issues found by doctor",usage:"codebase fix",examples:[{command:"codebase fix",description:"Auto-fix all issues"}],seeAlso:["doctor"]},release:{description:"Gate check \u2192 tag \u2192 merge develop\u2192main \u2192 GitHub release",usage:"codebase release [version] [options]",examples:[{command:"codebase release",description:"Auto-increment version and release"},{command:"codebase release v1.2.0",description:"Release with explicit version"},{command:"codebase release --dry-run",description:"Preview release without tagging"}],options:[{flag:"--dry-run",description:"Preview release notes without creating tag or merge"}],seeAlso:["doctor"]}};function Jt(){console.log(`
|
|
479
|
+
${E("codebase")} \u2014 One command. Every AI tool understands your project instantly.
|
|
448
480
|
|
|
449
|
-
${
|
|
450
|
-
${
|
|
481
|
+
${E("QUICK START")}
|
|
482
|
+
${$("npx codebase")} \u2190 Run this once. That's it.
|
|
451
483
|
|
|
452
|
-
${
|
|
484
|
+
${E("AI INTERFACE")}
|
|
453
485
|
These are the commands your AI tools call:
|
|
454
486
|
|
|
455
|
-
${
|
|
456
|
-
${
|
|
457
|
-
${
|
|
458
|
-
${
|
|
459
|
-
|
|
460
|
-
${
|
|
461
|
-
After ${
|
|
462
|
-
|
|
463
|
-
${
|
|
464
|
-
${
|
|
465
|
-
${
|
|
466
|
-
${
|
|
467
|
-
${
|
|
468
|
-
|
|
469
|
-
${$("
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
${
|
|
473
|
-
${
|
|
474
|
-
${
|
|
475
|
-
|
|
476
|
-
${$("
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
${
|
|
480
|
-
${
|
|
481
|
-
|
|
482
|
-
${
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
${
|
|
486
|
-
${
|
|
487
|
-
${
|
|
488
|
-
|
|
489
|
-
${$("
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
${
|
|
493
|
-
|
|
494
|
-
${
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
${$("
|
|
500
|
-
`)
|
|
487
|
+
${$("codebase brief")} Full project briefing \u2014 run this first
|
|
488
|
+
${$("codebase next")} What should I work on next?
|
|
489
|
+
${$("codebase status")} Kanban board, priorities, milestones
|
|
490
|
+
${$("codebase query <path>")} Query any field (e.g. ${W("stack.languages")})
|
|
491
|
+
|
|
492
|
+
${E("AUTONOMOUS LOOP")}
|
|
493
|
+
After ${$("codebase setup")}, these slash commands are available in Claude Code:
|
|
494
|
+
|
|
495
|
+
${$("/setup")} Bootstrap project \u2014 labels, milestone, PRODUCT.md
|
|
496
|
+
${$("/simulate")} AI customer journeys (Playwright) + UX audit
|
|
497
|
+
${$("/build")} Autonomous loop \u2014 build \u2192 test \u2192 simulate \u2192 repeat
|
|
498
|
+
${$("/launch")} Gate check \u2192 tag \u2192 release \u2192 merge to main
|
|
499
|
+
${$("/review")} Security, quality, deps, accessibility audit
|
|
500
|
+
|
|
501
|
+
${$("codebase skills")} List installed Claude skills
|
|
502
|
+
|
|
503
|
+
${E("HUMAN COMMANDS")}
|
|
504
|
+
${$("codebase init")} Full setup (scan + AI tools + hooks)
|
|
505
|
+
${$("codebase scan")} Update .codebase.json only (lightweight)
|
|
506
|
+
${$("codebase setup")} Wire AI tools + install slash commands
|
|
507
|
+
${$("codebase release")} Gate check \u2192 tag \u2192 develop\u2192main
|
|
508
|
+
${$("codebase doctor")} Health check & diagnostics
|
|
509
|
+
|
|
510
|
+
${E("OPTIONS")}
|
|
511
|
+
${W("--help, -h")} Show this help or command-specific help
|
|
512
|
+
${W("--version, -v")} Show version
|
|
513
|
+
${W("--verbose")} Show detailed progress
|
|
514
|
+
${W("--quiet")} Suppress output
|
|
515
|
+
|
|
516
|
+
${E("EXAMPLES")}
|
|
517
|
+
${$("npx codebase")} # One-time setup
|
|
518
|
+
${$("codebase brief")} # Project overview
|
|
519
|
+
${$("codebase next")} # Next task
|
|
520
|
+
${$("codebase query commands.test --force | sh")} # Run tests
|
|
521
|
+
${$('codebase issue create "Fix bug"')} # Track work
|
|
522
|
+
|
|
523
|
+
${E("GLOBAL OPTIONS")}
|
|
524
|
+
${W("--path <dir>")} Target directory (default: current)
|
|
525
|
+
${W("--verbose")} Show detailed output
|
|
526
|
+
${W("--quiet")} Minimal output
|
|
527
|
+
|
|
528
|
+
${E("LEARN MORE")}
|
|
529
|
+
Docs: ${ze("https://github.com/ZySec-AI/codebase#readme","README.md")}
|
|
530
|
+
Issues: ${ze("https://github.com/ZySec-AI/codebase/issues","Report a bug")}
|
|
531
|
+
Commands: ${$("codebase <command> --help")} Show command-specific help
|
|
532
|
+
`)}function Wt(e){let t=zn[e];t||(console.error(`
|
|
533
|
+
${E("\u2717")} Unknown command: ${e}
|
|
534
|
+
`),console.log(` Run ${$("codebase --help")} to see all commands.
|
|
501
535
|
`),process.exit(1)),console.log(`
|
|
502
|
-
${
|
|
536
|
+
${E(e)} \u2014 ${t.description}
|
|
503
537
|
|
|
504
|
-
${
|
|
505
|
-
${
|
|
538
|
+
${E("USAGE")}
|
|
539
|
+
${W(t.usage)}
|
|
506
540
|
${t.examples.length>0?`
|
|
507
|
-
${
|
|
508
|
-
${t.examples.map(s=>` ${
|
|
541
|
+
${E("EXAMPLES")}
|
|
542
|
+
${t.examples.map(s=>` ${$(s.command)}${Bt(" # "+s.description)}`).join(`
|
|
509
543
|
`)}
|
|
510
544
|
`:""}${t.options?`
|
|
511
|
-
${
|
|
512
|
-
${t.options.map(s=>` ${
|
|
545
|
+
${E("OPTIONS")}
|
|
546
|
+
${t.options.map(s=>` ${W(s.flag.padEnd(25))} ${s.description}`).join(`
|
|
513
547
|
`)}
|
|
514
548
|
`:""}${t.seeAlso?`
|
|
515
|
-
${
|
|
516
|
-
${t.seeAlso.map(s
|
|
517
|
-
`:""}${
|
|
518
|
-
${
|
|
519
|
-
${
|
|
520
|
-
`)}var
|
|
521
|
-
${
|
|
522
|
-
> `);let o=(await
|
|
549
|
+
${E("SEE ALSO")}
|
|
550
|
+
${t.seeAlso.map(s=>$(s)).join(", ")}
|
|
551
|
+
`:""}${E("MORE HELP")}
|
|
552
|
+
${$("codebase --help")} Show all commands
|
|
553
|
+
${ze("https://github.com/ZySec-AI/codebase/docs","Full documentation")}
|
|
554
|
+
`)}var kc={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 Vn={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},Kt=new Set(["scan","setup","query","mcp","issue","status","init","scan-only","brief","next","doctor","fix","release","plan","skills"]);function zt(e){let t={...Vn},s=[];for(let n=0;n<e.length;n++){let i=e[n];if(!i.startsWith("-")&&Kt.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&&(Jt(),process.exit(0)),(i==="--version"||i==="-v")&&(console.log("codebase 0.2.0"),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&&Kt.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 Vt(e){Wt(e),process.exit(0)}M();import{get as Qn}from"https";import{readFileSync as kt,writeFileSync as Yn,mkdirSync as Xn}from"fs";import{homedir as Zn}from"os";import{join as Qt}from"path";import{execSync as Ve,spawnSync as ei}from"child_process";var Yt=Qt(Zn(),".codebase"),Xt=Qt(Yt,"update-check.json"),ti=1440*60*1e3,ce="codebase-ai",me=!!process.env.NO_COLOR,R={yellow:me?"":"\x1B[33m",cyan:me?"":"\x1B[36m",green:me?"":"\x1B[32m",bold:me?"":"\x1B[1m",dim:me?"":"\x1B[2m",reset:me?"":"\x1B[0m"};function si(){return"0.2.0"}function ni(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 ii(){try{return JSON.parse(kt(Xt,"utf8"))}catch{return null}}function oi(e){try{Xn(Yt,{recursive:!0}),Yn(Xt,JSON.stringify({version:e,checkedAt:Date.now()}))}catch{}}function ri(){return new Promise((e,t)=>{let s=Qn(`https://registry.npmjs.org/${ce}/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 ai(){try{let e=Ve("npm root -g 2>/dev/null",{encoding:"utf8"}).trim();if(e&&kt(`${e}/${ce}/package.json`,"utf8"))return`npm install -g ${ce}@latest`}catch{}try{Ve("pnpm --version 2>/dev/null",{encoding:"utf8"});let e=Ve("pnpm root -g 2>/dev/null",{encoding:"utf8"}).trim();if(e&&kt(`${e}/${ce}/package.json`,"utf8"))return`pnpm add -g ${ce}@latest`}catch{}try{return Ve("yarn --version 2>/dev/null",{encoding:"utf8"}),`yarn global add ${ce}@latest`}catch{}return`npm install -g ${ce}@latest`}function ci(e){let[t,...s]=e.split(" ");return ei(t,s,{stdio:"inherit"}).status===0}function li(){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 Zt(){if(process.env.CI||process.env.NO_UPDATE_CHECK||process.env.CODEBASE_NO_UPDATE_CHECK||!process.stdout.isTTY||!process.stdin.isTTY)return;let e=si(),t=ii(),s;if(t&&Date.now()-t.checkedAt<ti)s=t.version;else try{s=await ri(),oi(s)}catch{return}if(!ni(s,e))return;let n=ai();console.log(`
|
|
555
|
+
${R.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${R.reset}`),console.log(` ${R.yellow}\u2502${R.reset} ${R.bold}Update available${R.reset} ${R.dim}${e}${R.reset} ${R.yellow}\u2192${R.reset} ${R.bold}${R.cyan}${s}${R.reset}`),console.log(` ${R.yellow}\u2502${R.reset} Press ${R.bold}Y${R.reset} to update now, any other key to skip`),console.log(` ${R.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${R.reset}`),process.stdout.write(`
|
|
556
|
+
> `);let o=(await li()).toLowerCase()==="y";if(console.log(o?"Updating\u2026":`Skipped.
|
|
523
557
|
`),!o)return;console.log(`
|
|
524
|
-
${
|
|
525
|
-
`);let r=
|
|
526
|
-
${
|
|
558
|
+
${R.dim}$ ${n}${R.reset}
|
|
559
|
+
`);let r=ci(n);console.log(r?`
|
|
560
|
+
${R.green}\u2713${R.reset} ${R.bold}Updated to ${s}!${R.reset} Restart codebase to use the new version.
|
|
527
561
|
`:`
|
|
528
|
-
${
|
|
529
|
-
`),process.exit(0)}
|
|
530
|
-
`);let
|
|
531
|
-
`)
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
`),
|
|
536
|
-
`),
|
|
537
|
-
`),
|
|
562
|
+
${R.yellow}!${R.reset} Update failed. Run manually: ${R.bold}${n}${R.reset}
|
|
563
|
+
`),process.exit(0)}_t();qe();Ae();import{resolve as Br,join as de}from"path";import{existsSync as ut,writeFileSync as Jr,readFileSync as un}from"fs";import{execFile as ln}from"child_process";import{writeFile as Nt,rename as Wr}from"fs/promises";import{homedir as Kr}from"os";Ne();var Ur=[te];function cn(e){return Ur.filter(t=>t.detect(e))}Ne();ot();rt();M();function zr(e){if(!ut(de(e,".codebase.json")))return!1;let t=de(e,"CLAUDE.md");if(ut(t))try{let s=un(t,"utf-8"),n=s.includes("<!-- codebase:start -->")&&s.includes("<!-- codebase:end -->"),i=s.includes("# codebase:start")&&s.includes("# codebase:end");if(n||i)return!0}catch{}return!1}async function dn(e){Q(e.quiet);let t=Br(e.path);if(zr(t)&&!e.force){_(`codebase \u2014 refreshing project manifest
|
|
564
|
+
`);let h=await je()==="authenticated";u(`Scanning ${t}...`);let v=await K(t,{depth:e.depth,categories:e.categories.length?e.categories:void 0,quiet:e.quiet,sync:h}),x=de(t,".codebase.json"),j=JSON.stringify(v,null,2);await Nt(x,j,"utf-8");let g=(Buffer.byteLength(j)/1024).toFixed(1);y(`Manifest refreshed \u2014 .codebase.json (${g} KB)`),k("Already initialized. Run with --force to force full re-setup.");return}_(`codebase \u2014 activating project intelligence
|
|
565
|
+
`);let s=await je();s==="authenticated"?y("GitHub CLI \u2014 authenticated"):s==="not-authenticated"?(S("GitHub CLI installed but not logged in"),k("Run: gh auth login"),k("After login, re-run `npx codebase` for full GitHub integration\n")):(k("GitHub CLI not found \u2014 GitHub features disabled"),k(`To enable: brew install gh && gh auth login
|
|
566
|
+
`));let n=s==="authenticated";u(`Scanning ${t}...`);let i=await K(t,{depth:e.depth,categories:e.categories.length?e.categories:void 0,quiet:e.quiet,sync:n});for(let[m,h]of Object.entries(i))m==="version"||m==="generated_at"||typeof h!="object"||h===null||y(`${Vr(m)} (${nt(m,h)})`);let o=de(t,".codebase.json"),r=JSON.stringify(i,null,2);await Nt(o,r,"utf-8");let a=(Buffer.byteLength(r)/1024).toFixed(1);u(`
|
|
567
|
+
Written: .codebase.json (${a} KB)`),_("AI Tool Integration");let c=cn(t),l=Qr(),p=new Set(c.map(m=>m.name));for(let m of l)p.has(m.name)||(c.push(m),p.add(m.name));c.length===0?(k("No AI tool detected in project or system configs"),k("Creating CLAUDE.md as default (works with Claude Code, and readable by all tools)"),Jr(de(t,"CLAUDE.md"),`# Project Rules
|
|
568
|
+
|
|
569
|
+
`,"utf-8"),c=[te]):u(` Detected: ${c.map(m=>m.name).join(", ")}`);for(let m of c){let h=await m.inject(t);h.ok?y(`${m.name} \u2014 instructions injected`):S(`${m.name} \u2014 injection failed: ${h.message||"unknown error"}`)}_("MCP Server (native AI tool access)");let d=await Lt(t,p);if(d.length){for(let m of d)y(`${m} \u2014 MCP server auto-configured`);k("AI tools can now call project_brief, get_next_task, create_issue, etc. natively")}else k("AI tools will read .codebase.json directly."),k("To enable MCP later, add to your tool's MCP config:"),u(' { "command": "npx", "args": ["codebase", "mcp"] }');if(_("Auto-Update Hooks"),xe(t,n)?(y("post-commit hook \u2014 manifest updates on every commit"),y("post-checkout hook \u2014 manifest updates on branch switch"),n&&y("hooks include GitHub sync \u2014 issues/PRs stay current")):k("Not a git repository \u2014 skipping hooks"),we(t),y(".gitignore updated"),_(`Ready!
|
|
570
|
+
`),u(`Your project is now fully activated. Here's what happens automatically:
|
|
571
|
+
`),u(" On every commit \u2192 .codebase.json updates (code + GitHub data)"),u(" On branch switch \u2192 .codebase.json updates"),u(" When AI starts \u2192 reads .codebase.json or calls project_brief via MCP"),u(" AI knows \u2192 stack, commands, open issues, priorities, blockers, decisions"),u(` AI can \u2192 create issues, close issues, get next task, check blockers
|
|
572
|
+
`),n){let m=i.status?.issues?.filter(v=>v.state==="open").length||0,h=i.status?.pull_requests?.filter(v=>v.state==="open").length||0;(m||h)&&u(` GitHub synced: ${m} open issues, ${h} open PRs`)}u(`
|
|
538
573
|
You don't need to run this again. Everything stays alive.
|
|
539
|
-
`)}function
|
|
540
|
-
`,"utf-8"),!0}import{resolve as
|
|
574
|
+
`)}function Vr(e){return e.charAt(0).toUpperCase()+e.slice(1)}function je(){return new Promise(e=>{ln("sh",["-c","which gh 2>/dev/null"],{timeout:5e3},t=>{if(t){e("not-installed");return}ln("sh",["-c","gh auth status 2>&1"],{timeout:1e4},(s,n,i)=>{let o=(n||"")+(i||"");!s&&o.includes("Logged in")?e("authenticated"):e("not-authenticated")})})})}function Qr(){let e=Kr(),t=[];return ut(de(e,".claude"))&&t.push(te),t}async function Lt(e,t){let s=[],n={command:"npx",args:["codebase","mcp"],cwd:e};if(t.has("claude")||t.size===0){let i=de(e,".mcp.json");await Yr(i,"codebase",n)&&s.push("Claude Code (project .mcp.json)")}return s}async function Yr(e,t,s){let n={};if(ut(e)){try{n=JSON.parse(un(e,"utf-8"))}catch{n={}}let o=n.mcpServers;if(o&&o[t])return!1}n.mcpServers||(n.mcpServers={}),n.mcpServers[t]=s;let i=`${e}.tmp`;return await Nt(i,JSON.stringify(n,null,2)+`
|
|
575
|
+
`,"utf-8"),await Wr(i,e),!0}import{resolve as Xr,join as Zr}from"path";import{readFile as ea}from"fs/promises";function dt(e){let t=[],s=e.project?.name||"Unknown Project";t.push(`# PROJECT BRIEF: ${s}`),e.project?.description&&t.push(e.project.description),t.push(`
|
|
541
576
|
Generated: ${e.generated_at}
|
|
542
577
|
`),t.push("## Technical Overview");let n=[];if(e.repo?.url&&(n.push(`Repository: ${e.repo.url}`),n.push(`Default branch: ${e.repo.default_branch||"unknown"}`),e.repo.is_monorepo&&n.push(`Monorepo: yes (${e.repo.workspace_manager||"workspaces"})`)),e.stack){let o=[];e.stack.languages?.length&&o.push(`Languages: ${e.stack.languages.join(", ")}`),e.stack.frameworks?.length&&o.push(`Frameworks: ${e.stack.frameworks.join(", ")}`),e.stack.package_manager&&o.push(`Package manager: ${e.stack.package_manager}`),e.stack.database&&o.push(`Database: ${e.stack.database}`),e.stack.orm&&o.push(`ORM: ${e.stack.orm}`),e.stack.styling&&o.push(`Styling: ${e.stack.styling}`),e.stack.build_tool&&o.push(`Build tool: ${e.stack.build_tool}`),n.push(o.join(`
|
|
543
578
|
`))}if(e.patterns&&(e.patterns.architecture&&n.push(`Architecture: ${e.patterns.architecture}`),e.patterns.state_management&&n.push(`State management: ${e.patterns.state_management}`),e.patterns.api_style&&n.push(`API style: ${e.patterns.api_style}`)),t.push(n.join(`
|
|
544
579
|
`)),e.commands){let o=Object.entries(e.commands).filter(([,r])=>r);if(o.length){t.push(`
|
|
545
580
|
## Commands`);for(let[r,a]of o)t.push(`- ${r}: \`${a}\``)}}if(e.structure&&(t.push(`
|
|
546
581
|
## Key Paths`),e.structure.entry_points?.length&&t.push(`Entry points: ${e.structure.entry_points.join(", ")}`),e.patterns?.key_modules&&Object.keys(e.patterns.key_modules).length))for(let[o,r]of Object.entries(e.patterns.key_modules))t.push(`- ${o} \u2192 ${r}`);if(e.status&&e.status.github_available){let o=[],r=e.status.kanban?.in_progress||[];if(r.length){o.push(`
|
|
547
|
-
### In Progress NOW`);for(let
|
|
548
|
-
### NEXT TASK (highest priority)`);let
|
|
549
|
-
### Backlog (${
|
|
550
|
-
### BLOCKERS`);for(let
|
|
551
|
-
### Open PRs (${
|
|
582
|
+
### In Progress NOW`);for(let f of r){let m=f.assignee?` \u2192 @${f.assignee}`:"",h=f.mapped_files?.length?` (files: ${f.mapped_files.join(", ")})`:"";o.push(`- #${f.number}: ${f.title}${m}${h}`)}}let c=(e.status.priorities||[])[0];if(c){o.push(`
|
|
583
|
+
### NEXT TASK (highest priority)`);let f=c.labels.length?` [${c.labels.join(", ")}]`:"";if(o.push(`#${c.number}: ${c.title}${f}`),c.body){let m=c.body.length>300?c.body.slice(0,300)+"\u2026":c.body;o.push(m)}c.mapped_files?.length&&o.push(`Start in: ${c.mapped_files.join(", ")}`)}let l=e.status.kanban?.backlog||[];if(l.length>0){o.push(`
|
|
584
|
+
### Backlog (${l.length} items)`);for(let f of l.slice(0,5)){let m=f.labels.length?` [${f.labels.join(", ")}]`:"";o.push(`- #${f.number}: ${f.title}${m}`)}l.length>5&&o.push(` ... and ${l.length-5} more`)}let p=(e.status.issues||[]).filter(f=>f.state==="open"&&f.labels.some(m=>m.toLowerCase().includes("blocked")||m.toLowerCase().includes("blocker")));if(p.length){o.push(`
|
|
585
|
+
### BLOCKERS`);for(let f of p)o.push(`- #${f.number}: ${f.title} [${f.labels.join(", ")}]`)}let d=(e.status.pull_requests||[]).filter(f=>f.state==="open");if(d.length){o.push(`
|
|
586
|
+
### Open PRs (${d.length})`);for(let f of d.slice(0,5)){let m=f.reviewers.length?` \u2192 waiting on: ${f.reviewers.join(", ")}`:"";o.push(`- PR #${f.number}: ${f.title} (${f.branch})${m}`)}}o.length>0&&(t.push(`
|
|
552
587
|
## CURRENT STATUS`),t.push(...o))}if(e.roadmap?.milestones?.length){t.push(`
|
|
553
588
|
## Roadmap`);for(let o of e.roadmap.milestones){let r=o.due_date?` (due: ${o.due_date.split("T")[0]})`:"";t.push(`- ${o.title}: ${o.progress.percent}% complete (${o.progress.closed}/${o.progress.open+o.progress.closed} done)${r}`)}}let i=[...e.decisions?.from_prs||[],...e.decisions?.from_adrs||[],...e.decisions?.manual||[]];if(i.length){t.push(`
|
|
554
589
|
## Recent Decisions`);for(let o of i.slice(0,5))t.push(`- ${o.title} (${o.source})`),o.summary&&t.push(` ${o.summary.slice(0,150)}`)}if(e.git&&(e.git.uncommitted_changes&&(t.push(`
|
|
555
590
|
## WARNING`),t.push("There are uncommitted changes in the working directory.")),e.git.recent_commits?.length)){t.push(`
|
|
556
|
-
## Recent Commits`);for(let o of e.git.recent_commits.slice(0,3))t.push(`- ${o}`)}return t.
|
|
557
|
-
|
|
558
|
-
`)}
|
|
559
|
-
|
|
560
|
-
${
|
|
561
|
-
`);return}let o=
|
|
591
|
+
## Recent Commits`);for(let o of e.git.recent_commits.slice(0,3))t.push(`- ${o}`)}return t.join(`
|
|
592
|
+
`)}M();async function pn(e){let t=Xr(e.path),s=Zr(t,".codebase.json"),n;try{let r=await ea(s,"utf-8");n=JSON.parse(r)}catch{C("No .codebase.json found (or it's corrupted). Run `npx codebase` first."),process.exit(1)}!e.quiet&&!n.status&&!n.roadmap&&S("GitHub data unavailable (gh not authenticated or --sync not used). Issues, PRs and milestones not included.");let i=n;e.categories.length>0&&(i=ta(n,e.categories));let o=sa(i,e.format);process.stdout.write(o+`
|
|
593
|
+
`)}function ta(e,t){let s={version:e.version,generated_at:e.generated_at,project:e.project},n={project:"project",repo:"repo",structure:"structure",stack:"stack",commands:"commands",dependencies:"dependencies",config:"config",git:"git",quality:"quality",patterns:"patterns",status:"status",roadmap:"roadmap",decisions:"decisions"};for(let i of t){let o=n[i.toLowerCase()];o&&e[o]&&(s[o]=e[o])}return s}function sa(e,t){return t==="json"?JSON.stringify(e,null,2):dt(e)}M();De();import{resolve as na,join as ia}from"path";import{readFile as oa}from"fs/promises";async function fn(e){let t=na(e.path),s;try{let l=await oa(ia(t,".codebase.json"),"utf-8");s=JSON.parse(l)}catch{C("No .codebase.json found (or it's corrupted). Run `npx codebase` first."),process.exit(1)}let n=s.status;if(!n||!n.github_available){k("No GitHub data. Run `npx codebase` with `gh` CLI authenticated.");return}let i=n.kanban?.in_progress||[];if(i.length){u(E("IN PROGRESS (don't duplicate):"));for(let l of i){let p=l.assignee?` \u2192 @${l.assignee}`:"";u(` #${l.number}: ${l.title}${p}`)}u("")}let o=n.priorities??[];if(!o.length){let l=(s.status?.issues??[]).filter(p=>p.state==="open");o=Pe(l)}let r=o[0];if(!r){u("No open tasks in the backlog. Create one:"),u(' codebase issue create "task title"');return}if(u(E("NEXT TASK:")),u(` #${r.number}: ${r.title}`),r.labels.length&&u(` Labels: ${r.labels.join(", ")}`),r.effort){let l={S:"Small (hours)",M:"Medium (days)",L:"Large (weeks)"}[r.effort];u(` Effort: ${l}`)}r.assignee&&u(` Assignee: @${r.assignee}`),r.milestone&&u(` Milestone: ${r.milestone}`),r.mapped_files?.length&&u(` Start in: ${r.mapped_files.join(", ")}`);let a=n.kanban?.needs_verify??[];if(a.length>0){u(`
|
|
594
|
+
${E("NEEDS VERIFY (simulate to close):")}`);for(let l of a.slice(0,5))u(` #${l.number}: ${l.title}`)}let c=n.issues?.filter(l=>l.state==="open"&&l.labels.some(p=>p.toLowerCase().includes("blocked")||p.toLowerCase().includes("blocker")))||[];if(c.length){u(`
|
|
595
|
+
${E("BLOCKERS:")}`);for(let l of c)u(` #${l.number}: ${l.title} [${l.labels.join(", ")}]`)}}import{resolve as ra,join as aa}from"path";import{readFile as ca}from"fs/promises";function pt(e,t){let s=t.split("."),n=e;for(let i of s){if(n==null||typeof n!="object")return;n=n[i]}return n}M();async function mn(e){let t=ra(e.path),s=aa(t,".codebase.json"),n;try{let r=await ca(s,"utf-8");n=JSON.parse(r)}catch{C("No .codebase.json found (or it's corrupted). Run `npx codebase` first."),process.exit(1)}let i=e.positionals[0];if(!i){process.stdout.write(JSON.stringify(n,null,2)+`
|
|
596
|
+
`);return}let o=pt(n,i);o===void 0&&(C(`Path "${i}" not found in manifest.`),process.exit(1)),e.force?typeof o=="string"?process.stdout.write(o+`
|
|
562
597
|
`):Array.isArray(o)?process.stdout.write(o.join(`
|
|
563
598
|
`)+`
|
|
564
599
|
`):process.stdout.write(JSON.stringify(o)+`
|
|
565
600
|
`):process.stdout.write(JSON.stringify(o,null,2)+`
|
|
566
|
-
`)}import{resolve as
|
|
601
|
+
`)}import{resolve as ua}from"path";M();import{execFile as la}from"child_process";function Te(e,t){return new Promise((s,n)=>{la("gh",t,{cwd:e,timeout:3e4},(i,o,r)=>{i?n(new Error(r||i.message)):s(o.trim())})})}async function gn(e,t,s,n){let i=s||`## Summary
|
|
567
602
|
|
|
568
603
|
${t}
|
|
569
604
|
|
|
@@ -577,36 +612,53 @@ ${t}
|
|
|
577
612
|
|
|
578
613
|
## Actual
|
|
579
614
|
|
|
580
|
-
`,o=["issue","create","--title",t,"--body",i];n?.length&&o.push("--label",n.join(","));try{let r=await
|
|
615
|
+
`,o=["issue","create","--title",t,"--body",i];n?.length&&o.push("--label",n.join(","));try{let r=await Te(e,o);y(`Created issue: ${r}`)}catch(r){C(`Failed to create issue: ${r.message}`)}}async function hn(e,t,s){try{let n=["issue","close",t];s&&n.push("--comment",s),await Te(e,n),y(`Closed issue #${t}`)}catch(n){C(`Failed to close issue: ${n.message}`)}}async function bn(e,t){try{let s=["issue","list","--limit","30"];t==="mine"&&s.push("--assignee","@me");let n=await Te(e,s);n?u(n):u("No issues found.")}catch(s){C(`Failed to list issues: ${s.message}`)}}async function yn(e,t,s){try{await Te(e,["issue","comment",t,"--body",s]),y(`Comment added to issue #${t}`)}catch(n){C(`Failed to comment on issue: ${n.message}`)}}async function kn(e,t,s){try{let n=`**Mapped files:**
|
|
581
616
|
${s.map(i=>`- \`${i}\``).join(`
|
|
582
|
-
`)}`;await
|
|
583
|
-
${
|
|
584
|
-
${
|
|
585
|
-
${
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
617
|
+
`)}`;await Te(e,["issue","comment",t,"--body",n]),y(`Mapped issue #${t} to ${s.length} files`)}catch(n){C(`Failed to map issue: ${n.message}`)}}M();async function wn(e){let t=ua(e.path);switch(e.subcommand){case"create":{let s=e.positionals[0];s||(C('Usage: codebase issue create "Issue title" [--message "body"]'),process.exit(1)),await gn(t,s,e.message||void 0);break}case"close":{let s=e.positionals[0];s||(C('Usage: codebase issue close <number> [--reason "reason"]'),process.exit(1)),await hn(t,s,e.reason||void 0);break}case"comment":{let s=e.positionals[0],n=e.message;(!s||!n)&&(C('Usage: codebase issue comment <number> --message "text"'),process.exit(1)),await yn(t,s,n);break}case"list":{let s=e.positionals[0];await bn(t,s);break}case"map":{let s=e.positionals[0],n=e.positionals.slice(1);(!s||n.length===0)&&(C("Usage: codebase issue map <number> <file1> <file2> ..."),process.exit(1)),await kn(t,s,n);break}default:C("Usage: codebase issue create|close|comment|list|map"),process.exit(1)}}De();M();import{resolve as da,join as vn}from"path";import{readFile as $n,writeFile as pa,rename as fa}from"fs/promises";async function xn(e){let t=da(e.path),s=null;try{s=JSON.parse(await $n(vn(t,".codebase.json"),"utf-8"))}catch{}if(!s?.status){k("Syncing from GitHub...");let o=await be(t);if(o||(C("Could not sync. Is `gh` CLI installed and authenticated?"),process.exit(1)),o&&s){s.status=o.status,s.roadmap=o.roadmap,s.decisions=o.decisions;try{let r=vn(t,".codebase.json"),c={...JSON.parse(await $n(r,"utf-8")),status:o.status,roadmap:o.roadmap,decisions:o.decisions},l=r+".tmp";await pa(l,JSON.stringify(c,null,2),"utf-8"),await fa(l,r)}catch{}}}let n=s?.status;if(!n){C("No status data available.");return}let i=e.positionals[0];(i==="kanban"||!i)&&ma(n),(i==="priorities"||!i)&&ga(n),i==="milestones"&&s?.roadmap&&ha(s.roadmap),i==="decisions"&&s?.decisions&&ba(s.decisions)}function ma(e){_("Kanban Board");let{kanban:t}=e;u(`
|
|
618
|
+
${E("BACKLOG")} (${t.backlog.length})`);for(let n of t.backlog.slice(0,10))u(` #${n.number} ${n.title}`);u(`
|
|
619
|
+
${E("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}`)}let s=t.needs_verify??[];if(s.length>0){u(`
|
|
620
|
+
${E("NEEDS VERIFY")} (${s.length})`);for(let n of s.slice(0,10))u(` #${n.number} ${n.title}`)}u(`
|
|
621
|
+
${E("DONE")} (${t.done.length} recent)`);for(let n of t.done.slice(0,5))u(` #${n.number} ${n.title}`)}function ga(e){_("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 ha(e){_("Milestones");for(let t of e.milestones){let s=ya(t.progress.percent),n=t.due_date?` (due: ${t.due_date.split("T")[0]})`:"";u(`
|
|
622
|
+
${E(t.title)} ${s} ${t.progress.percent}%${n}`),u(` ${t.progress.closed}/${t.progress.open+t.progress.closed} issues closed`)}}function ba(e){_("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 ya(e){let t=Math.round(e/5),s=20-t;return`[${"\u2588".repeat(t)}${"\u2591".repeat(s)}]`}import{resolve as Ra}from"path";import{createInterface as ka}from"readline";import{readFile as Ge,writeFile as mt,rename as gt}from"fs/promises";import{existsSync as ft,readdirSync as jn}from"fs";import{join as z,resolve as Cn}from"path";import{homedir as En}from"os";import{execFile as _n}from"child_process";Ae();De();var wa=[{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 structured project data. Use 'category' to get a specific section: repo, structure, stack, commands, dependencies, config, git, quality, patterns, status, roadmap, decisions. Use 'fields' for sparse selection within a category, e.g. fields: ['languages', 'frameworks']. Without category returns everything.",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. 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'"}},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 Rn(e){let t=ka({input:process.stdin,terminal:!1});for await(let s of t){if(!s.trim())continue;let n;try{n=JSON.parse(s)}catch{Sn({jsonrpc:"2.0",id:0,error:{code:-32700,message:"Parse error"}});continue}let i=await va(n,e);i&&Sn(i)}}async function va(e,t){switch(e.method){case"initialize":return O(e.id,{protocolVersion:"2024-11-05",serverInfo:{name:"codebase",version:"0.1.0"},capabilities:{tools:{}}});case"notifications/initialized":return null;case"tools/list":return O(e.id,{tools:wa});case"tools/call":return $a(e,t);default:return{jsonrpc:"2.0",id:e.id,error:{code:-32601,message:`Method not found: ${e.method}`}}}}async function $a(e,t){let s=e.params||{},n=s.name,i=s.arguments||{};try{switch(n){case"project_brief":{let o=await He(t,!0),r=dt(o);return O(e.id,{content:[{type:"text",text:r}]})}case"get_codebase":{let o=await He(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 He(t),r=i.path,a=pt(o,r);return O(e.id,{content:[{type:"text",text:JSON.stringify(a??null,null,2)}]})}case"get_next_task":{let o=await He(t,!0),r=ja(o);return O(e.id,{content:[{type:"text",text:JSON.stringify(r,null,2)}]})}case"get_blockers":{let o=await He(t,!0),r=Ca(o);return O(e.id,{content:[{type:"text",text:JSON.stringify(r,null,2)}]})}case"create_issue":{let o=await Ea(t,i);return await Mt(t),O(e.id,{content:[{type:"text",text:o}]})}case"close_issue":{let o=await Sa(t,i);return await Mt(t),O(e.id,{content:[{type:"text",text:o}]})}case"update_issue":{let o=await _a(t,i);return await Mt(t),O(e.id,{content:[{type:"text",text:o}]})}case"list_commands":{let o=z(t,".claude","commands"),r=z(En(),".claude","commands"),a=new Set,c=[];for(let p of[o,r])if(ft(p))for(let d of jn(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}
|
|
623
|
+
|
|
624
|
+
Loop: /simulate \u2192 /build \u2192 /launch`}]})}case"list_skills":{let o=z(En(),".claude","skills"),r=z(t,".claude","skills"),a=new Set,c=[];for(let p of[r,o])if(ft(p))for(let d of jn(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(f=>{let m=z(d,p);_n("unzip",["-p",m,"*/SKILL.md"],{timeout:1e4},(h,v)=>{if(h||!v.trim()){f();return}let x=v.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!x){f();return}let j=x[1],g=j.match(/^name:\s*(.+)$/m),G=j.match(/^description:\s*(.+)$/m),w=g?g[1].trim():p.replace(/\.skill$/,""),A=G?G[1].trim():"";l.push({name:w,description:A,file:p}),f()})}))),O(e.id,{content:[{type:"text",text:JSON.stringify(l,null,2)}]})}case"get_plan":{let o=z(Cn(t),"PLAN.md");if(!ft(o))return O(e.id,{content:[{type:"text",text:"No PLAN.md found. Use update_plan to create one."}]});let r=await Ge(o,"utf-8");return O(e.id,{content:[{type:"text",text:r}]})}case"update_plan":{let o=z(Cn(t),"PLAN.md"),r=i.message,c=`
|
|
625
|
+
<!-- updated: ${new Date().toISOString().split("T")[0]} -->
|
|
626
|
+
${r.trim()}
|
|
627
|
+
`,l;if(!ft(o))l=`# PLAN.md \u2014 Autonomous Loop State
|
|
628
|
+
|
|
629
|
+
> Managed by Claude. Updated each build/simulate cycle.
|
|
630
|
+
|
|
631
|
+
## Current Sprint
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
## In Flight
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
## Decisions Log
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
## Blocked
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
## Update Log
|
|
644
|
+
${c}`;else{let d=await Ge(o,"utf-8");d.includes("## Update Log")?l=d.replace(/(## Update Log\n)/,`$1${c}`):l=d+`
|
|
645
|
+
## Update Log
|
|
646
|
+
${c}`}let p=o+".tmp";return await mt(p,l,"utf-8"),await gt(p,o),O(e.id,{content:[{type:"text",text:"PLAN.md updated."}]})}case"get_issue":{let o=i.number,r=await Y(t,["issue","view",String(o),"--json","number,title,state,body,labels,assignees,milestone,comments,url"]),a=JSON.parse(r);return O(e.id,{content:[{type:"text",text:JSON.stringify(a,null,2)}]})}case"get_pr":{let o=i.number,r=await Y(t,["pr","view",String(o),"--json","number,title,state,body,author,labels,reviewRequests,reviewDecision,statusCheckRollup,additions,deletions,comments,url"]),a=JSON.parse(r);return O(e.id,{content:[{type:"text",text:JSON.stringify(a,null,2)}]})}case"rescan_project":{let o=i.sync!==!1,r=await K(t,{quiet:!0,sync:o,incremental:i.incremental===!0}),a=z(t,".codebase.json"),c=a+".tmp";return await mt(c,JSON.stringify(r,null,2),"utf-8"),await gt(c,a),O(e.id,{content:[{type:"text",text:`Project rescanned. Manifest updated at ${r.generated_at}`}]})}case"refresh_status":{let o=z(t,".codebase.json"),r=await be(t);if(r){let a=await Ge(o,"utf-8"),c=JSON.parse(a);c.status=r.status,c.roadmap=r.roadmap,c.decisions=r.decisions;let l=c;l.generated_at=new Date().toISOString();let p=o+".tmp";await mt(p,JSON.stringify(l,null,2),"utf-8"),await gt(p,o)}return O(e.id,{content:[{type:"text",text:`GitHub data refreshed at ${new Date().toISOString()}`}]})}default:return{jsonrpc:"2.0",id:e.id,error:{code:-32602,message:`Unknown tool: ${n}`}}}}catch(o){return O(e.id,{content:[{type:"text",text:`Error: ${o.message}`}],isError:!0})}}var Ft=Number(process.env.CODEBASE_MANIFEST_TTL_HOURS),xa=(Number.isFinite(Ft)&&Ft>0?Ft:24)*60*60*1e3;async function He(e,t=!1){try{let s=await Ge(z(e,".codebase.json"),"utf-8"),n=JSON.parse(s);return n.generated_at&&Date.now()-new Date(n.generated_at).getTime()<=xa?n:await K(e,{quiet:!0,sync:t})}catch{return await K(e,{quiet:!0,sync:t})}}function ja(e){let t=(e.status?.issues||[]).filter(c=>c.state==="open"),s=e.status?.priorities?.length?e.status.priorities:Pe(t);if(!s.length)return{summary:"No open issues found. The project has no tracked tasks. You can create issues with the create_issue tool when you identify work to do.",task:null,queue:[]};let n=s[0],i=s.slice(1,4).map(c=>({number:c.number,title:c.title,labels:c.labels})),o=[`NEXT TASK: #${n.number} \u2014 ${n.title}`];n.labels.length&&o.push(`[${n.labels.join(", ")}]`),n.assignee&&o.push(`(assigned to @${n.assignee})`),n.mapped_files?.length&&o.push(`Start in: ${n.mapped_files.join(", ")}`);let r=n.effort?{S:"Small (hours)",M:"Medium (days)",L:"Large (weeks)"}[n.effort]:void 0;r&&o.push(`Effort: ${r}`);let a=(e.status?.kanban?.needs_verify??[]).map(c=>({number:c.number,title:c.title}));return{summary:o.join(" "),task:{number:n.number,title:n.title,labels:n.labels,effort:n.effort,assignee:n.assignee,mapped_files:n.mapped_files||[],url:n.url,body:n.body||""},queue:i,needs_verify:a}}function Ca(e){let t=(e.status?.issues||[]).filter(c=>c.state==="open"&&c.labels.some(l=>l.toLowerCase().includes("blocked")||l.toLowerCase().includes("blocker"))),s=(e.status?.pull_requests||[]).filter(c=>c.state==="open"&&c.reviewers.length>0&&c.review_decision!=="approved"),n=(e.status?.pull_requests||[]).filter(c=>c.state==="open"&&c.checks_status==="failing"),i=(e.status?.pull_requests||[]).filter(c=>c.state==="open"&&c.merge_conflicts===!0),o=e.git?.uncommitted_changes??!1,r=t.length>0||s.length>0||n.length>0||i.length>0||o,a=[];return r?(t.length&&a.push(`${t.length} blocked issue(s)`),s.length&&a.push(`${s.length} PR(s) awaiting review`),n.length&&a.push(`${n.length} PR(s) with failing checks`),i.length&&a.push(`${i.length} PR(s) with merge conflicts`),o&&a.push("uncommitted changes in working directory")):a.push("No blockers found. All clear to proceed with the next task."),{summary:a.join(", "),has_blockers:r,blocked_issues:t.map(c=>({number:c.number,title:c.title,labels:c.labels,url:c.url})),prs_waiting_review:s.map(c=>({number:c.number,title:c.title,reviewers:c.reviewers,url:c.url})),prs_failing_checks:n.map(c=>({number:c.number,title:c.title,url:c.url})),prs_with_conflicts:i.map(c=>({number:c.number,title:c.title,url:c.url})),uncommitted_changes:o}}function Y(e,t){return new Promise((s,n)=>{_n("gh",t,{cwd:e,timeout:3e4},(i,o,r)=>{i?n(new Error(r||i.message)):s(o.trim())})})}async function Ea(e,t){let s=t.title,n=t.body||s,i=t.labels,o=["issue","create","--title",s,"--body",n];if(i?.length){let a=i.filter(c=>!c.includes(","));a.length&&o.push("--label",a.join(","))}return`Issue created: ${await Y(e,o)}`}async function Sa(e,t){let s=t.number,n=t.comment;return n&&await Y(e,["issue","comment",String(s),"--body",n]),await Y(e,["issue","close",String(s)]),`Issue #${s} closed.`}async function _a(e,t){let s=t.number,n=t.add_labels,i=t.remove_labels,o=t.assignee,r=[];if(n?.length&&(await Y(e,["issue","edit",String(s),"--add-label",n.join(",")]),r.push(`added labels: ${n.join(", ")}`)),i?.length&&(await Y(e,["issue","edit",String(s),"--remove-label",i.join(",")]),r.push(`removed labels: ${i.join(", ")}`)),o!==void 0)if(o===""){let a=await Y(e,["issue","view",String(s),"--json","assignees"]),{assignees:c}=JSON.parse(a);for(let l of c)await Y(e,["issue","edit",String(s),"--remove-assignee",l.login]);r.push("unassigned all assignees")}else await Y(e,["issue","edit",String(s),"--add-assignee",o]),r.push(`assigned to @${o}`);return r.length===0?`Issue #${s}: no changes requested.`:`Issue #${s} updated: ${r.join("; ")}.`}async function Mt(e){try{let t=z(e,".codebase.json"),s=await Ge(t,"utf-8"),n=JSON.parse(s);n.generated_at="1970-01-01T00:00:00.000Z";let i=t+".tmp";await mt(i,JSON.stringify(n,null,2),"utf-8"),await gt(i,t)}catch{}}function O(e,t){return{jsonrpc:"2.0",id:e,result:t}}function Sn(e){process.stdout.write(JSON.stringify(e)+`
|
|
647
|
+
`)}async function Pn(e){let t=Ra(e.path);await Rn(t)}import{resolve as Pa,join as q}from"path";import{homedir as Da}from"os";import{existsSync as H,readFileSync as X,statSync as Dn,readdirSync as An}from"fs";M();var Aa="# codebase-auto-update";async function In(e){Q(e.quiet);let t=Pa(e.path),s=[];_(`codebase doctor
|
|
648
|
+
`);let n=q(t,".codebase.json"),i=null;if(H(n))try{let b=X(n,"utf-8");i=JSON.parse(b);let P=Dn(n),N=(P.size/1024).toFixed(1),F=Date.now()-P.mtimeMs,Ke=Ma(F);s.push({label:"Manifest",ok:!0,detail:`.codebase.json (${N} KB, ${Ke})`})}catch{s.push({label:"Manifest",ok:!1,detail:"Corrupted \u2014 run `codebase fix`"})}else s.push({label:"Manifest",ok:!1,detail:"Missing \u2014 run `codebase fix`"});if(i){let b=i.generated_at?new Date(i.generated_at).getTime():0,P=(Date.now()-b)/(1e3*60*60),N=!1;if(H(q(t,"src")))try{Dn(q(t,"src")).mtimeMs>b&&(N=!0)}catch{}N?s.push({label:"Freshness",ok:!1,detail:`Stale (${Math.round(P)} hours old)`}):s.push({label:"Freshness",ok:!0,detail:"Up to date"});let F=["project","repo","structure","stack","commands","dependencies","config","git","quality","patterns"],Ke=F.filter(fe=>fe in i);if(Ke.length===F.length)s.push({label:"Detectors",ok:!0,detail:"10/10 categories present"});else{let fe=F.filter(Jn=>!Ke.includes(Jn));s.push({label:"Detectors",ok:!1,detail:`Missing: ${fe.join(", ")}`})}let yt=i._warnings;if(Array.isArray(yt)&&yt.length>0)for(let fe of yt)s.push({label:"Detector Warning",ok:!1,detail:`(non-fatal) ${fe}`})}let o=await je(),r=o==="authenticated";if(o==="authenticated"?s.push({label:"GitHub CLI",ok:!0,detail:"Authenticated"}):o==="not-authenticated"?s.push({label:"GitHub CLI",ok:!1,detail:"Not authenticated \u2014 run `gh auth login`"}):s.push({label:"GitHub CLI",ok:!1,detail:"Not installed \u2014 brew install gh"}),i){let b=i.repo?.url,P=i.status?.github_available,N=b?.includes("github.com");N&&P===!1?s.push({label:"GitHub Sync",ok:!1,detail:"Repo has GitHub remote but github_available is false"}):!N&&P===!0?s.push({label:"GitHub Sync",ok:!1,detail:"No GitHub remote but github_available is true"}):s.push({label:"GitHub Sync",ok:!0,detail:"Consistent"})}let a=Oa(t);s.push({label:"Claude Code",ok:a,detail:a?"CLAUDE.md injected":"CLAUDE.md injection missing \u2014 run `codebase fix`"});let c=Ia(t);if(s.push({label:"MCP",ok:c,detail:c?".mcp.json configured":".mcp.json missing \u2014 run `codebase fix`"}),H(q(t,".git"))){let b=On(t,"post-commit"),P=On(t,"post-checkout"),N=Fa(t);if(b&&P){let F=r&&N?" (with --sync)":"";s.push({label:"Git Hooks",ok:!0,detail:`post-commit + post-checkout${F}`})}else{let F=[];b||F.push("post-commit"),P||F.push("post-checkout"),s.push({label:"Git Hooks",ok:!1,detail:`${F.join(" + ")} missing`})}r&&b&&!N&&s.push({label:"Hook Sync",ok:!1,detail:"Missing --sync flag"})}else s.push({label:"Git Hooks",ok:!0,detail:"Not a git repo \u2014 skipped"});if(H(q(t,".git"))&&(Na(t)?s.push({label:"Branch Hook",ok:!0,detail:"commit-msg blocks direct commits to main/master"}):s.push({label:"Branch Hook",ok:!1,detail:"commit-msg hook missing \u2014 run `codebase fix`"})),H(q(t,".git"))){let b=La(t);(()=>{try{let N=JSON.parse(X(q(t,"package.json"),"utf-8"));return!!(N.scripts?.check||N.scripts?.typecheck||N.scripts?.lint)}catch{return!1}})()?b?s.push({label:"Pre-commit",ok:!0,detail:"Runs lint + typecheck before every commit"}):s.push({label:"Pre-commit",ok:!1,detail:"pre-commit hook missing \u2014 run `codebase fix`"}):s.push({label:"Pre-commit",ok:!0,detail:"No lint/typecheck scripts \u2014 skipped"})}let l=q(t,".claude","commands");if(H(l)){let b=An(l).filter(P=>P.endsWith(".md"));s.push({label:"Claude Commands",ok:b.length>0,detail:`${b.length} commands in .claude/commands/`})}else s.push({label:"Claude Commands",ok:!1,detail:".claude/commands/ missing \u2014 run `codebase setup`"});let p=q(Da(),".claude","skills");if(H(p)){let b=An(p).filter(P=>P.endsWith(".skill"));if(b.length>0){let P=b.map(N=>N.replace(/\.skill$/,"")).join(", ");s.push({label:"Claude Skills",ok:!0,detail:`${b.length} skill${b.length>1?"s":""} installed: ${P}`})}else s.push({label:"Claude Skills",ok:!1,detail:"No skills installed \u2014 run: codebase setup"})}else s.push({label:"Claude Skills",ok:!1,detail:"No skills installed \u2014 run: codebase setup"});let d=q(t,".claude","hooks","git-guard.sh"),f=q(t,".claude","hooks","git-post.sh"),m=q(t,".claude","settings.json"),h=H(d)&&H(f),v=(()=>{if(!H(m))return!1;try{let b=JSON.parse(X(m,"utf-8")),P=JSON.stringify(b.hooks?.PreToolUse??""),N=JSON.stringify(b.hooks?.PostToolUse??"");return P.includes("git-guard")&&N.includes("git-post")}catch{return!1}})();if(h&&v)s.push({label:"Claude Hooks",ok:!0,detail:"git-guard + git-post wired in settings.json"});else{let b=[];h||b.push("hook scripts"),v||b.push("settings.json wiring"),s.push({label:"Claude Hooks",ok:!1,detail:`Missing: ${b.join(", ")} \u2014 run \`codebase setup\``})}let x=q(t,".gitignore");H(x)?X(x,"utf-8").includes(".codebase.json")?s.push({label:"Gitignore",ok:!0,detail:".codebase.json in .gitignore"}):s.push({label:"Gitignore",ok:!1,detail:".codebase.json not in .gitignore"}):s.push({label:"Gitignore",ok:!1,detail:".gitignore missing"});let j=!!process.env.NO_COLOR,g=j?"":"\x1B[32m",G=j?"":"\x1B[31m",w=j?"":"\x1B[0m",A=s.filter(b=>!b.ok);for(let b of s){let P=b.ok?`${g}\u2713${w}`:`${G}\u2717${w}`,N=(b.label.startsWith(" ")," "),F=b.label.startsWith(" ")?18:16;u(`${N}${b.label.trimStart().padEnd(F)} ${P} ${b.detail}`)}u(""),A.length===0?u(" All checks passed. Your project is healthy."):u(` ${A.length} issue${A.length>1?"s":""} found. Run \`codebase fix\` to repair.`),u(""),A.length>0&&process.exit(1)}function Oa(e){let t=q(e,"CLAUDE.md");return H(t)?X(t,"utf-8").includes("<!-- codebase:start -->"):!1}function Ia(e){let t=q(e,".mcp.json");if(!H(t))return!1;try{return!!JSON.parse(X(t,"utf-8")).mcpServers?.codebase}catch{return!1}}function On(e,t){let s=q(e,".git","hooks",t);return H(s)?X(s,"utf-8").includes(Aa):!1}function Na(e){let t=q(e,".git","hooks","commit-msg");return H(t)?X(t,"utf-8").includes("codebase-branch-check"):!1}function La(e){let t=q(e,".git","hooks","pre-commit");return H(t)?X(t,"utf-8").includes("codebase-pre-commit"):!1}function Fa(e){let t=q(e,".git","hooks","post-commit");return H(t)?X(t,"utf-8").includes("--sync"):!1}function Ma(e){let t=Math.floor(e/1e3);if(t<60)return`${t} sec ago`;let s=Math.floor(t/60);if(s<60)return`${s} min ago`;let n=Math.floor(s/60);if(n<24)return`${n} hr ago`;let i=Math.floor(n/24);return`${i} day${i>1?"s":""} ago`}Ae();import{resolve as qa,join as U}from"path";import{homedir as Ta}from"os";import{existsSync as B,readFileSync as oe,readdirSync as Ha}from"fs";import{writeFile as Ga}from"fs/promises";rt();ot();M();var Ua="# codebase-auto-update",Ln=!!process.env.NO_COLOR,Ba=Ln?"":"\x1B[32m",Ja=Ln?"":"\x1B[0m";function ie(e){console.log(` ${Ba}\u2713${Ja} ${e}`)}async function Fn(e){Q(e.quiet);let t=qa(e.path),s=0;_(`codebase fix
|
|
649
|
+
`);let n=await je(),i=n==="authenticated";n==="not-installed"?(k("GitHub CLI not installed \u2014 install with: brew install gh"),k(`(Cannot auto-fix \u2014 requires manual installation)
|
|
650
|
+
`)):n==="not-authenticated"&&(k("GitHub CLI not authenticated \u2014 run: gh auth login"),k(`(Cannot auto-fix \u2014 requires manual login)
|
|
651
|
+
`));let o=U(t,".codebase.json"),r=!1;if(!B(o))r=!0;else try{let w=oe(o,"utf-8");JSON.parse(w)}catch{r=!0}if(!r&&B(o))try{let w=oe(o,"utf-8"),A=JSON.parse(w),b=A.generated_at?new Date(A.generated_at).getTime():0;if(B(U(t,"src"))){let{statSync:P}=await import("fs");P(U(t,"src")).mtimeMs>b&&(r=!0)}}catch{r=!0}if(r){let w=await K(t,{depth:e.depth,quiet:!0,sync:i}),A=JSON.stringify(w,null,2);await Ga(o,A,"utf-8");let b=(Buffer.byteLength(A)/1024).toFixed(1);ie(`Re-scanned project \u2192 .codebase.json (${b} KB)`),s++}let{claudeIntegration:a}=await Promise.resolve().then(()=>(Ne(),Vs));Wa(t)||(a.inject(t),ie("Re-injected Claude Code instructions into CLAUDE.md"),s++);let l=await Lt(t,new Set(["claude"]));for(let w of l)ie(`Added MCP entry to ${w}`),s++;if(B(U(t,".git"))){let w=Nn(t,"post-commit"),A=Nn(t,"post-checkout"),b=Ka(t),P=za(t);if(!w||!A||i&&!b||!P){xe(t,i);let F=[];w||F.push("post-commit"),A||F.push("post-checkout"),i&&!b&&F.push("--sync flag"),P||F.push("pre-commit"),ie(`Installed ${F.join(" + ")} hook${F.length>1?"s":""}`),s++}}let p=U(t,".gitignore");(B(p)?oe(p,"utf-8"):"").includes(".codebase.json")||(we(t),ie("Added .codebase.json to .gitignore"),s++);let f=U(t,".claude","commands");if(!B(f)){let{installClaudeCommandsForFix:w}=await Promise.resolve().then(()=>(qe(),lt));w(t),ie("Installed Claude commands \u2192 .claude/commands/"),s++}let m=U(Ta(),".claude","skills");if(!(B(m)&&Ha(m).some(w=>w.endsWith(".skill")))){let{installClaudeSkillsForFix:w}=await Promise.resolve().then(()=>(qe(),lt));w(t),ie("Installed Claude skills \u2192 ~/.claude/skills/"),s++}let v=U(t,".claude","hooks","git-guard.sh"),x=U(t,".claude","hooks","git-post.sh"),j=U(t,".claude","settings.json"),g=B(v)&&B(x),G=(()=>{if(!B(j))return!1;try{let w=JSON.parse(oe(j,"utf-8")),A=JSON.stringify(w.hooks?.PreToolUse??""),b=JSON.stringify(w.hooks?.PostToolUse??"");return A.includes("git-guard")&&b.includes("git-post")}catch{return!1}})();if(!g||!G){let{installClaudeHooksForFix:w}=await Promise.resolve().then(()=>(qe(),lt));w(t),ie("Installed Claude Code hooks \u2192 .claude/hooks/ + settings.json"),s++}u(""),s===0?u(" Nothing to fix. Your project is healthy."):u(` Fixed ${s} issue${s>1?"s":""}. Run \`codebase doctor\` to verify.`),u("")}function Wa(e){let t=U(e,"CLAUDE.md");return B(t)?oe(t,"utf-8").includes("<!-- codebase:start -->"):!1}function Nn(e,t){let s=U(e,".git","hooks",t);return B(s)?oe(s,"utf-8").includes(Ua):!1}function Ka(e){let t=U(e,".git","hooks","post-commit");return B(t)?oe(t,"utf-8").includes("--sync"):!1}function za(e){let t=U(e,".git","hooks","pre-commit");return B(t)?oe(t,"utf-8").includes("codebase-pre-commit"):!1}M();import{resolve as Va,join as Be}from"path";import{execFile as Je}from"child_process";import{existsSync as Tt,readFileSync as ht,writeFileSync as Qa}from"fs";async function Mn(e){let t=Va(e.path),s=e.dryRun,n=e.positionals[0]??null;_(`codebase release${s?" (dry run)":""}`),await Ya()||(C("gh CLI not authenticated. Run: gh auth login"),process.exit(1)),await Ue(t,"remote","get-url","origin")||(C("No git remote. Run: git remote add origin <url>"),process.exit(1)),u(`
|
|
652
|
+
Checking launch gates...`);let r=Be(t,".codebase.json");if(Tt(r)&&!e.dryRun)try{let G=(JSON.parse(ht(r,"utf-8")).status?.issues||[]).filter(w=>w.state==="open"&&w.labels.some(A=>A.toLowerCase().includes("bug")));if(G.length>0&&!e.force){C(`Gate 1a FAILED \u2014 ${G.length} open bug issue(s) in manifest`);for(let w of G.slice(0,5))u(` #${w.number}: ${w.title} [${w.labels.join(", ")}]`);u(`
|
|
653
|
+
Fix: resolve open bugs or run /simulate. Use --force to skip this gate.`),process.exit(1)}}catch{}let[a,c]=await Promise.all([qt(t,["bug","critical"]),qt(t,["bug","high"])]);(a>0||c>0)&&(C("Gate 1a FAILED \u2014 open blocking bugs:"),a>0&&u(` Critical: ${a}`),c>0&&u(` High: ${c}`),u(`
|
|
654
|
+
Fix: run /simulate, or close with wontfix label`),process.exit(1)),y("Gate 1a \u2014 no open bugs");let l=Xa(t);if(l){let g=await Za(t,l);g.ok||(C("Gate 1b FAILED \u2014 test suite has failures"),u(g.output.split(`
|
|
603
655
|
`).slice(-10).join(`
|
|
604
|
-
`)),
|
|
605
|
-
Fix: run /review to repair failing tests`),process.exit(1)),
|
|
606
|
-
All gates passed.`);let
|
|
607
|
-
Release version: ${
|
|
608
|
-
--- DRY RUN \u2014 release notes preview ---`),
|
|
609
|
-
codebase release ${
|
|
656
|
+
`)),u(`
|
|
657
|
+
Fix: run /review to repair failing tests`),process.exit(1)),y(`Gate 1b \u2014 tests pass (${l})`)}else S("Gate 1b \u2014 no test runner detected (skipping)");let p=await ec(t);p!==null&&p<7&&(C(`Gate 1c FAILED \u2014 world-class score ${p}/10 (minimum 7.0)`),u(" Fix: run /simulate to improve UX score"),process.exit(1)),p!==null?y(`Gate 1c \u2014 world-class score ${p}/10`):S("Gate 1c \u2014 no simulation data yet (run /simulate first)");let d=await qt(t,["carry"]);d>0?S(`Gate 2 \u2014 ${d} carry bug(s) will appear in release notes`):y("Gate 2 \u2014 no carry bugs");let f=await Ue(t,"status","--short");f&&(C("Gate 3 FAILED \u2014 uncommitted changes"),u(f),process.exit(1)),await Ue(t,"fetch","origin","develop"),await Ue(t,"log","HEAD..origin/develop","--oneline")&&(C("Gate 3 FAILED \u2014 branch is behind origin/develop"),u(" Fix: git pull origin develop"),process.exit(1)),y("Gate 3 \u2014 branch clean and current"),u(`
|
|
658
|
+
All gates passed.`);let h=n??await tc(t);u(`
|
|
659
|
+
Release version: ${h}`);let v=await sc(t,h,d);if(s){u(`
|
|
660
|
+
--- DRY RUN \u2014 release notes preview ---`),u(v),u("--- DRY RUN \u2014 no tag, no merge, no GitHub release created ---");return}await pe(t,["tag","-a",h,"-m",`Release ${h}`]),await pe(t,["push","origin",h]),y(`Tagged ${h}`),await pe(t,["checkout","main"]),await pe(t,["pull","origin","main"]),await pe(t,["merge","develop","--no-ff","-m",`Release ${h}`]),await pe(t,["push","origin","main"]),await pe(t,["checkout","develop"]),y("Merged develop \u2192 main");let{ok:x,stdout:j}=await Z(t,["release","create",h,"--title",h,"--notes",v,"--target","develop"]);x?y(`GitHub release: ${j}`):S("Could not create GitHub release \u2014 tag and merge succeeded"),await nc(t),u(`
|
|
661
|
+
codebase release ${h} complete.`),u("develop \u2192 main merged. Tag pushed. Ready.")}function Ue(e,...t){return new Promise(s=>{Je("git",t,{cwd:e,timeout:3e4},(n,i)=>{s(n?"":i.trim())})})}function pe(e,t){return new Promise((s,n)=>{Je("git",t,{cwd:e,timeout:3e4},(i,o,r)=>{i?n(new Error(r||i.message)):s()})})}function Z(e,t){return new Promise(s=>{Je("gh",t,{cwd:e,timeout:3e4},(n,i)=>{s({ok:!n,stdout:(i||"").trim()})})})}async function Ya(){return new Promise(e=>{Je("gh",["auth","status"],{timeout:5e3},t=>e(!t))})}async function qt(e,t){let{stdout:s}=await Z(e,["issue","list","--label",t.join(","),"--state","open","--limit","100","--json","number","--jq","length"]);return parseInt(s,10)||0}function Xa(e){try{let t=JSON.parse(ht(Be(e,"package.json"),"utf-8"));if(t.devDependencies?.vitest||t.dependencies?.vitest)return"npx vitest run";if(t.devDependencies?.jest||t.dependencies?.jest)return"npx jest";if(t.scripts?.test)return"npm test"}catch{}if(Tt(Be(e,"pyproject.toml")))try{if(ht(Be(e,"pyproject.toml"),"utf-8").includes("pytest"))return"uv run pytest"}catch{}return null}function Za(e,t){let[s,...n]=t.split(" ");return new Promise(i=>{Je(s,n,{cwd:e,timeout:12e4},(o,r,a)=>{i({ok:!o,output:r+a})})})}async function ec(e){let{stdout:t}=await Z(e,["issue","list","--label","cycle","--state","all","--limit","1","--json","body","--jq",".[0].body // empty"]);if(!t)return null;let s=t.match(/[Ww]orld[- ]class[^0-9]*([0-9]+(?:\.[0-9]+)?)\/10/);return s?parseFloat(s[1]):null}async function tc(e){let t=await Ue(e,"describe","--tags","--abbrev=0");if(!t)return"v0.1.0";let s=t.match(/^v?(\d+)\.(\d+)\.(\d+)$/);return s?`v${s[1]}.${s[2]}.${parseInt(s[3],10)+1}`:"v0.1.0"}async function sc(e,t,s){let n=new Date().toISOString().split("T")[0],[i,o,r,a]=await Promise.all([Z(e,["issue","list","--label","arch","--state","closed","--limit","50","--json","number,title","--jq",'.[] | "- #(.number) (.title)"']),Z(e,["issue","list","--label","bug,sim","--state","closed","--limit","50","--json","number,title","--jq",'.[] | "- #(.number) (.title)"']),Z(e,["issue","list","--label","carry","--state","open","--limit","20","--json","number,title","--jq",'.[] | "- #(.number) (.title)"']),Z(e,["issue","list","--label","arch","--state","open","--limit","20","--json","number,title","--jq",'.[] | "- #(.number) (.title)"'])]),c=`# Release ${t} \u2014 ${n}
|
|
610
662
|
|
|
611
663
|
`;return i.stdout&&(c+=`## What's New
|
|
612
664
|
|
|
@@ -624,16 +676,40 @@ ${r.stdout}
|
|
|
624
676
|
`),a.stdout&&(c+=`### Pending Architecture
|
|
625
677
|
${a.stdout}
|
|
626
678
|
|
|
627
|
-
`)),c}async function
|
|
679
|
+
`)),c}async function nc(e){let t=Be(e,".vibekit","milestone.env");if(!Tt(t))return;let s=ht(t,"utf-8"),n=s.match(/MILESTONE_NUMBER=(\d+)/),i=s.match(/MILESTONE_TITLE=(v[\d.]+)/);if(!n||!i)return;let{stdout:o}=await Z(e,["repo","view","--json","nameWithOwner","--jq",".nameWithOwner"]);if(!o)return;await Z(e,["api",`repos/${o}/milestones/${n[1]}`,"-X","PATCH","-f","state=closed"]),k(`Milestone ${i[1]} closed`);let r=i[1].match(/^v(\d+)\.(\d+)$/);if(!r)return;let a=`v${r[1]}.${parseInt(r[2],10)+1}`,{stdout:c}=await Z(e,["api",`repos/${o}/milestones`,"-X","POST","-f",`title=${a}`,"-f","state=open","-f","description=Next release cycle \u2014 managed by vibekit","--jq",".number"]);c&&(Qa(t,`MILESTONE_NUMBER=${c}
|
|
628
680
|
MILESTONE_TITLE=${a}
|
|
629
|
-
`,"utf-8"),
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
681
|
+
`,"utf-8"),y(`Next milestone created: ${a}`))}M();import{resolve as ic,join as oc}from"path";import{readFile as Tn,writeFile as qn}from"fs/promises";import{existsSync as Hn}from"fs";var rc="PLAN.md";async function Gn(e){let t=ic(e.path),s=oc(t,rc);if(e.message){await ac(s,e.message);return}if(!Hn(s)){k("No PLAN.md found. Create one by running:"),u(""),u(' codebase plan --message "Started sprint. Working on auth refactor."'),u(""),u("Or create PLAN.md manually with the vibeloop schema:"),u(" ## Current Sprint"),u(" ## In Flight"),u(" ## Decisions Log"),u(" ## Blocked");return}let n=await Tn(s,"utf-8");_("PLAN.md"),u(n)}async function ac(e,t){let n=`
|
|
682
|
+
<!-- updated: ${new Date().toISOString().split("T")[0]} -->
|
|
683
|
+
${t.trim()}
|
|
684
|
+
`;if(!Hn(e)){let o=`# PLAN.md \u2014 Autonomous Loop State
|
|
685
|
+
|
|
686
|
+
> Managed by Claude. Updated each build/simulate cycle.
|
|
687
|
+
|
|
688
|
+
## Current Sprint
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
## In Flight
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
## Decisions Log
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
## Blocked
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
## Update Log
|
|
701
|
+
${n}`;await qn(e,o,"utf-8"),u(`${E("Created")} PLAN.md`);return}let i=await Tn(e,"utf-8");i.includes("## Update Log")?i=i.replace(/(## Update Log\n)/,`$1${n}`):i+=`
|
|
702
|
+
## Update Log
|
|
703
|
+
${n}`,await qn(e,i,"utf-8"),u(`${E("Updated")} PLAN.md`)}M();import{join as Ht,resolve as cc}from"path";import{existsSync as lc,readdirSync as uc}from"fs";import{execFile as dc}from"child_process";function pc(e){return new Promise((t,s)=>{dc("unzip",["-p",e,"*/SKILL.md"],(n,i)=>{n&&!i?s(n):t(i??"")})})}function fc(e){let t=e.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!t)return{};let s={};for(let n of t[1].split(`
|
|
704
|
+
`)){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 Un(e){let t=Ht(process.env.HOME??"~",".claude","skills"),s=Ht(cc(e.path??"."),".claude","skills"),n=new Set,i=[];for(let d of[s,t])if(lc(d))for(let f of uc(d))f.endsWith(".skill")&&!n.has(f)&&(n.add(f),i.push({file:f,dir:d}));if(i.length===0){u("No skills installed. Run: codebase setup");return}let o=[];for(let{file:d,dir:f}of i){let m=Ht(f,d),h=d.replace(/\.skill$/,""),v="";try{let x=await pc(m),j=fc(x);j.name&&(h=j.name),j.description&&(v=j.description)}catch{}o.push({name:h,description:v,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,f)=>d.padEnd(f),p=` ${"\u2500".repeat(r)} ${"\u2500".repeat(a)} ${"\u2500".repeat(c)}`;k(`
|
|
705
|
+
${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("")}var re=zt(process.argv.slice(2));Q(re.quiet);Ut(re.verbose);re.helpCommand&&re.command&&Vt(re.command);var mc={scan:Oe,init:dn,brief:pn,next:fn,setup:It,query:mn,issue:wn,status:xn,mcp:Pn,doctor:In,fix:Fn,release:Mn,plan:Gn,skills:Un,"scan-only":Oe};Zt().catch(()=>{});var Bn=mc[re.command];Bn||(console.error(`
|
|
706
|
+
Unknown command: ${re.command}
|
|
707
|
+
`),console.log(` Run ${bt("codebase --help")} to see all commands.
|
|
708
|
+
`),process.exit(1));Bn(re).catch(e=>{console.error(`
|
|
709
|
+
${gc("\u2717")} Error: ${e.message}
|
|
710
|
+
`);let t=e.message.toLowerCase();t.includes("not a git repository")?console.log(` ${We("\u2192")} Initialize git first: ${bt("git init")}
|
|
711
|
+
`):t.includes("permission denied")?console.log(` ${We("\u2192")} Check file permissions or run with appropriate access
|
|
712
|
+
`):t.includes("no such file")?console.log(` ${We("\u2192")} Check that the path is correct
|
|
713
|
+
`):t.includes("github")&&(console.log(` ${We("\u2192")} Ensure GitHub CLI is installed: ${bt("gh --version")}
|
|
714
|
+
`),console.log(` ${We("\u2192")} Authenticate: ${bt("gh auth login")}
|
|
715
|
+
`)),process.exit(1)});function gc(e){return`\x1B[31m${e}\x1B[0m`}function We(e){return`\x1B[36m${e}\x1B[0m`}function bt(e){return`\x1B[1m${e}\x1B[0m`}
|