prjct-cli 2.14.3 → 2.15.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/CHANGELOG.md +28 -0
- package/bin/prjct +15 -0
- package/dist/bin/prjct-core.mjs +418 -374
- package/dist/bin/prjct.mjs +1 -1
- package/dist/daemon/entry.mjs +301 -257
- package/dist/mcp/server.mjs +113 -65
- package/dist/templates.json +1 -1
- package/package.json +1 -1
- package/templates/sdd-canonical-sequence.md +85 -0
- package/templates/skills/prjct/SKILL.md +416 -0
- package/templates/spec-reviewer-rubrics/architecture.md +47 -0
- package/templates/spec-reviewer-rubrics/design.md +38 -0
- package/templates/spec-reviewer-rubrics/strategic.md +32 -0
- package/templates/spec-template.md +94 -0
- /package/templates/{planning-methodology.md → planning-methodology-deep.md} +0 -0
package/dist/mcp/server.mjs
CHANGED
|
@@ -5,13 +5,13 @@ import { dirname as __pathDirname } from 'path';
|
|
|
5
5
|
var require = __createRequire(import.meta.url);
|
|
6
6
|
var __filename = __fileURLToPath(import.meta.url);
|
|
7
7
|
var __dirname = __pathDirname(__filename);
|
|
8
|
-
var
|
|
9
|
-
`;await
|
|
10
|
-
`)[0];if(n?.startsWith("worktree "))return n.replace("worktree ","").trim()}catch{}let{stdout:e}=await
|
|
8
|
+
var gt=Object.defineProperty;var Jr=Object.getOwnPropertyDescriptor;var Yr=Object.getOwnPropertyNames;var zr=Object.prototype.hasOwnProperty;var c=(r,t)=>gt(r,"name",{value:t,configurable:!0}),De=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(t,e)=>(typeof require<"u"?require:t)[e]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var L=(r,t)=>()=>(r&&(t=r(r=0)),t);var Le=(r,t)=>{for(var e in t)gt(r,e,{get:t[e],enumerable:!0})},Kr=(r,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of Yr(t))!zr.call(r,n)&&n!==e&>(r,n,{get:()=>t[n],enumerable:!(s=Jr(t,n))||s.enumerable});return r};var It=r=>Kr(gt({},"__esModule",{value:!0}),r);var je,Oe,Me,Dt=L(()=>{"use strict";je=new Set(["node_modules",".git","dist","build","out",".next",".nuxt","coverage",".cache",".turbo",".vercel",".parcel-cache","__pycache__",".pytest_cache","target","vendor",".venv","venv","eggs","*.egg-info",".prjct",".worktrees"]),Oe=["",".ts",".tsx",".js",".jsx","/index.ts","/index.js"],Me=/(?:import|from)\s+['"]([^'"]+)['"]/g});function Qr(r){return r instanceof Error&&"code"in r}function N(r){return Qr(r)&&r.code==="ENOENT"}function $e(r){return r instanceof Error?r.message:typeof r=="string"?r:"Unknown error"}var J=L(()=>{"use strict";c(Qr,"isNodeError");c(N,"isNotFoundError");c($e,"getErrorMessage")});import Be from"node:fs/promises";async function He(r,t){let e;try{e=await Be.readFile(r,"utf-8")}catch(i){if(N(i))return null;throw i}let s;try{s=JSON.parse(e)}catch{return await Xe(r,e),We(r,"Malformed JSON"),null}let n=t.safeParse(s);return n.success?s:(await Xe(r,e),We(r,Zr(n.error)),null)}async function Xe(r,t){let e=`${r}.backup`;try{await Be.writeFile(e,t,"utf-8")}catch{}}function We(r,t){console.error(`[prjct] Warning: Corrupted storage file: ${r}`),console.error(`[prjct] Reason: ${t}`),console.error("[prjct] A .backup file has been created. Returning defaults.")}function Zr(r){return r.issues.slice(0,3).map(t=>`${t.path.join(".")}: ${t.message}`).join("; ")}var qe=L(()=>{"use strict";J();c(He,"safeRead");c(Xe,"createBackup");c(We,"logCorruption");c(Zr,"formatZodError")});import Y from"node:fs/promises";import Lt from"node:path";async function Ge(r,t={}){let e=[],s=t.maxFiles??1/0,n=t.dotfileAllowlist?new Set(t.dotfileAllowlist):null;async function i(o){if(e.length>=s)return;let a=await Y.readdir(o,{withFileTypes:!0}).catch(()=>[]);for(let u of a){if(e.length>=s)break;let p=String(u.name);if(je.has(p)||t.skipDotfiles&&p.startsWith(".")&&(!n||!n.has(p)))continue;let m=Lt.join(o,p);u.isDirectory()?await i(m):u.isFile()&&e.push(Lt.relative(r,m))}}return c(i,"walk"),await i(r),e}async function Je(r,t,e){let s=[];for(let n=0;n<r.length;n+=t){let i=await Promise.all(r.slice(n,n+t).map(e));for(let o of i)o!==null&&s.push(o)}return s}async function ft(r,t=null,e){if(e)return await He(r,e)??t;try{let s=await Y.readFile(r,"utf-8");return JSON.parse(s)}catch(s){if(N(s))return t;throw s}}async function $(r,t,e=2){let s=Lt.dirname(r);await Y.mkdir(s,{recursive:!0});let n=`${JSON.stringify(t,null,e)}
|
|
9
|
+
`;await Y.writeFile(r,n,"utf-8")}async function P(r){try{return await Y.access(r),!0}catch(t){if(N(t))return!1;throw t}}async function jt(r){try{return(await Y.stat(r)).isDirectory()}catch(t){if(N(t))return!1;throw t}}async function H(r){await Y.mkdir(r,{recursive:!0})}var X=L(()=>{"use strict";Dt();qe();J();c(Ge,"walkDir");c(Je,"batchProcess");c(ft,"readJson");c($,"writeJson");c(P,"fileExists");c(jt,"dirExists");c(H,"ensureDir")});import{exec as en,execFile as sn}from"node:child_process";import{promisify as Ke}from"node:util";var w,no,V=L(()=>{"use strict";w=Ke(en),no=Ke(sn)});var Xt={};Le(Xt,{default:()=>rn,worktreeService:()=>Qe});import Ut from"node:fs/promises";import j from"node:path";var Ve,$t,Qe,rn,Wt=L(()=>{"use strict";V();X();Ve=".worktrees",$t=class{static{c(this,"WorktreeService")}async create(t,e,s={}){let n=await this.getMainWorktree(t),i=j.join(n,Ve,e),o=s.branch||`feat/${e}`;await Ut.mkdir(j.join(n,Ve),{recursive:!0});let a=s.baseBranch?` ${s.baseBranch}`:"";await w(`git worktree add "${i}" -b "${o}"${a}`,{cwd:n});let{stdout:u}=await w("git rev-parse HEAD",{cwd:i});return{path:i,branch:o,commit:u.trim(),isMain:!1,slug:e}}async remove(t,e=!1){let s=await this.getMainWorktree(t),n;if(e)try{let{stdout:i}=await w("git rev-parse --abbrev-ref HEAD",{cwd:t});n=i.trim()}catch{}if(await w(`git worktree remove "${t}" --force`,{cwd:s}),e&&n&&n!=="main"&&n!=="master")try{await w(`git branch -D "${n}"`,{cwd:s})}catch{}}async list(t){let e=await this.getMainWorktree(t),{stdout:s}=await w("git worktree list --porcelain",{cwd:e});return this.parsePorcelainOutput(s,e)}async detect(t){try{let{stdout:e}=await w("git rev-parse --git-common-dir",{cwd:t}),{stdout:s}=await w("git rev-parse --git-dir",{cwd:t}),n=j.resolve(t,e.trim()),i=j.resolve(t,s.trim());if(n!==i){let{stdout:o}=await w("git rev-parse --abbrev-ref HEAD",{cwd:t}),{stdout:a}=await w("git rev-parse HEAD",{cwd:t}),{stdout:u}=await w("git rev-parse --show-toplevel",{cwd:t}),p=u.trim(),m=j.basename(p);return{path:p,branch:o.trim(),commit:a.trim(),isMain:!1,slug:m}}return null}catch{return null}}async getMainWorktree(t){try{let{stdout:s}=await w("git worktree list --porcelain",{cwd:t}),n=s.split(`
|
|
10
|
+
`)[0];if(n?.startsWith("worktree "))return n.replace("worktree ","").trim()}catch{}let{stdout:e}=await w("git rev-parse --show-toplevel",{cwd:t});return e.trim()}async setup(t,e){let s=j.join(e,".env");await P(s)&&await Ut.copyFile(s,j.join(t,".env"));let n=j.join(e,".prjct"),i=j.join(t,".prjct");await P(n)&&!await P(i)&&await Ut.symlink(n,i,"dir")}async teardown(t){}async clean(t){let e=await this.list(t),s=[],n=await this.getMainWorktree(t);await w("git worktree prune",{cwd:n});for(let i of e)i.isMain||await P(i.path)||s.push(i.slug);return s}parsePorcelainOutput(t,e){let s=[],n=t.trim().split(`
|
|
11
11
|
|
|
12
|
-
`);for(let
|
|
13
|
-
`),a="",u="",p="",m=!1;for(let d of
|
|
14
|
-
`).map(
|
|
12
|
+
`);for(let i of n){if(!i.trim())continue;let o=i.trim().split(`
|
|
13
|
+
`),a="",u="",p="",m=!1;for(let d of o)d.startsWith("worktree ")?a=d.replace("worktree ","").trim():d.startsWith("HEAD ")?u=d.replace("HEAD ","").trim():d.startsWith("branch ")?p=d.replace("branch refs/heads/","").trim():d==="bare"?m=!0:d==="detached"&&(p="(detached)");if(a){let d=a===e||m;s.push({path:a,branch:p,commit:u,isMain:d,slug:d?"main":j.basename(a)})}}return s}},Qe=new $t,rn=Qe});var ss=L(()=>{"use strict"});import{z as ot}from"zod";function rs(r,t){let e=r.split(".").map(Number),s=t.split(".").map(Number);for(let n=0;n<3;n++){let i=e[n]??0,o=s[n]??0;if(i<o)return-1;if(i>o)return 1}return 0}var Ht,qt=L(()=>{"use strict";Ht=ot.object({provider:ot.string(),model:ot.string(),cliVersion:ot.string().optional(),recordedAt:ot.string()});c(rs,"compareSemver")});function ns(r,t){let e=typeof r=="string"?new Date(r).getTime():r;return Date.now()-e>t}var ht,Gt=L(()=>{"use strict";c(ns,"isExpired");ht=class{static{c(this,"TTLCache")}cache=new Map;ttl;maxSize;constructor(t={}){this.ttl=t.ttl??5e3,this.maxSize=t.maxSize??50}isValid(t){let e=this.cache.get(t);return e?Date.now()-e.timestamp<this.ttl:!1}get(t){let e=this.cache.get(t);return e?this.isValid(t)?e.data:(this.cache.delete(t),null):null}set(t,e){this.cache.set(t,{data:e,timestamp:Date.now()}),this.evictOldEntries()}delete(t){this.cache.delete(t)}clear(){this.cache.clear()}has(t){return this.cache.has(t)}get size(){return this.cache.size}evictOldEntries(){if(this.cache.size<=this.maxSize)return;let e=Array.from(this.cache.entries()).sort((s,n)=>s[1].timestamp-n[1].timestamp).slice(0,this.cache.size-this.maxSize);for(let[s]of e)this.cache.delete(s)}stats(){return{size:this.cache.size,maxSize:this.maxSize,ttl:this.ttl}}prune(){let t=0;for(let e of this.cache.keys())this.isValid(e)||(this.cache.delete(e),t++);return t}}});import an from"node:fs/promises";import cn from"node:os";import is from"node:path";async function as(){try{let r=await an.readFile(os,"utf-8"),t=JSON.parse(r);return!t.timestamp||!t.detection||!t.detection.claude||!t.detection.gemini||!t.detection.codex||ns(t.timestamp,ln)?null:t.detection}catch{return null}}async function cs(r){let t={timestamp:new Date().toISOString(),detection:r};await $(os,t)}var un,os,ln,us=L(()=>{"use strict";Gt();X();un=is.join(cn.homedir(),".prjct-cli","cache"),os=is.join(un,"providers.json"),ln=10*60*1e3;c(as,"readProviderCache");c(cs,"writeProviderCache")});var Tt={};Le(Tt,{ClaudeProvider:()=>yt,CursorProvider:()=>ds,GeminiProvider:()=>Yt,Providers:()=>at,detectAllProviders:()=>zt,detectAntigravity:()=>fn,detectCodex:()=>hs,detectProvider:()=>Jt,getActiveProvider:()=>mn,getProviderBranding:()=>gn,selectProvider:()=>hn,validateCliVersion:()=>fs});import q from"node:os";import M from"node:path";async function gs(r){try{let{stdout:t}=await w(`which ${r}`,{timeout:2e3});return t.trim()}catch{return null}}async function dn(r){try{let{stdout:t}=await w(`${r} --version`,{timeout:2e3}),e=t.match(/\d+\.\d+\.\d+/);return e?e[0]:t.trim()}catch{return null}}async function Jt(r){let t=at[r];if(!t.cliCommand)return{installed:!1};let e=await gs(t.cliCommand);if(!e)return{installed:!1};let s=await dn(t.cliCommand),n=fs(r,s||void 0);return{installed:!0,version:s||void 0,path:e,versionWarning:n||void 0}}function fs(r,t){let e=at[r];return!e.minCliVersion||!t?null:rs(t,e.minCliVersion)<0?`\u26A0\uFE0F ${e.displayName} v${t} is below minimum v${e.minCliVersion}. Some features may not work correctly.`:null}async function zt(r=!1){if(!r){let o=await as();if(o)return o}let[t,e,s]=await Promise.all([Jt("claude"),Jt("gemini"),hs()]),n={installed:s.installed},i={claude:t,gemini:e,codex:n};return await cs(i).catch(()=>{}),i}async function mn(r){if(r&&at[r])return at[r];let t=await zt();return t.claude.installed&&!t.gemini.installed?yt:t.gemini.installed&&!t.claude.installed?Yt:yt}function gn(r){return{commitFooter:"Generated with [p/](https://www.prjct.app/)",signature:{claude:"\u26A1 prjct + Claude",gemini:"\u26A1 prjct + Gemini",cursor:"\u26A1 prjct + Cursor",antigravity:"\u26A1 prjct + Antigravity",windsurf:"\u26A1 prjct + Windsurf",codex:"\u26A1 prjct + Codex"}[r]||"\u26A1 prjct"}}async function fn(){let r=ps.configDir;if(!r)return{installed:!1,skillInstalled:!1};let t=M.join(r,"skills","prjct","SKILL.md"),[e,s]=await Promise.all([P(r),P(t)]);return{installed:e,skillInstalled:s,configPath:e?r:void 0}}async function hs(){let r=ms.configDir;if(!r)return{installed:!1,skillInstalled:!1};let t=await gs("codex"),e=M.join(r,"skills","prjct","SKILL.md"),s=await P(e),n=!!t;return{installed:n,skillInstalled:s,configPath:n?r:void 0}}async function hn(){let r=await zt(),t=r.claude.installed,e=r.gemini.installed;return!t&&!e?{provider:"claude",userSelected:!1,detection:r}:t&&!e?{provider:"claude",userSelected:!1,detection:r}:e&&!t?{provider:"gemini",userSelected:!1,detection:r}:{provider:"claude",userSelected:!0,detection:r}}var yt,Yt,ps,ds,pn,ms,at,kt=L(()=>{"use strict";ss();qt();V();X();us();yt={name:"claude",displayName:"Claude Code",cliCommand:"claude",configDir:M.join(q.homedir(),".claude"),contextFile:"CLAUDE.md",skillsDir:M.join(q.homedir(),".claude","skills"),commandsDir:".claude/commands",commandFormat:"md",settingsFile:"settings.json",projectSettingsFile:"settings.local.json",ignoreFile:".claudeignore",websiteUrl:"https://www.anthropic.com/claude",docsUrl:"https://docs.anthropic.com/claude-code",defaultModel:"sonnet",supportedModels:["opus","sonnet","haiku"],minCliVersion:"1.0.0",capabilityTier:"full"},Yt={name:"gemini",displayName:"Gemini CLI",cliCommand:"gemini",configDir:M.join(q.homedir(),".gemini"),contextFile:"GEMINI.md",skillsDir:M.join(q.homedir(),".gemini","skills"),commandsDir:".gemini/commands",commandFormat:"toml",settingsFile:"settings.json",projectSettingsFile:"settings.json",ignoreFile:".geminiignore",websiteUrl:"https://geminicli.com",docsUrl:"https://geminicli.com/docs",defaultModel:"2.5-flash",supportedModels:["2.5-pro","2.5-flash","2.0-flash"],minCliVersion:"1.0.0",capabilityTier:"standard"},ps={name:"antigravity",displayName:"Google Antigravity",cliCommand:null,configDir:M.join(q.homedir(),".gemini","antigravity"),contextFile:"ANTIGRAVITY.md",skillsDir:M.join(q.homedir(),".gemini","antigravity","global_skills"),commandsDir:".agent/skills",commandFormat:"md",settingsFile:"mcp_config.json",projectSettingsFile:null,ignoreFile:".agentignore",websiteUrl:"https://gemini.google.com/app/antigravity",docsUrl:"https://gemini.google.com/app/antigravity",defaultModel:null,supportedModels:[],minCliVersion:null,capabilityTier:"basic"},ds={name:"cursor",displayName:"Cursor IDE",cliCommand:null,configDir:null,contextFile:"prjct.mdc",skillsDir:null,commandsDir:".cursor/commands",rulesDir:".cursor/rules",commandFormat:"md",settingsFile:null,projectSettingsFile:null,ignoreFile:".cursorignore",isProjectLevel:!0,websiteUrl:"https://cursor.com",docsUrl:"https://cursor.com/docs",defaultModel:null,supportedModels:[],minCliVersion:null,capabilityTier:"basic"},pn={name:"windsurf",displayName:"Windsurf IDE",cliCommand:null,configDir:null,contextFile:"prjct.md",skillsDir:null,commandsDir:".windsurf/workflows",rulesDir:".windsurf/rules",commandFormat:"md",settingsFile:null,projectSettingsFile:null,ignoreFile:".windsurfignore",isProjectLevel:!0,websiteUrl:"https://windsurf.com",docsUrl:"https://docs.windsurf.com",defaultModel:null,supportedModels:[],minCliVersion:null,capabilityTier:"basic"},ms={name:"codex",displayName:"OpenAI Codex",cliCommand:"codex",configDir:M.join(q.homedir(),".codex"),contextFile:"AGENTS.md",skillsDir:M.join(q.homedir(),".codex","skills"),commandsDir:".agents/skills",commandFormat:"md",settingsFile:null,projectSettingsFile:null,ignoreFile:".codexignore",websiteUrl:"https://openai.com/codex",docsUrl:"https://github.com/openai/codex",defaultModel:null,supportedModels:[],minCliVersion:null,capabilityTier:"basic"},at={claude:yt,gemini:Yt,cursor:ds,antigravity:ps,windsurf:pn,codex:ms};c(gs,"whichCommand");c(dn,"getCliVersion");c(Jt,"detectProvider");c(fs,"validateCliVersion");c(zt,"detectAllProviders");c(mn,"getActiveProvider");c(gn,"getProviderBranding");c(fn,"detectAntigravity");c(hs,"detectCodex");c(hn,"selectProvider")});import{StdioServerTransport as Ni}from"@modelcontextprotocol/sdk/server/stdio.js";import{McpServer as Ai}from"@modelcontextprotocol/sdk/server/mcp.js";import{z as C}from"zod";Dt();import ws from"node:fs/promises";import Q from"node:path";import Qt from"node:fs";import Ss from"node:path";import yn from"node:crypto";import Et from"node:fs/promises";import Kt from"node:os";import S from"node:path";import{formatDistanceToNowStrict as Mi}from"date-fns";function Fe(r){return{year:r.getFullYear().toString(),month:(r.getMonth()+1).toString().padStart(2,"0"),day:r.getDate().toString().padStart(2,"0")}}c(Fe,"getYearMonthDay");function g(){return new Date().toISOString()}c(g,"getTimestamp");function Ue(r){let t=new Date;return t.setDate(t.getDate()-r),t}c(Ue,"getDaysAgo");X();X();import K from"node:fs/promises";import A from"node:path";import{globSync as tn}from"glob";async function Mt(r){let t={isMonorepo:!1,type:null,rootPath:r,packages:[]},e=[{file:"pnpm-workspace.yaml",type:"pnpm"},{file:"lerna.json",type:"lerna"},{file:"nx.json",type:"nx"},{file:"rush.json",type:"rush"},{file:"turbo.json",type:"turborepo"}];for(let s of e)if(await P(A.join(r,s.file))){t.isMonorepo=!0,t.type=s.type;break}if(!t.isMonorepo){let s=A.join(r,"package.json");if(await P(s))try{JSON.parse(await K.readFile(s,"utf-8")).workspaces&&(t.isMonorepo=!0,t.type="npm")}catch{}}return t.isMonorepo&&(t.packages=await Ft(r,t.type)),t}c(Mt,"detectMonorepo");async function Ft(r,t){let e=[],s=[];try{if(t==="pnpm"){let i=(await K.readFile(A.join(r,"pnpm-workspace.yaml"),"utf-8")).match(/packages:\s*\n((?:\s*-\s*.+\n?)+)/);i&&(s=i[1].split(`
|
|
14
|
+
`).map(o=>o.replace(/^\s*-\s*['"]?|['"]?\s*$/g,"")).filter(Boolean))}else if(t==="npm"||t==="lerna"){let n=A.join(r,"package.json"),i=JSON.parse(await K.readFile(n,"utf-8"));if(Array.isArray(i.workspaces)?s=i.workspaces:i.workspaces?.packages&&(s=i.workspaces.packages),t==="lerna"){let o=A.join(r,"lerna.json");if(await P(o)){let a=JSON.parse(await K.readFile(o,"utf-8"));a.packages&&(s=a.packages)}}}else if(t==="nx")s=["apps/*","libs/*","packages/*"];else if(t==="turborepo"){let n=A.join(r,"package.json"),i=JSON.parse(await K.readFile(n,"utf-8"));Array.isArray(i.workspaces)&&(s=i.workspaces)}s.length===0&&(s=["packages/*","apps/*","libs/*"]);for(let n of s){if(n.startsWith("!"))continue;let i=tn(n,{cwd:r,absolute:!1});for(let o of i){let a=A.join(r,o),u=A.join(a,"package.json");if(await P(u))try{let p=JSON.parse(await K.readFile(u,"utf-8")),m=A.join(a,"PRJCT.md");e.push({name:p.name||A.basename(o),path:a,relativePath:o,hasPrjctMd:await P(m)})}catch{}}}}catch{}return e}c(Ft,"discoverMonorepoPackages");async function Ye(r,t){if(!t.isMonorepo)return null;let e=A.resolve(r);for(let s of t.packages){let n=A.resolve(s.path);if(e.startsWith(n))return s}return null}c(Ye,"findContainingPackage");async function ze(r){let t=A.resolve(r),e=A.parse(t).root;for(;t!==e;){if((await Mt(t)).isMonorepo)return t;t=A.dirname(t)}return null}c(ze,"findMonorepoRoot");import Bt from"node:os";import O from"node:path";async function Ze(r,t){if(t&&t.trim().length>0)return on(r,t);let e=await nn(r),n=O.basename(O.resolve(e)).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"project";return O.join(Bt.homedir(),"Documents","prjct",n)}c(Ze,"getWikiPath");function ts(r,t){let s=O.basename(O.resolve(r)).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"project",n=t.replace(/-/g,"").slice(0,8);return O.join(Bt.homedir(),"Documents","prjct",`${s}-${n}`)}c(ts,"getWikiPathWithProjectHash");function es(r){return O.join(r,".prjct","wiki")}c(es,"getLegacyWikiPath");async function nn(r){try{let{worktreeService:t}=await Promise.resolve().then(()=>(Wt(),Xt));return await t.detect(r)&&await t.getMainWorktree(r)||r}catch{return r}}c(nn,"resolveProjectRootPath");function on(r,t){let e=t.trim();return(e.startsWith("~/")||e==="~")&&(e=O.join(Bt.homedir(),e.slice(1))),O.isAbsolute(e)||(e=O.resolve(r,e)),e}c(on,"resolveVaultOverride");var Vt=class{static{c(this,"PathManager")}globalBaseDir;globalProjectsDir;globalConfigDir;constructor(){let t=process.env.PRJCT_CLI_HOME?.trim();this.globalBaseDir=t?S.resolve(t):S.join(Kt.homedir(),".prjct-cli"),this.globalProjectsDir=S.join(this.globalBaseDir,"projects"),this.globalConfigDir=S.join(this.globalBaseDir,"config")}setGlobalBaseDir(t){this.globalBaseDir=S.resolve(t),this.globalProjectsDir=S.join(this.globalBaseDir,"projects"),this.globalConfigDir=S.join(this.globalBaseDir,"config")}generateProjectId(t){return yn.randomUUID()}getGlobalBasePath(){return this.globalBaseDir}getGlobalProjectPath(t){return S.join(this.globalProjectsDir,t)}getLocalConfigPath(t){return S.join(t,".prjct","prjct.config.json")}getGlobalProjectConfigPath(t){return S.join(this.getGlobalProjectPath(t),"project.json")}getLegacyPrjctPath(t){return S.join(t,".prjct")}async hasLegacyStructure(t){return await jt(this.getLegacyPrjctPath(t))}async hasConfig(t){return await P(this.getLocalConfigPath(t))}async ensureGlobalStructure(){await H(this.globalBaseDir),await H(this.globalProjectsDir),await H(this.globalConfigDir)}async ensureProjectStructure(t){await this.ensureGlobalStructure();let e=this.getGlobalProjectPath(t),s=["core","progress","planning","analysis","memory"];for(let n of s)await H(S.join(e,n));return await H(S.join(e,"planning","tasks")),await H(S.join(e,"sessions")),e}getSessionPath(t,e=new Date){let{year:s,month:n,day:i}=Fe(e);return S.join(this.getGlobalProjectPath(t),"sessions",s,n,i)}getCurrentSessionPath(t){return this.getSessionPath(t,new Date)}async ensureSessionPath(t,e=new Date){let s=this.getSessionPath(t,e);return await H(s),s}async listSessions(t,e=null,s=null){let n=S.join(this.getGlobalProjectPath(t),"sessions"),i=[];try{let o=await Et.readdir(n,{withFileTypes:!0});for(let a of o){if(!a.isDirectory()||e&&a.name!==e.toString())continue;let u=S.join(n,a.name),p=await Et.readdir(u,{withFileTypes:!0});for(let m of p){if(!m.isDirectory()||s&&m.name!==s.toString().padStart(2,"0"))continue;let d=S.join(u,m.name),h=await Et.readdir(d,{withFileTypes:!0});for(let y of h)y.isDirectory()&&i.push({year:a.name,month:m.name,day:y.name,path:S.join(d,y.name),date:new Date(`${a.name}-${m.name}-${y.name}`)})}}return i.sort((a,u)=>u.date.getTime()-a.date.getTime()),i}catch{return[]}}async getSessionsInRange(t,e,s=new Date){return(await this.listSessions(t)).filter(i=>i.date>=e&&i.date<=s)}getFilePath(t,e,s){return S.join(this.getGlobalProjectPath(t),e,s)}async listProjects(){try{return await this.ensureGlobalStructure(),(await Et.readdir(this.globalProjectsDir,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return[]}}async projectExists(t){return await jt(this.getGlobalProjectPath(t))}getDisplayPath(t){let e=Kt.homedir();return t.startsWith(e)?t.replace(e,"~"):t}getAuthConfigPath(){return S.join(this.globalConfigDir,"auth.json")}getSyncPendingPath(t){return S.join(this.getGlobalProjectPath(t),"sync","pending.json")}getLastSyncPath(t){return S.join(this.getGlobalProjectPath(t),"sync","last-sync.json")}getRunningStatusPath(){return S.join(this.globalBaseDir,".running")}getDocsPath(){return S.join(this.globalBaseDir,"docs")}async getAgentDir(){return(await(kt(),It(Tt)).getActiveProvider()).configDir}async getAgentSettingsPath(){let t=await(kt(),It(Tt)).getActiveProvider();return(kt(),It(Tt)).getGlobalSettingsPath(t.name)}getClaudeDir(){return S.join(Kt.homedir(),".claude")}getClaudeSettingsPath(){return S.join(this.getClaudeDir(),"settings.json")}getStoragePath(t,e){return S.join(this.getGlobalProjectPath(t),"storage",e)}getContextPath(t){return S.join(this.getGlobalProjectPath(t),"context")}async getWikiPath(t,e){return Ze(t,e)}getWikiPathWithProjectHash(t,e){return ts(t,e)}getLegacyWikiPath(t){return es(t)}async detectMonorepo(t){return Mt(t)}async discoverMonorepoPackages(t,e){return Ft(t,e)}async findContainingPackage(t,e){return Ye(t,e)}async findMonorepoRoot(t){return ze(t)}},Tn=new Vt,_=Tn;var ys=`
|
|
15
15
|
-- =======================================================================
|
|
16
16
|
-- Document storage (backward-compatible with JSON file pattern)
|
|
17
17
|
-- =======================================================================
|
|
@@ -225,7 +225,7 @@ CREATE TABLE velocity_sprints (
|
|
|
225
225
|
started_at TEXT,
|
|
226
226
|
ended_at TEXT
|
|
227
227
|
);
|
|
228
|
-
`;var
|
|
228
|
+
`;var Ts=[{version:1,name:"initial-schema",up:c(r=>{r.run(ys)},"up")},{version:2,name:"archives-table",up:c(r=>{r.run(`
|
|
229
229
|
-- =======================================================================
|
|
230
230
|
-- Archives: Stale data moved out of active storage (PRJ-267)
|
|
231
231
|
-- =======================================================================
|
|
@@ -242,7 +242,7 @@ CREATE TABLE velocity_sprints (
|
|
|
242
242
|
CREATE INDEX idx_archives_entity_type ON archives(entity_type);
|
|
243
243
|
CREATE INDEX idx_archives_archived_at ON archives(archived_at);
|
|
244
244
|
CREATE INDEX idx_archives_entity_id ON archives(entity_id);
|
|
245
|
-
`)},"up")},{version:3,name:"workflow-rules-table",up:c(
|
|
245
|
+
`)},"up")},{version:3,name:"workflow-rules-table",up:c(r=>{r.run(`
|
|
246
246
|
-- =======================================================================
|
|
247
247
|
-- Workflow Rules: hooks, gates, and custom steps (Phase 2)
|
|
248
248
|
-- =======================================================================
|
|
@@ -260,7 +260,7 @@ CREATE TABLE velocity_sprints (
|
|
|
260
260
|
);
|
|
261
261
|
|
|
262
262
|
CREATE INDEX idx_workflow_rules_command ON workflow_rules(command);
|
|
263
|
-
`)},"up")},{version:4,name:"custom-workflows-table",up:c(
|
|
263
|
+
`)},"up")},{version:4,name:"custom-workflows-table",up:c(r=>{r.run(`
|
|
264
264
|
-- =======================================================================
|
|
265
265
|
-- Custom Workflows: User-defined workflows with agentic auto-config
|
|
266
266
|
-- =======================================================================
|
|
@@ -285,7 +285,7 @@ CREATE TABLE velocity_sprints (
|
|
|
285
285
|
('done', 'Complete current task/subtask', 1, 1, datetime('now'), datetime('now')),
|
|
286
286
|
('ship', 'Ship feature with version bump and PR', 1, 1, datetime('now'), datetime('now')),
|
|
287
287
|
('sync', 'Analyze project and regenerate context', 1, 1, datetime('now'), datetime('now'));
|
|
288
|
-
`)},"up")},{version:5,name:"llm-analysis-table",up:c(
|
|
288
|
+
`)},"up")},{version:5,name:"llm-analysis-table",up:c(r=>{r.run(`
|
|
289
289
|
-- =======================================================================
|
|
290
290
|
-- LLM Analysis: Structured findings from hybrid sync pipeline
|
|
291
291
|
-- Pipeline: CLI (collect) \u2192 LLM (analyze) \u2192 CLI (store)
|
|
@@ -301,7 +301,7 @@ CREATE TABLE velocity_sprints (
|
|
|
301
301
|
|
|
302
302
|
CREATE INDEX idx_llm_analysis_status ON llm_analysis(status);
|
|
303
303
|
CREATE INDEX idx_llm_analysis_commit ON llm_analysis(commit_hash);
|
|
304
|
-
`)},"up")},{version:6,name:"context-feedback-table",up:c(
|
|
304
|
+
`)},"up")},{version:6,name:"context-feedback-table",up:c(r=>{r.run(`
|
|
305
305
|
-- =======================================================================
|
|
306
306
|
-- Context Feedback: RL loop for file suggestion improvement
|
|
307
307
|
-- Records suggested vs actual files per task for scoring boosts
|
|
@@ -319,7 +319,7 @@ CREATE TABLE velocity_sprints (
|
|
|
319
319
|
);
|
|
320
320
|
|
|
321
321
|
CREATE INDEX idx_cf_task ON context_feedback(task_id);
|
|
322
|
-
`)},"up")},{version:7,name:"sessions-table",up:c(
|
|
322
|
+
`)},"up")},{version:7,name:"sessions-table",up:c(r=>{r.run(`
|
|
323
323
|
-- =======================================================================
|
|
324
324
|
-- Sessions: Task lifecycle tracking (replaces current.json + archive/)
|
|
325
325
|
-- =======================================================================
|
|
@@ -339,13 +339,13 @@ CREATE TABLE velocity_sprints (
|
|
|
339
339
|
CREATE INDEX idx_sessions_project ON sessions(project_id);
|
|
340
340
|
CREATE INDEX idx_sessions_status ON sessions(status);
|
|
341
341
|
CREATE INDEX idx_sessions_completed ON sessions(completed_at);
|
|
342
|
-
`)},"up")},{version:8,name:"task-token-tracking",up:c(
|
|
342
|
+
`)},"up")},{version:8,name:"task-token-tracking",up:c(r=>{r.run(`
|
|
343
343
|
-- =======================================================================
|
|
344
344
|
-- Token usage tracking per task (input + output)
|
|
345
345
|
-- =======================================================================
|
|
346
346
|
ALTER TABLE tasks ADD COLUMN tokens_in INTEGER DEFAULT 0;
|
|
347
347
|
ALTER TABLE tasks ADD COLUMN tokens_out INTEGER DEFAULT 0;
|
|
348
|
-
`)},"up")},{version:9,name:"context-health-tables",up:c(
|
|
348
|
+
`)},"up")},{version:9,name:"context-health-tables",up:c(r=>{r.run(`
|
|
349
349
|
-- =======================================================================
|
|
350
350
|
-- Context Zone Events: Track zone transitions for health analytics
|
|
351
351
|
-- =======================================================================
|
|
@@ -375,7 +375,7 @@ CREATE TABLE velocity_sprints (
|
|
|
375
375
|
);
|
|
376
376
|
|
|
377
377
|
CREATE INDEX idx_cc_project ON context_compactions(project_id);
|
|
378
|
-
`)},"up")},{version:10,name:"fts5-memories",up:c(
|
|
378
|
+
`)},"up")},{version:10,name:"fts5-memories",up:c(r=>{r.run(`
|
|
379
379
|
-- =======================================================================
|
|
380
380
|
-- Memories: Tagged, searchable memory store (replaces memories.json)
|
|
381
381
|
-- =======================================================================
|
|
@@ -424,11 +424,11 @@ CREATE TABLE velocity_sprints (
|
|
|
424
424
|
INSERT INTO memories_fts(rowid, title, content, tags)
|
|
425
425
|
VALUES (NEW.rowid, NEW.title, NEW.content, NEW.tags);
|
|
426
426
|
END;
|
|
427
|
-
`);try{let t=
|
|
427
|
+
`);try{let t=r.prepare("SELECT data FROM kv_store WHERE key = 'memory:memories'").get();if(t){let e=JSON.parse(t.data);if(e.memories&&e.memories.length>0){let s=r.prepare(`
|
|
428
428
|
INSERT OR IGNORE INTO memories
|
|
429
429
|
(id, project_id, title, content, tags, content_hash, user_triggered, confidence, observation_count, created_at, updated_at)
|
|
430
430
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
431
|
-
`);for(let n of e.memories)
|
|
431
|
+
`);for(let n of e.memories)s.run(n.id,"_migrated",n.title,n.content,(n.tags||[]).join(","),null,n.userTriggered?1:0,n.confidence??null,n.observationCount??0,n.createdAt,n.updatedAt)}}}catch{}},"up")},{version:11,name:"agent-sessions",up:c(r=>{r.run(`
|
|
432
432
|
-- =======================================================================
|
|
433
433
|
-- Agent Sessions: Track AI agent work sessions across compactions
|
|
434
434
|
-- =======================================================================
|
|
@@ -461,7 +461,7 @@ CREATE TABLE velocity_sprints (
|
|
|
461
461
|
|
|
462
462
|
CREATE INDEX IF NOT EXISTS idx_user_prompts_project ON user_prompts(project_id);
|
|
463
463
|
CREATE INDEX IF NOT EXISTS idx_user_prompts_session ON user_prompts(session_id);
|
|
464
|
-
`);try{
|
|
464
|
+
`);try{r.run("ALTER TABLE memories ADD COLUMN session_id TEXT")}catch{}},"up")},{version:12,name:"task-body-and-comments",up:c(r=>{try{r.run("ALTER TABLE queue_tasks ADD COLUMN body TEXT")}catch{}r.run(`
|
|
465
465
|
CREATE TABLE IF NOT EXISTS queue_task_comments (
|
|
466
466
|
id TEXT PRIMARY KEY,
|
|
467
467
|
task_id TEXT NOT NULL,
|
|
@@ -472,7 +472,7 @@ CREATE TABLE velocity_sprints (
|
|
|
472
472
|
);
|
|
473
473
|
|
|
474
474
|
CREATE INDEX IF NOT EXISTS idx_qtc_task_id ON queue_task_comments(task_id);
|
|
475
|
-
`)},"up")},{version:13,name:"workflow-rules-v2",up:c(
|
|
475
|
+
`)},"up")},{version:13,name:"workflow-rules-v2",up:c(r=>{try{r.run("ALTER TABLE workflow_rules ADD COLUMN when_expr TEXT")}catch{}try{r.run("ALTER TABLE workflow_rules ADD COLUMN parallel INTEGER NOT NULL DEFAULT 1")}catch{}r.run(`
|
|
476
476
|
CREATE TABLE IF NOT EXISTS workflow_rule_cache (
|
|
477
477
|
rule_id INTEGER NOT NULL,
|
|
478
478
|
context_hash TEXT NOT NULL,
|
|
@@ -482,78 +482,126 @@ CREATE TABLE velocity_sprints (
|
|
|
482
482
|
);
|
|
483
483
|
|
|
484
484
|
CREATE INDEX IF NOT EXISTS idx_wrc_rule ON workflow_rule_cache(rule_id);
|
|
485
|
-
`)},"up")},{version:14,name:"workflow-rules-trust-source",up:c(
|
|
485
|
+
`)},"up")},{version:14,name:"workflow-rules-trust-source",up:c(r=>{try{r.run("ALTER TABLE workflow_rules ADD COLUMN trust_source TEXT NOT NULL DEFAULT 'local'")}catch{}},"up")},{version:15,name:"disable-orphan-workflow-rules",up:c(r=>{let e=["pause","resume","reopen","next","dash","bug","idea","linear","jira","tokens","velocity","plan"].map(s=>`'${s}'`).join(",");r.run(`UPDATE workflow_rules SET enabled = 0 WHERE command IN (${e}) AND enabled = 1`)},"up")},{version:16,name:"specs-and-task-linkage",up:c(r=>{r.run(`
|
|
486
|
+
CREATE TABLE IF NOT EXISTS specs (
|
|
487
|
+
id TEXT PRIMARY KEY,
|
|
488
|
+
title TEXT NOT NULL,
|
|
489
|
+
status TEXT NOT NULL DEFAULT 'draft',
|
|
490
|
+
content TEXT NOT NULL,
|
|
491
|
+
tags TEXT,
|
|
492
|
+
created_at TEXT NOT NULL,
|
|
493
|
+
updated_at TEXT NOT NULL,
|
|
494
|
+
shipped_at TEXT,
|
|
495
|
+
shipped_pr INTEGER,
|
|
496
|
+
archived_at TEXT
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
CREATE INDEX IF NOT EXISTS idx_specs_status ON specs(status);
|
|
500
|
+
CREATE INDEX IF NOT EXISTS idx_specs_created ON specs(created_at);
|
|
501
|
+
`);try{r.run("ALTER TABLE tasks ADD COLUMN linked_spec_id TEXT"),r.run("CREATE INDEX IF NOT EXISTS idx_tasks_spec ON tasks(linked_spec_id)")}catch{}},"up")}];function kn(){return typeof globalThis<"u"&&"Bun"in globalThis?"bun":"node"}c(kn,"detectRuntime");function ks(){return kn()==="bun"}c(ks,"isBun");function Es(r){if(ks()){let{Database:n}=De("bun:sqlite");return new n(r,{create:!0})}let t=De("better-sqlite3"),e=new t(r),s=e.exec.bind(e);return e.run=n=>s(n),e}c(Es,"openDatabase");var En=3,Zt=class{static{c(this,"PrjctDatabase")}connections=new Map;accessOrder=[];statementCache=new WeakMap;prepareCached(t,e){let s=this.statementCache.get(t);s||(s=new Map,this.statementCache.set(t,s));let n=s.get(e);if(n)return n;let i=t.prepare(e);return s.set(e,i),i}getDbPath(t){return Ss.join(_.getGlobalProjectPath(t),"prjct.db")}getDb(t){let e=this.connections.get(t);if(e)return this.touchAccessOrder(t),e;this.connections.size>=En&&this.evictLru();let s=this.getDbPath(t),n=Ss.dirname(s);Qt.existsSync(n)||Qt.mkdirSync(n,{recursive:!0});let i=Es(s);return i.run("PRAGMA journal_mode = WAL"),i.run("PRAGMA synchronous = NORMAL"),i.run("PRAGMA cache_size = -2000"),i.run("PRAGMA temp_store = MEMORY"),i.run("PRAGMA mmap_size = 33554432"),this.runMigrations(i),this.connections.set(t,i),this.touchAccessOrder(t),i}close(t){if(t){let e=this.connections.get(t);e&&(e.close(),this.connections.delete(t),this.accessOrder=this.accessOrder.filter(s=>s!==t))}else this.connections.forEach(e=>{e.close()}),this.connections.clear(),this.accessOrder=[]}touchAccessOrder(t){this.accessOrder=this.accessOrder.filter(e=>e!==t),this.accessOrder.push(t)}evictLru(){if(this.accessOrder.length===0)return;let t=this.accessOrder.shift(),e=this.connections.get(t);e&&(e.close(),this.connections.delete(t))}checkpointAll(){for(let[t,e]of this.connections)try{e.run("PRAGMA wal_checkpoint(TRUNCATE)")}catch{}}exists(t){return Qt.existsSync(this.getDbPath(t))}getDoc(t,e){let s=this.getDb(t),n=this.prepareCached(s,"SELECT data FROM kv_store WHERE key = ?").get(e);return n?JSON.parse(n.data):null}setDoc(t,e,s){let n=this.getDb(t),i=JSON.stringify(s),o=new Date().toISOString();this.prepareCached(n,"INSERT OR REPLACE INTO kv_store (key, data, updated_at) VALUES (?, ?, ?)").run(e,i,o)}deleteDoc(t,e){let s=this.getDb(t);this.prepareCached(s,"DELETE FROM kv_store WHERE key = ?").run(e)}hasDoc(t,e){let s=this.getDb(t);return this.prepareCached(s,"SELECT 1 FROM kv_store WHERE key = ?").get(e)!==null}appendEvent(t,e,s,n){let i=this.getDb(t),o=new Date().toISOString();this.prepareCached(i,"INSERT INTO events (type, task_id, data, timestamp) VALUES (?, ?, ?, ?)").run(e,n??null,JSON.stringify(s),o)}getEvents(t,e,s=100){let n=this.getDb(t);return e?this.prepareCached(n,"SELECT * FROM events WHERE type = ? ORDER BY id DESC LIMIT ?").all(e,s):this.prepareCached(n,"SELECT * FROM events ORDER BY id DESC LIMIT ?").all(s)}query(t,e,...s){let n=this.getDb(t);return this.prepareCached(n,e).all(...s)}run(t,e,...s){let n=this.getDb(t);this.prepareCached(n,e).run(...s)}get(t,e,...s){let n=this.getDb(t);return this.prepareCached(n,e).get(...s)??null}transaction(t,e){let s=this.getDb(t);return s.transaction(e)(s)}runMigrations(t){t.run(`
|
|
486
502
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
487
503
|
version INTEGER PRIMARY KEY,
|
|
488
504
|
name TEXT NOT NULL,
|
|
489
505
|
applied_at TEXT NOT NULL
|
|
490
506
|
)
|
|
491
|
-
`);let e=new Set(t.prepare("SELECT version FROM _migrations").all().map(
|
|
492
|
-
`)){let i
|
|
493
|
-
### Directly Changed (${
|
|
494
|
-
### Affected via Imports (${
|
|
495
|
-
### Affected Domains`),a.push(
|
|
496
|
-
Total affected: ${
|
|
497
|
-
`)}]}})),t.tool("prjct_import_graph","Import graph stats + file neighbors (imports/importers). Pass a file for its neighbors, omit for graph stats.",{projectPath:
|
|
498
|
-
### Imports (${
|
|
507
|
+
`);let e=new Set(t.prepare("SELECT version FROM _migrations").all().map(s=>s.version));for(let s of Ts)e.has(s.version)||t.transaction(()=>{s.up(t),t.prepare("INSERT INTO _migrations (version, name, applied_at) VALUES (?, ?, ?)").run(s.version,s.name,new Date().toISOString())})()}getMigrations(t){return this.getDb(t).prepare("SELECT * FROM _migrations ORDER BY version").all()}getSchemaVersion(t){return this.getDb(t).prepare("SELECT MAX(version) as version FROM _migrations").get()?.version??0}},k=new Zt,T=k;X();function Sn(r){let t=[],e,s=new RegExp(Me.source,"g");for(;(e=s.exec(r))!==null;){let n=e[1];(n.startsWith(".")||n.startsWith("@/"))&&t.push(n)}return t}c(Sn,"extractImportSources");async function wn(r,t,e){let s;if(r.startsWith("@/"))s=Q.join(e,"src",r.slice(2));else{let n=Q.dirname(Q.join(e,t));s=Q.resolve(n,r)}for(let n of Oe){let i=s+n;try{if((await ws.stat(i)).isFile())return Q.relative(e,i)}catch{}}return null}c(wn,"resolveImport");async function bn(r){let t=await Ge(r),e={},s={},n=0,i=await Je(t,50,async o=>{try{let a=await ws.readFile(Q.join(r,o),"utf-8"),u=Sn(a),p=[];for(let m of u){let d=await wn(m,o,r);d&&d!==o&&p.push(d)}return p.length>0?{filePath:o,imports:p}:null}catch{return null}});for(let{filePath:o,imports:a}of i){e[o]=a,n+=a.length;for(let u of a)s[u]||(s[u]=[]),s[u].push(o)}return{forward:e,reverse:s,fileCount:t.length,edgeCount:n,builtAt:new Date().toISOString()}}c(bn,"buildGraph");function bs(r,t,e=2){let s=new Set(r),n=new Map,i=[];for(let o of r){let a=t.forward[o]||[],u=t.reverse[o]||[];for(let p of[...a,...u])s.has(p)||i.push({file:p,depth:1})}for(;i.length>0;){let{file:o,depth:a}=i.shift();if(a>e)continue;let u=1/(a+1),p=n.get(o);if(p){u>p.score&&n.set(o,{score:u,depth:a});continue}if(n.set(o,{score:u,depth:a}),a<e){let m=t.forward[o]||[],d=t.reverse[o]||[];for(let h of[...m,...d])!s.has(h)&&!n.has(h)&&i.push({file:h,depth:a+1})}}return Array.from(n.entries()).map(([o,{score:a,depth:u}])=>({path:o,score:a,depth:u})).sort((o,a)=>a.score-o.score)}c(bs,"scoreFromSeeds");var te="import-graph",St=new Map;function _n(r,t){T.setDoc(r,te,t),St.delete(r)}c(_n,"saveGraph");function ct(r){let t=T.get(r,"SELECT updated_at FROM kv_store WHERE key = ?",te);if(!t)return St.delete(r),null;let e=St.get(r);if(e&&e.updatedAt===t.updated_at)return e.graph;let s=T.getDoc(r,te);return s&&St.set(r,{graph:s,updatedAt:t.updated_at}),s}c(ct,"loadGraph");async function _s(r,t){let e=await bn(r);return _n(t,e),e}c(_s,"indexImports");function vs(r,t){let e=[...r.added,...r.modified],s=new Set(e),n=new Set,i=ct(t);if(i)for(let u of e){let p=i.reverse[u];if(p)for(let m of p)s.has(m)||n.add(m)}let o=Array.from(n),a=[...e,...o];return{directlyChanged:e,affectedByImports:o,deleted:r.deleted,allAffected:a}}c(vs,"propagateChanges");function xs(r){let t=new Set;for(let e of r){let s=e.toLowerCase();(s.endsWith(".tsx")||s.endsWith(".jsx")||s.endsWith(".css")||s.endsWith(".scss")||s.endsWith(".vue")||s.endsWith(".svelte")||s.includes("/components/")||s.includes("/pages/")||s.includes("/app/"))&&(t.add("frontend"),t.add("uxui")),(s.includes(".test.")||s.includes(".spec.")||s.includes("__tests__")||s.includes("/test/"))&&t.add("testing"),(s.includes("dockerfile")||s.includes("docker-compose")||s.includes(".dockerignore")||s.includes(".github/")||s.includes("ci/")||s.includes("cd/"))&&t.add("devops"),(s.endsWith(".sql")||s.includes("prisma")||s.includes("drizzle")||s.includes("migration")||s.includes("/db/"))&&t.add("database"),(s.endsWith(".ts")||s.endsWith(".js"))&&!s.includes(".test.")&&!s.includes(".spec.")&&!s.endsWith(".d.ts")&&t.add("backend")}return t}c(xs,"affectedDomains");V();async function xn(r,t=100){try{let{stdout:e}=await w(`git log --name-only --pretty=format:'---COMMIT---' -${t}`,{cwd:r,maxBuffer:10485760}),s=[],n=null;for(let i of e.split(`
|
|
508
|
+
`)){let o=i.trim();o==="---COMMIT---"?(n&&n.size>0&&n.size<=30&&s.push(n),n=new Set):o&&n&&Pn(o)&&n.add(o)}return n&&n.size>0&&n.size<=30&&s.push(n),s}catch{return[]}}c(xn,"parseGitLog");function Pn(r){return/\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|cs|rb|php|vue|svelte)$/i.test(r)&&!r.includes("node_modules/")}c(Pn,"isSourceFile");async function Rn(r,t=100){let e=await xn(r,t),s=new Map,n=new Map;for(let o of e){let a=Array.from(o);for(let u of a)s.set(u,(s.get(u)||0)+1);for(let u=0;u<a.length;u++)for(let p=u+1;p<a.length;p++){let m=An(a[u],a[p]);n.set(m,(n.get(m)||0)+1)}}let i={};for(let[o,a]of n){let[u,p]=o.split("\0"),m=s.get(u)||0,d=s.get(p)||0;if(m<2||d<2)continue;let h=m+d-a,y=h>0?a/h:0;y<.1||(i[u]||(i[u]={}),i[p]||(i[p]={}),i[u][p]=y,i[p][u]=y)}return{matrix:i,commitsAnalyzed:e.length,filesAnalyzed:s.size,builtAt:new Date().toISOString()}}c(Rn,"buildMatrix");function An(r,t){return r<t?`${r}\0${t}`:`${t}\0${r}`}c(An,"pairKey");function se(r,t){let e=new Set(r),s=new Map;for(let n of r){let i=t.matrix[n];if(i)for(let[o,a]of Object.entries(i)){if(e.has(o))continue;let u=s.get(o)||0;a>u&&s.set(o,a)}}return Array.from(s.entries()).map(([n,i])=>({path:n,score:i})).sort((n,i)=>i.score-n.score)}c(se,"scoreFromSeeds");var ee="cochange-index",wt=new Map;function Cn(r,t){T.setDoc(r,ee,t),wt.delete(r)}c(Cn,"saveMatrix");function re(r){let t=T.get(r,"SELECT updated_at FROM kv_store WHERE key = ?",ee);if(!t)return wt.delete(r),null;let e=wt.get(r);if(e&&e.updatedAt===t.updated_at)return e.matrix;let s=T.getDoc(r,ee);return s&&wt.set(r,{matrix:s,updatedAt:t.updated_at}),s}c(re,"loadMatrix");async function As(r,t,e=100){let s=await Rn(r,e);return Cn(t,s),s}c(As,"indexCoChanges");import ce from"node:fs/promises";import Mn from"node:path";import*as vt from"jsonc-parser";var ne=class extends Error{static{c(this,"PrjctError")}code;isOperational;constructor(t,e="PRJCT_ERROR"){super(t),this.name="PrjctError",this.code=e,this.isOperational=!0,Error.captureStackTrace?.(this,this.constructor)}};function Nn(r){return r instanceof ne}c(Nn,"isPrjctError");function ie(r){return Nn(r)||r instanceof Error?r.message:typeof r=="string"?r:"Unknown error"}c(ie,"getErrorMessage");J();X();J();import oe from"node:fs";import bt from"node:path";var Z=null,ut=null;function Cs(){if(ut)return ut;let r=__dirname;for(let t=0;t<5;t++){let e=bt.join(r,"package.json");if(oe.existsSync(e))try{if(JSON.parse(oe.readFileSync(e,"utf-8")).name==="prjct-cli")return ut=r,r}catch{}r=bt.dirname(r)}return ut=bt.join(__dirname,"..","..",".."),ut}c(Cs,"getPackageRoot");function In(){if(Z)return Z;let r=process.env.PRJCT_VERSION;if(r&&/^\d+\.\d+\.\d+/.test(r))return Z=r,Z;try{let t=bt.join(Cs(),"package.json");return Z=JSON.parse(oe.readFileSync(t,"utf-8")).version,Z}catch(t){return process.env.PRJCT_DEBUG==="1"&&console.error("Failed to read version from package.json:",$e(t)),"0.0.0"}}c(In,"getVersion");var ae=In(),Ra=Cs();V();async function _t(r){try{let{stdout:t}=await w(r,{timeout:5e3});return{success:!0,output:t.trim()}}catch{return{success:!1,output:""}}}c(_t,"execCommand");async function Dn(){let r=await _t("gh api user --jq .login");return r.success&&r.output||(r=await _t("git config --global github.user"),r.success&&r.output)?r.output:null}c(Dn,"detectGitHubUsername");async function Ln(){let r=await _t("git config user.name");return r.success&&r.output?r.output:null}c(Ln,"detectGitName");async function jn(){let r=await _t("git config user.email");return r.success&&r.output?r.output:null}c(jn,"detectGitEmail");async function Ns(){let[r,t,e]=await Promise.all([Dn(),Ln(),jn()]);return{github:r,email:e,name:t||r||"Unknown"}}c(Ns,"detect");function Is(r){let t=[],e=vt.parse(r,t,{allowTrailingComma:!0,disallowComments:!1});if(t.length>0){let s=t[0];throw new SyntaxError(`JSON parse error at offset ${s.offset}: ${vt.printParseErrorCode(s.error)}`)}return e}c(Is,"parseJsonc");var ue=class{static{c(this,"ConfigManager")}async readConfig(t){try{let e=_.getLocalConfigPath(t),s=await ce.readFile(e,"utf-8");return Is(s)}catch(e){return N(e)||console.warn(`Warning: Could not read config at ${t}: ${ie(e)}`),null}}async writeConfig(t,e){let s=_.getLocalConfigPath(t);await $(s,e)}async readGlobalConfig(t){try{let e=_.getGlobalProjectConfigPath(t),s=await ce.readFile(e,"utf-8");return Is(s)}catch(e){return N(e)||console.warn(`Warning: Could not read global config for ${t}: ${ie(e)}`),null}}async writeGlobalConfig(t,e){let s=_.getGlobalProjectConfigPath(t);await $(s,e)}async ensureGlobalConfig(t){let e=await this.readGlobalConfig(t);if(!e){let s=g();e={projectId:t,authors:[],version:ae,lastSync:s},await this.writeGlobalConfig(t,e)}return e}async createConfig(t,e){let s=_.generateProjectId(t),n=_.getGlobalProjectPath(s),i=_.getDisplayPath(n),o=g(),a={projectId:s,dataPath:i,showMetrics:!0};await this.writeConfig(t,a);let u={projectId:s,authors:[{name:e.name||"Unknown",email:e.email||"",github:e.github||"",firstContribution:o,lastActivity:o}],version:ae,created:o,lastSync:o};return await this.writeGlobalConfig(s,u),a}async updateLastSync(t){let e=await this.getProjectId(t),s=await this.readGlobalConfig(e);s&&(s.lastSync=g(),await this.writeGlobalConfig(e,s))}validateConfig(t){return!(!t||!t.projectId||!t.dataPath)}async needsMigration(t){if(!await _.hasLegacyStructure(t))return!1;if(!await _.hasConfig(t))return!0;let n=await this.readConfig(t);if(!n||!n.projectId)return!0;let i=_.getGlobalProjectPath(n.projectId);try{return(await ce.readdir(Mn.join(i,"core"))).length===0}catch(o){return N(o),!0}}async getProjectId(t){let e=await this.readConfig(t);if(e?.projectId)return e.projectId;try{let{worktreeService:s}=await Promise.resolve().then(()=>(Wt(),Xt));if(await s.detect(t)){let i=await s.getMainWorktree(t);if(i!==t){let o=await this.readConfig(i);if(o?.projectId)return o.projectId}}}catch{}return _.generateProjectId(t)}async findAuthor(t,e){let s=await this.readGlobalConfig(t);return!s||!s.authors?null:s.authors.find(n=>n.github===e)||null}async addAuthor(t,e){let s=await this.ensureGlobalConfig(t);if(s.authors.some(o=>o.github===e.github))return;let i=g();s.authors.push({name:e.name||"Unknown",email:e.email||"",github:e.github||"",firstContribution:i,lastActivity:i}),s.lastSync=i,await this.writeGlobalConfig(t,s)}async updateAuthorActivity(t,e){let s=await this.readGlobalConfig(t);if(!s||!s.authors)return;let n=s.authors.find(i=>i.github===e);n&&(n.lastActivity=g(),s.lastSync=n.lastActivity,await this.writeGlobalConfig(t,s))}async getCurrentAuthor(t){let e=await Ns(),s=await this.getProjectId(t);return await this.addAuthor(s,{name:e.name??void 0,email:e.email??void 0,github:e.github??void 0}),e.github||e.name||"Unknown"}async isConfigured(t){let e=await this.readConfig(t);return this.validateConfig(e)}async getShowMetrics(t){return(await this.readConfig(t))?.showMetrics??!0}async setShowMetrics(t,e){let s=await this.readConfig(t);s&&(s.showMetrics=e,await this.writeConfig(t,s))}async getConfigWithDefaults(t){let e=await this.readConfig(t);if(e)return e;let s=_.generateProjectId(t);return{projectId:s,dataPath:_.getDisplayPath(_.getGlobalProjectPath(s))}}},Fn=new ue,W=Fn;async function v(r){return W.getProjectId(r)}c(v,"resolveProjectId");function E(r,t){return async e=>{try{return await t(e)}catch(s){return Un(s,r)}}}c(E,"safeMcpCall");function Un(r,t){let e=r instanceof Error?r.message:String(r);return{content:[{type:"text",text:`[${t}] Error: ${e}`}],isError:!0}}c(Un,"mcpError");function Ds(r){let t=r;t.tool("prjct_impact_analysis","Given changed files, find affected files via import graph + affected domains",{projectPath:C.string().describe("Project directory path"),changedFiles:C.array(C.string()).describe("List of changed file paths (relative to project root)")},E("prjct_impact_analysis",async e=>{let s=await v(e.projectPath),n={added:[],modified:e.changedFiles,deleted:[],unchanged:[]},i=vs(n,s),o=xs(i.allAffected),a=["## Impact Analysis"];a.push(`
|
|
509
|
+
### Directly Changed (${i.directlyChanged.length})`);for(let u of i.directlyChanged)a.push(`- ${u}`);if(i.affectedByImports.length>0){a.push(`
|
|
510
|
+
### Affected via Imports (${i.affectedByImports.length})`);for(let u of i.affectedByImports)a.push(`- ${u}`)}return a.push(`
|
|
511
|
+
### Affected Domains`),a.push(o.size>0?Array.from(o).join(", "):"none detected"),a.push(`
|
|
512
|
+
Total affected: ${i.allAffected.length} files`),{content:[{type:"text",text:a.join(`
|
|
513
|
+
`)}]}})),t.tool("prjct_import_graph","Import graph stats + file neighbors (imports/importers). Pass a file for its neighbors, omit for graph stats.",{projectPath:C.string().describe("Project directory path"),file:C.string().optional().describe("File path to get neighbors for (omit for graph stats)"),rebuild:C.boolean().optional().default(!1).describe("Force rebuild the import graph")},E("prjct_import_graph",async e=>{let s=await v(e.projectPath),n=e.rebuild?null:ct(s);if(n||(n=await _s(e.projectPath,s)),e.file){let o=n.forward[e.file]||[],a=n.reverse[e.file]||[];return{content:[{type:"text",text:[`## Import Neighbors: ${e.file}`,`
|
|
514
|
+
### Imports (${o.length})`,...o.map(p=>`- ${p}`),`
|
|
499
515
|
### Imported By (${a.length})`,...a.map(p=>`- ${p}`)].join(`
|
|
500
516
|
`)}]}}return{content:[{type:"text",text:["## Import Graph Stats",`Files: ${n.fileCount}`,`Edges: ${n.edgeCount}`,`Built: ${n.builtAt}`].join(`
|
|
501
|
-
`)}]}})),t.tool("prjct_cochange","Files that historically change together (Jaccard similarity from git history)",{projectPath:
|
|
502
|
-
`)}]}})),t.tool("prjct_related_context","Combined: import neighbors + co-change partners for seed files",{projectPath:
|
|
503
|
-
`)}]}}))}c(Sr,"registerCodeIntelTools");import{z as B}from"zod";Ut();import{z as l}from"zod";var An=l.enum(["low","medium","high","critical"]),Et=l.enum(["feature","bug","improvement","chore"]),Nn=l.enum(["active","backlog","previously_active"]),Cn=l.enum(["pending","in_progress","completed","blocked","paused","failed","skipped"]),ne=l.object({title:l.string(),description:l.string(),filesChanged:l.array(l.object({path:l.string(),action:l.enum(["created","modified","deleted"])})),whatWasDone:l.array(l.string()).min(1),outputForNextAgent:l.string().min(1),notes:l.string().optional()}),vr=l.object({output:l.string().min(1,"Subtask output is required"),summary:ne}),Pr=l.object({id:l.string(),description:l.string(),domain:l.string(),agent:l.string(),status:Cn,dependsOn:l.array(l.string()),startedAt:l.string().optional(),completedAt:l.string().optional(),output:l.string().optional(),summary:ne.optional(),skipReason:l.string().optional(),blockReason:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional()}),_r=l.object({completed:l.number(),total:l.number(),percentage:l.number()}),Rr=l.object({id:l.string(),description:l.string(),type:Et.optional(),startedAt:l.string(),sessionId:l.string(),featureId:l.string().optional(),subtasks:l.array(Pr).optional(),currentSubtaskIndex:l.number().optional(),subtaskProgress:_r.optional(),linearId:l.string().optional(),linearUuid:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional(),modelMetadata:Ft.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional(),parentDescription:l.string().optional(),branch:l.string().optional(),prUrl:l.string().optional()}),xr=l.object({id:l.string(),description:l.string(),status:l.literal("paused"),startedAt:l.string(),pausedAt:l.string(),pauseReason:l.string().optional(),type:Et.optional(),sessionId:l.string().optional(),featureId:l.string().optional(),subtasks:l.array(Pr).optional(),currentSubtaskIndex:l.number().optional(),subtaskProgress:_r.optional(),linearId:l.string().optional(),linearUuid:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional(),modelMetadata:Ft.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional()}),In=l.object({stackConfirmed:l.array(l.string()).optional(),patternsDiscovered:l.array(l.string()).optional(),agentAccuracy:l.array(l.object({agent:l.string(),rating:l.enum(["helpful","neutral","inaccurate"]),note:l.string().optional()})).optional(),issuesEncountered:l.array(l.string()).optional()}),Dn=l.object({taskId:l.string(),title:l.string(),classification:Et,startedAt:l.string(),completedAt:l.string(),subtaskCount:l.number(),subtaskSummaries:l.array(ne),outcome:l.string(),branchName:l.string(),linearId:l.string().optional(),linearUuid:l.string().optional(),prUrl:l.string().optional(),feedback:In.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional()}),Ln=Rr.extend({workspaceId:l.string(),worktreePath:l.string().optional(),agentSessionId:l.string().optional(),jiraId:l.string().optional(),jiraUuid:l.string().optional(),dispatchedFrom:l.string().optional()}),Ar=l.object({currentTask:Rr.nullable(),previousTask:xr.nullable().optional(),pausedTasks:l.array(xr).optional(),taskHistory:l.array(Dn).optional(),activeTasks:l.array(Ln).optional(),lastUpdated:l.string()}),On=l.object({id:l.string(),description:l.string(),body:l.string().optional(),priority:An,type:Et,featureId:l.string().optional(),originFeature:l.string().optional(),completed:l.boolean(),completedAt:l.string().optional(),createdAt:l.string(),section:Nn,agent:l.string().optional(),groupName:l.string().optional(),groupId:l.string().optional()}),Nr=l.object({tasks:l.array(On),lastUpdated:l.string()});var nt={idle:{transitions:["task"],prompt:"prjct task <description> Start working",description:"No active task"},working:{transitions:["done","pause"],prompt:"prjct status done Complete task | prjct status paused Switch context",description:"Task in progress"},paused:{transitions:["resume","task","ship"],prompt:"prjct status active Continue | prjct task <new> Start different | prjct ship Ship directly",description:"Task paused"},completed:{transitions:["ship","task","pause","reopen"],prompt:"prjct ship Ship it | prjct task <next> Start next | prjct status active Reopen",description:"Task completed"},shipped:{transitions:["task"],prompt:"prjct task <description> Start new task",description:"Feature shipped"}},oe=class{static{c(this,"WorkflowStateMachine")}getCurrentState(t,e){let r=null;if(e&&t?.activeTasks?.length&&(r=t.activeTasks.find(o=>o.workspaceId===e)),r||(r=t?.currentTask),!r)return(t?.pausedTasks?.length||0)>0||t?.previousTask?.status==="paused"?"paused":"idle";switch((typeof r.status=="string"?r.status:"").toLowerCase()){case"in_progress":case"working":return"working";case"paused":return"paused";case"completed":case"done":return"completed";case"shipped":return"shipped";default:return r?"working":"idle"}}canTransition(t,e){if(nt[t].transitions.includes(e))return{valid:!0};let n=this.formatNextSteps(t).join(" | ");return{valid:!1,error:`Cannot transition to '${e}' from '${t}' state`,suggestion:`Valid next steps: ${n}`}}getNextState(t,e){switch(e){case"task":return"working";case"done":return"completed";case"pause":return"paused";case"resume":return"working";case"ship":return"shipped";case"reopen":return"working";default:return t}}getStateInfo(t){return nt[t]}getPrompt(t){return nt[t].prompt}getValidCommands(t){return nt[t].transitions}formatNextSteps(t){return nt[t].transitions.map(r=>{switch(r){case"task":return"prjct task <desc> Start new task";case"done":return"prjct status done Complete current task";case"pause":return"prjct status paused Pause and switch context";case"resume":return"prjct status active Continue paused task";case"ship":return"prjct ship Ship the feature";case"reopen":return"prjct status active Reopen completed task";default:return`prjct ${r}`}})}},ie=new oe;import Mn from"node:crypto";function U(){return Mn.randomUUID()}c(U,"generateUUID");var ot={SHIPPED_RETENTION_DAYS:90,IDEA_DORMANT_DAYS:180,QUEUE_COMPLETED_DAYS:7,PAUSED_TASK_DAYS:30,MEMORY_MAX_ENTRIES:500},ae=class{static{c(this,"ArchiveStorage")}archive(t,e){let r=U(),n=f();return y.run(t,"INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)",r,e.entityType,e.entityId,JSON.stringify(e.entityData),e.summary??null,n,e.reason),r}archiveMany(t,e){if(e.length===0)return 0;let r=f();return y.transaction(t,n=>{let o=n.prepare("INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)");for(let i of e)o.run(U(),i.entityType,i.entityId,JSON.stringify(i.entityData),i.summary??null,r,i.reason)}),e.length}getArchived(t,e,r=50){return e?y.query(t,"SELECT * FROM archives WHERE entity_type = ? ORDER BY archived_at DESC LIMIT ?",e,r):y.query(t,"SELECT * FROM archives ORDER BY archived_at DESC LIMIT ?",r)}getStats(t){let e=y.query(t,"SELECT entity_type, COUNT(*) as count FROM archives GROUP BY entity_type"),r={shipped:0,idea:0,queue_task:0,paused_task:0,memory_entry:0,total:0};for(let n of e){let o=n.entity_type;o in r&&(r[o]=n.count),r.total+=n.count}return r}restore(t,e){let r=y.get(t,"SELECT * FROM archives WHERE id = ?",e);return r?(y.run(t,"DELETE FROM archives WHERE id = ?",e),JSON.parse(r.entity_data)):null}pruneOldArchives(t,e){let r=new Date(Date.now()-e*24*60*60*1e3).toISOString(),n=this.getTotalCount(t);y.run(t,"DELETE FROM archives WHERE archived_at < ?",r);let o=this.getTotalCount(t);return n-o}getTotalCount(t){return y.get(t,"SELECT COUNT(*) as count FROM archives")?.count??0}},z=new ae;async function Cr(s,t,e){let r=await s.read(t);if(!r.currentTask)return null;s.validateTransition(r,"pause");let n={...r.currentTask,status:"paused",pausedAt:f(),pauseReason:e},o=s.getPausedTasksFromState(r),i=[n,...o].slice(0,s.maxPausedTasks);return await s.update(t,a=>({...a,currentTask:null,previousTask:null,pausedTasks:i,lastUpdated:f()})),await s.publish(t,"task.paused",{taskId:n.id,description:n.description,pausedAt:n.pausedAt,reason:e,pausedCount:i.length}),n}c(Cr,"pauseTask");async function Ir(s,t,e){let r=await s.read(t),n=s.getPausedTasksFromState(r);if(n.length===0)return null;s.validateTransition(r,"resume");let o=0;if(e&&(o=n.findIndex(h=>h.id===e),o===-1))return null;let i=n[o],a=n.filter((h,N)=>N!==o),{status:u,pausedAt:p,pauseReason:m,...d}=i,g={...d,startedAt:f(),sessionId:i.sessionId??U()};return await s.update(t,h=>({...h,currentTask:g,previousTask:null,pausedTasks:a,lastUpdated:f()})),await s.publish(t,"task.resumed",{taskId:g.id,description:g.description,resumedAt:g.startedAt,remainingPaused:a.length}),g}c(Ir,"resumeTask");async function Dr(s,t){let e=await s.read(t),r=s.getPausedTasksFromState(e),n=Date.now()-s.stalenessThresholdDays*24*60*60*1e3;return r.filter(o=>new Date(o.pausedAt).getTime()<n)}c(Dr,"getStalePausedTasks");async function Lr(s,t){let e=await s.read(t),r=s.getPausedTasksFromState(e),n=Date.now()-s.stalenessThresholdDays*24*60*60*1e3,o=r.filter(a=>new Date(a.pausedAt).getTime()<n),i=r.filter(a=>new Date(a.pausedAt).getTime()>=n);if(o.length===0)return[];z.archiveMany(t,o.map(a=>({entityType:"paused_task",entityId:a.id,entityData:a,summary:a.description,reason:"staleness"}))),await s.update(t,a=>({...a,pausedTasks:i,previousTask:null,lastUpdated:f()}));for(let a of o)await s.publish(t,"task.archived",{taskId:a.id,description:a.description,pausedAt:a.pausedAt,reason:"staleness"});return o}c(Lr,"archiveStalePausedTasks");async function Or(s,t){await s.update(t,()=>({currentTask:null,previousTask:null,pausedTasks:[],activeTasks:[],lastUpdated:f()}))}c(Or,"clearTask");async function Mr(s,t){let e=await s.read(t),r=s.getPausedTasksFromState(e);return e.currentTask!==null||r.length>0}c(Mr,"hasTask");async function jr(s,t){let e=await s.read(t);return s.getPausedTasksFromState(e)[0]||null}c(jr,"getPausedTask");async function Fr(s,t){let e=await s.read(t);return s.getPausedTasksFromState(e)}c(Fr,"getAllPausedTasks");async function ce(s,t){let e=await s.read(t);return s.getTaskHistoryFromState(e)}c(ce,"getTaskHistory");async function Ur(s,t){let e=await s.read(t);return s.getTaskHistoryFromState(e)[0]||null}c(Ur,"getMostRecentTask");async function Xr(s,t,e){let r=await s.read(t);return s.getTaskHistoryFromState(r).filter(o=>o.classification===e)}c(Xr,"getTaskHistoryByType");async function Wr(s,t){let r=(await ce(s,t)).filter(g=>g.feedback),n=[],o=[],i=[],a=[];for(let g of r){let h=g.feedback;Array.isArray(h.stackConfirmed)&&n.push(...h.stackConfirmed),Array.isArray(h.patternsDiscovered)&&o.push(...h.patternsDiscovered),Array.isArray(h.agentAccuracy)&&i.push(...h.agentAccuracy),Array.isArray(h.issuesEncountered)&&a.push(...h.issuesEncountered)}let u=[...new Set(n)],p=[...new Set(o)],m=new Map;for(let g of a)m.set(g,(m.get(g)||0)+1);let d=[...m.entries()].filter(([g,h])=>h>=2).map(([g])=>g);return{stackConfirmed:u,patternsDiscovered:p,agentAccuracy:i,issuesEncountered:[...new Set(a)],knownGotchas:d}}c(Wr,"getAggregatedFeedback");async function $r(s,t,e){let r=await s.read(t);if(!r.currentTask)return;let n=e.map((o,i)=>({...o,status:i===0?"in_progress":"pending",startedAt:i===0?f():void 0,dependsOn:o.dependsOn||[]}));await s.update(t,o=>({...o,currentTask:{...o.currentTask,subtasks:n,currentSubtaskIndex:0,subtaskProgress:{completed:0,total:n.length,percentage:0}},lastUpdated:f()})),await s.publish(t,"subtasks.created",{taskId:r.currentTask.id,subtaskCount:n.length,subtasks:n.map(o=>({id:o.id,description:o.description,domain:o.domain}))})}c($r,"createSubtasks");async function Br(s,t,e){let r=vr.safeParse(e);if(!r.success){let N=r.error.issues.map(at=>`${at.path.join(".")}: ${at.message}`);throw new Error(`Subtask completion requires handoff data:
|
|
504
|
-
${
|
|
505
|
-
`)}`)}let{output:n,summary:o}=r.data,i=await s.read(t);if(!i.currentTask?.subtasks)return null;let a=i.currentTask.currentSubtaskIndex||0,u=i.currentTask.subtasks[a];if(!u)return null;let p=[...i.currentTask.subtasks];p[a]={...u,status:"completed",completedAt:f(),output:n,summary:o};let m=p.filter(N=>N.status==="completed").length,d=p.length,g=Math.round(m/d*100),h=a+1;return h<p.length&&(p[h]={...p[h],status:"in_progress",startedAt:f()}),await s.update(t,N=>({...N,currentTask:{...N.currentTask,subtasks:p,currentSubtaskIndex:h<d?h:a,subtaskProgress:{completed:m,total:d,percentage:g}},lastUpdated:f()})),await s.publish(t,"subtask.completed",{taskId:i.currentTask.id,subtaskId:u.id,description:u.description,output:n,handoff:o.outputForNextAgent,filesChanged:o.filesChanged.length,progress:{completed:m,total:d,percentage:g}}),h<d?p[h]:null}c(Br,"completeSubtask");async function Hr(s,t){let e=await s.read(t);if(!e.currentTask?.subtasks)return null;let r=e.currentTask.currentSubtaskIndex||0;return e.currentTask.subtasks[r]||null}c(Hr,"getCurrentSubtask");async function Gr(s,t){let e=await s.read(t);if(!e.currentTask?.subtasks)return null;let r=(e.currentTask.currentSubtaskIndex||0)+1;return e.currentTask.subtasks[r]||null}c(Gr,"getNextSubtask");async function ue(s,t){let e=await s.read(t);if(!e.currentTask?.subtasks)return null;let r=(e.currentTask.currentSubtaskIndex||0)-1;return r<0?null:e.currentTask.subtasks[r]||null}c(ue,"getPreviousSubtask");async function qr(s,t){let e=await ue(s,t);return e?.summary?.outputForNextAgent?{fromSubtask:e.description,outputForNextAgent:e.summary.outputForNextAgent,filesChanged:e.summary.filesChanged,whatWasDone:e.summary.whatWasDone}:null}c(qr,"getPreviousHandoff");async function Jr(s,t){return(await s.read(t)).currentTask?.subtasks||[]}c(Jr,"getSubtasks");async function Yr(s,t){return(await s.read(t)).currentTask?.subtaskProgress||null}c(Yr,"getSubtaskProgress");async function zr(s,t){return((await s.read(t)).currentTask?.subtasks?.length||0)>0}c(zr,"hasSubtasks");async function Kr(s,t){let e=await s.read(t);return e.currentTask?.subtasks?e.currentTask.subtasks.every(r=>r.status==="completed"||r.status==="failed"||r.status==="skipped"):!0}c(Kr,"areAllSubtasksComplete");async function Vr(s,t,e){let r=await s.read(t);if(!r.currentTask?.subtasks)return null;let n=r.currentTask.currentSubtaskIndex||0,o=r.currentTask.subtasks[n];if(!o)return null;let i=[...r.currentTask.subtasks];i[n]={...o,status:"failed",completedAt:f(),output:`Failed: ${e}`};let a=n+1,u=i.length;a<u&&(i[a]={...i[a],status:"in_progress",startedAt:f()});let p=i.filter(d=>d.status==="completed"||d.status==="failed"||d.status==="skipped").length,m=Math.round(p/u*100);return await s.update(t,d=>({...d,currentTask:{...d.currentTask,subtasks:i,currentSubtaskIndex:a<u?a:n,subtaskProgress:{completed:p,total:u,percentage:m}},lastUpdated:f()})),await s.publish(t,"subtask.failed",{taskId:r.currentTask.id,subtaskId:o.id,description:o.description,error:e}),a<u?i[a]:null}c(Vr,"failSubtask");async function Qr(s,t,e){let r=await s.read(t);if(!r.currentTask?.subtasks)return null;let n=r.currentTask.currentSubtaskIndex||0,o=r.currentTask.subtasks[n];if(!o)return null;let i=[...r.currentTask.subtasks];i[n]={...o,status:"skipped",completedAt:f(),output:`Skipped: ${e}`,skipReason:e};let a=n+1,u=i.length;a<u&&(i[a]={...i[a],status:"in_progress",startedAt:f()});let p=i.filter(d=>d.status==="completed"||d.status==="failed"||d.status==="skipped").length,m=Math.round(p/u*100);return await s.update(t,d=>({...d,currentTask:{...d.currentTask,subtasks:i,currentSubtaskIndex:a<u?a:n,subtaskProgress:{completed:p,total:u,percentage:m}},lastUpdated:f()})),await s.publish(t,"subtask.skipped",{taskId:r.currentTask.id,subtaskId:o.id,description:o.description,reason:e}),a<u?i[a]:null}c(Qr,"skipSubtask");async function Zr(s,t,e){let r=await s.read(t);if(!r.currentTask?.subtasks)return null;let n=r.currentTask.currentSubtaskIndex||0,o=r.currentTask.subtasks[n];if(!o)return null;let i=[...r.currentTask.subtasks];i[n]={...o,status:"blocked",output:`Blocked: ${e}`,blockReason:e};let a=n+1,u=i.length;return a<u&&(i[a]={...i[a],status:"in_progress",startedAt:f()}),await s.update(t,p=>({...p,currentTask:{...p.currentTask,subtasks:i,currentSubtaskIndex:a<u?a:n},lastUpdated:f()})),await s.publish(t,"subtask.blocked",{taskId:r.currentTask.id,subtaskId:o.id,description:o.description,blocker:e}),a<u?i[a]:null}c(Zr,"blockSubtask");async function ts(s,t,e,r){let n={...e,workspaceId:r,startedAt:f()};return await s.update(t,o=>({...o,activeTasks:[...o.activeTasks||[],n],lastUpdated:f()})),await s.publish(t,"task.started",{taskId:n.id,description:n.description,startedAt:n.startedAt,sessionId:n.sessionId,workspaceId:r}),n}c(ts,"startTaskInWorkspace");async function es(s,t,e){return((await s.read(t)).activeTasks||[]).find(n=>n.workspaceId===e)??null}c(es,"getCurrentTaskForWorkspace");async function rs(s,t,e,r){let n=await s.read(t),i=(n.activeTasks||[]).find(d=>d.workspaceId===e);if(!i)return null;let a=f(),u=s.createTaskHistoryEntry(i,a,r),p=s.getTaskHistoryFromState(n),m=[u,...p].slice(0,s.maxTaskHistory);return await s.update(t,d=>({...d,activeTasks:(d.activeTasks||[]).filter(g=>g.workspaceId!==e),taskHistory:m,lastUpdated:a})),await s.publish(t,"task.completed",{taskId:i.id,description:i.description,startedAt:i.startedAt,completedAt:a,workspaceId:e}),i}c(rs,"completeTaskInWorkspace");async function ss(s,t){return(await s.read(t)).activeTasks||[]}c(ss,"getActiveTasks");async function ns(s,t){return((await s.read(t)).activeTasks||[]).length}c(ns,"getActiveTaskCount");async function os(s,t,e,r){let o=(await s.read(t)).activeTasks||[],i=o.findIndex(u=>u.workspaceId===e);if(i===-1)return null;let a={...o[i],...r,workspaceId:e};return await s.update(t,u=>{let p=[...u.activeTasks||[]];return p[i]=a,{...u,activeTasks:p,lastUpdated:f()}}),a}c(os,"updateWorkspaceTask");async function is(s,t,e,r){let n=await s.read(t);if(!n.currentTask)return null;let o=(n.currentTask.tokensIn||0)+e,i=(n.currentTask.tokensOut||0)+r;return await s.update(t,a=>({...a,currentTask:{...a.currentTask,tokensIn:o,tokensOut:i},lastUpdated:f()})),{tokensIn:o,tokensOut:i}}c(is,"addTokens");M();var le=class{static{c(this,"SyncEventBus")}async publish(t){let e=b.getSyncPendingPath(t.projectId),r=await ut(e,[])??[],n=Array.isArray(r)?r:[];n.push(t),await O(e,n)}async getPending(t){let e=b.getSyncPendingPath(t),r=await ut(e,[])??[];return Array.isArray(r)?r:[]}async clearPending(t){let e=b.getSyncPendingPath(t);await O(e,[])}async updateLastSync(t){let e=b.getLastSyncPath(t),r={timestamp:f(),success:!0};await O(e,r)}async getLastSync(t){let e=b.getLastSyncPath(t);return await ut(e,null)}},as=new le;Xt();var K=class{static{c(this,"StorageManager")}filename;cache;constructor(t,e){this.filename=t,this.cache=new lt({ttl:5e3,maxSize:50})}getStoreKey(){return this.filename.replace(".json","")}async read(t){let e=this.cache.get(t);if(e!==null)return e;try{let r=y.getDoc(t,this.getStoreKey());if(r!==null)return this.cache.set(t,r),r}catch{}return this.getDefault()}async write(t,e){y.setDoc(t,this.getStoreKey(),e),this.cache.set(t,e)}async update(t,e){let r=await this.read(t),n=e(r);return await this.write(t,n),n}async publishEvent(t,e,r){let n={type:e,path:[this.filename.replace(".json","")],data:r,timestamp:f(),projectId:t};await as.publish(n)}async publishEntityEvent(t,e,r,n){let o=`${e}.${r}`,i={...n,timestamp:f()};await this.publishEvent(t,o,i)}async exists(t){try{return y.hasDoc(t,this.getStoreKey())}catch{return!1}}clearCache(t){t?this.cache.delete(t):this.cache.clear()}getCacheStats(){return this.cache.stats()}};var pe=class extends K{static{c(this,"StateStorage")}constructor(){super("state.json",Ar)}getDefault(){return{currentTask:null,previousTask:null,pausedTasks:[],taskHistory:[],activeTasks:[],lastUpdated:""}}getEventType(t){return`state.${t}d`}validateTransition(t,e){let r=ie.getCurrentState(t),n=ie.canTransition(r,e);if(!n.valid)throw new Error(`${n.error}. ${n.suggestion||""}`.trim())}async getCurrentTask(t){return(await this.read(t)).currentTask}async getPausedTasks(t){let e=await this.read(t);return this.getPausedTasksFromState(e)}async startTask(t,e){let r=await this.read(t);this.validateTransition(r,"task");let n={...e,startedAt:f()};return await this.update(t,o=>({...o,currentTask:n,lastUpdated:f()})),await this.publishEvent(t,"task.started",{taskId:n.id,description:n.description,startedAt:n.startedAt,sessionId:n.sessionId}),n}async updateCurrentTask(t,e){let r=await this.read(t);if(!r.currentTask)return null;let n={...r.currentTask,...e};return await this.update(t,o=>({...o,currentTask:n,lastUpdated:f()})),n}async completeTask(t,e){let r=await this.read(t),n=r.currentTask;if(!n)return null;this.validateTransition(r,"done");let o=f(),i=this.createTaskHistoryEntry(n,o,e),a=this.getTaskHistoryFromState(r),u=[i,...a].slice(0,this.maxTaskHistory);return await this.update(t,p=>({...p,currentTask:null,previousTask:null,taskHistory:u,lastUpdated:o})),await this.publishEvent(t,"task.completed",{taskId:n.id,description:n.description,startedAt:n.startedAt,completedAt:o}),n}createTaskHistoryEntry(t,e,r){let n=(t.subtasks||[]).filter(a=>a.status==="completed"&&a.summary).map(a=>a.summary),o=n.length>0?n.map(a=>a.title).join(", "):"Task completed",i={taskId:t.id,title:t.parentDescription||t.description,classification:t.type||"improvement",startedAt:t.startedAt,completedAt:e,subtaskCount:t.subtasks?.length||0,subtaskSummaries:n,outcome:o,branchName:t.branch||"unknown",linearId:t.linearId,linearUuid:t.linearUuid,prUrl:t.prUrl};return r&&(i.feedback=r),t.tokensIn&&(i.tokensIn=t.tokensIn),t.tokensOut&&(i.tokensOut=t.tokensOut),i}maxPausedTasks=5;maxTaskHistory=20;stalenessThresholdDays=30;lifecycleBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this),validateTransition:this.validateTransition.bind(this),getPausedTasksFromState:this.getPausedTasksFromState.bind(this),maxPausedTasks:this.maxPausedTasks,stalenessThresholdDays:this.stalenessThresholdDays}}async pauseTask(t,e){return Cr(this.lifecycleBackend(),t,e)}async resumeTask(t,e){return Ir(this.lifecycleBackend(),t,e)}getPausedTasksFromState(t){return Array.isArray(t.pausedTasks)&&t.pausedTasks.length>0?t.pausedTasks:t.previousTask?[t.previousTask]:[]}getTaskHistoryFromState(t){return t.taskHistory||[]}async getStalePausedTasks(t){return Dr(this.lifecycleBackend(),t)}async archiveStalePausedTasks(t){return Lr(this.lifecycleBackend(),t)}queryBackend(){return{read:this.read.bind(this),update:this.update.bind(this),getPausedTasksFromState:this.getPausedTasksFromState.bind(this),getTaskHistoryFromState:this.getTaskHistoryFromState.bind(this)}}async clearTask(t){return Or(this.queryBackend(),t)}async hasTask(t){return Mr(this.queryBackend(),t)}async getPausedTask(t){return jr(this.queryBackend(),t)}async getAllPausedTasks(t){return Fr(this.queryBackend(),t)}async getTaskHistory(t){return ce(this.queryBackend(),t)}async getMostRecentTask(t){return Ur(this.queryBackend(),t)}async getTaskHistoryByType(t,e){return Xr(this.queryBackend(),t,e)}async getAggregatedFeedback(t){return Wr(this.queryBackend(),t)}workspaceBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this),createTaskHistoryEntry:this.createTaskHistoryEntry.bind(this),getTaskHistoryFromState:this.getTaskHistoryFromState.bind(this),maxTaskHistory:this.maxTaskHistory}}async startTaskInWorkspace(t,e,r){return ts(this.workspaceBackend(),t,e,r)}async getCurrentTaskForWorkspace(t,e){return es(this.workspaceBackend(),t,e)}async completeTaskInWorkspace(t,e,r){return rs(this.workspaceBackend(),t,e,r)}async getActiveTasks(t){return ss(this.workspaceBackend(),t)}async getActiveTaskCount(t){return ns(this.workspaceBackend(),t)}async updateWorkspaceTask(t,e,r){return os(this.workspaceBackend(),t,e,r)}async addTokens(t,e,r){return is(this.workspaceBackend(),t,e,r)}subtaskBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this)}}async createSubtasks(t,e){return $r(this.subtaskBackend(),t,e)}async completeSubtask(t,e){return Br(this.subtaskBackend(),t,e)}async getCurrentSubtask(t){return Hr(this.subtaskBackend(),t)}async getNextSubtask(t){return Gr(this.subtaskBackend(),t)}async getPreviousSubtask(t){return ue(this.subtaskBackend(),t)}async getPreviousHandoff(t){return qr(this.subtaskBackend(),t)}async getSubtasks(t){return Jr(this.subtaskBackend(),t)}async getSubtaskProgress(t){return Yr(this.subtaskBackend(),t)}async hasSubtasks(t){return zr(this.subtaskBackend(),t)}async areAllSubtasksComplete(t){return Kr(this.subtaskBackend(),t)}async failSubtask(t,e){return Vr(this.subtaskBackend(),t,e)}async skipSubtask(t,e){return Qr(this.subtaskBackend(),t,e)}async blockSubtask(t,e){return Zr(this.subtaskBackend(),t,e)}},V=new pe;X();q();import Wn from"node:fs/promises";import bt from"node:path";var cs={frontend:["component","page","view","ui","layout","style","css","scss","sass","hook","context","store","redux","zustand","react","vue","svelte","angular","next","nuxt","app","client"],backend:["api","route","controller","service","middleware","handler","resolver","schema","model","entity","repository","server","socket","graphql","rest","trpc"],database:["migration","seed","schema","model","entity","repository","prisma","drizzle","sequelize","typeorm","mongoose","knex","sql","db"],auth:["auth","login","logout","session","token","jwt","oauth","passport","credential","permission","role","user","account"],testing:["test","spec","e2e","integration","unit","mock","fixture","stub","jest","vitest","cypress","playwright"],config:["config","env","setting","constant","option","tsconfig","eslint","prettier","vite","webpack","rollup"],infra:["docker","compose","kubernetes","k8s","ci","cd","github","gitlab","jenkins","terraform","ansible","deploy"],util:["util","helper","lib","common","shared","core","base","abstract"]},us=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py",".go",".rs",".java",".kt",".swift",".rb",".php",".c",".cpp",".h",".hpp",".cs",".vue",".svelte"]),ls=new Set(["node_modules",".git","dist","build",".next",".nuxt",".output","coverage",".cache","__pycache__",".pytest_cache","vendor","target",".turbo",".vercel"]),ps=new Set(["a","an","the","and","or","but","is","are","was","were","be","been","being","have","has","had","do","does","did","will","would","could","should","may","might","must","shall","can","need","to","of","in","for","on","with","at","by","from","as","into","through","during","before","after","above","below","between","under","again","further","then","once","here","there","when","where","why","how","all","each","few","more","most","other","some","such","no","nor","not","only","own","same","so","than","too","very","just","add","create","make","implement","fix","update","change","modify","remove","delete","new"]);async function ds(s,t,e={}){let r=Date.now(),n=e.maxFiles??30,o=e.minScore??.1,i=e.includeTests??!1,a=$n(s),u=await Bn(t),p=await Hn(t),m=[];for(let g of u){if(!i&&qn(g))continue;let h=Gn(g,a,p,e.historicalBoosts);h.score>=o&&m.push(h)}m.sort((g,h)=>h.score-g.score);let d=m.slice(0,n);return{files:d,metrics:{filesScanned:u.length,filesReturned:d.length,scanDuration:Date.now()-r}}}c(ds,"findRelevantFiles");function $n(s){return s.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean).filter(e=>!ps.has(e)&&e.length>2)}c($n,"extractKeywords");async function Bn(s){let t=[];async function e(r,n=""){try{let o=await Wn.readdir(r,{withFileTypes:!0});for(let i of o){let a=bt.join(r,i.name),u=bt.join(n,i.name);if(i.isDirectory()){if(ls.has(i.name)||i.name.startsWith("."))continue;await e(a,u)}else if(i.isFile()){let p=bt.extname(i.name).toLowerCase();us.has(p)&&t.push(u)}}}catch(o){A(o)}}return c(e,"walk"),await e(s),t}c(Bn,"getAllCodeFiles");async function Hn(s){let t=new Map;try{let{stdout:e}=await E(`git log -30 --pretty=format:"%H %ct" --name-only | awk '
|
|
517
|
+
`)}]}})),t.tool("prjct_cochange","Files that historically change together (Jaccard similarity from git history)",{projectPath:C.string().describe("Project directory path"),seedFiles:C.array(C.string()).describe("Seed files to find co-change partners for"),rebuild:C.boolean().optional().default(!1).describe("Force rebuild the co-change matrix"),maxResults:C.number().optional().default(10).describe("Max results (default 10)")},E("prjct_cochange",async e=>{let s=await v(e.projectPath),n=e.rebuild?null:re(s);n||(n=await As(e.projectPath,s));let i=se(e.seedFiles,n).slice(0,e.maxResults);if(i.length===0)return{content:[{type:"text",text:"No co-change partners found."}]};let o=["## Co-Change Partners",`Seeds: ${e.seedFiles.join(", ")}`,`Commits analyzed: ${n.commitsAnalyzed}`,""];for(let a of i)o.push(`- ${a.path} (similarity: ${Math.round(a.score*100)}%)`);return{content:[{type:"text",text:o.join(`
|
|
518
|
+
`)}]}})),t.tool("prjct_related_context","Combined: import neighbors + co-change partners for seed files",{projectPath:C.string().describe("Project directory path"),seedFiles:C.array(C.string()).describe("Seed files to find related context for"),maxResults:C.number().optional().default(15).describe("Max results (default 15)")},E("prjct_related_context",async e=>{let s=await v(e.projectPath),n=ct(s),i=n?bs(e.seedFiles,n):[],o=re(s),a=o?se(e.seedFiles,o):[],u=new Map;for(let d of i)u.set(d.path,{importScore:d.score,cochangeScore:0});for(let d of a){let h=u.get(d.path);h?h.cochangeScore=d.score:u.set(d.path,{importScore:0,cochangeScore:d.score})}let p=Array.from(u.entries()).map(([d,h])=>({path:d,combined:h.importScore*.6+h.cochangeScore*.4,importScore:h.importScore,cochangeScore:h.cochangeScore})).sort((d,h)=>h.combined-d.combined).slice(0,e.maxResults);if(p.length===0)return{content:[{type:"text",text:"No related files found. Run `prjct sync` to build indexes."}]};let m=["## Related Context",`Seeds: ${e.seedFiles.join(", ")}`,""];for(let d of p){let h=[];d.importScore>0&&h.push(`import: ${d.importScore.toFixed(2)}`),d.cochangeScore>0&&h.push(`cochange: ${Math.round(d.cochangeScore*100)}%`),m.push(`- ${d.path} (${h.join(", ")})`)}return{content:[{type:"text",text:m.join(`
|
|
519
|
+
`)}]}}))}c(Ds,"registerCodeIntelTools");import{z}from"zod";qt();import{z as l}from"zod";var $n=l.enum(["low","medium","high","critical"]),xt=l.enum(["feature","bug","improvement","chore"]),Xn=l.enum(["active","backlog","previously_active"]),Wn=l.enum(["pending","in_progress","completed","blocked","paused","failed","skipped"]),le=l.object({title:l.string(),description:l.string(),filesChanged:l.array(l.object({path:l.string(),action:l.enum(["created","modified","deleted"])})),whatWasDone:l.array(l.string()).min(1),outputForNextAgent:l.string().min(1),notes:l.string().optional()}),js=l.object({output:l.string().min(1,"Subtask output is required"),summary:le}),Os=l.object({id:l.string(),description:l.string(),domain:l.string(),agent:l.string(),status:Wn,dependsOn:l.array(l.string()),startedAt:l.string().optional(),completedAt:l.string().optional(),output:l.string().optional(),summary:le.optional(),skipReason:l.string().optional(),blockReason:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional()}),Ms=l.object({completed:l.number(),total:l.number(),percentage:l.number()}),Fs=l.object({id:l.string(),description:l.string(),type:xt.optional(),startedAt:l.string(),sessionId:l.string(),featureId:l.string().optional(),subtasks:l.array(Os).optional(),currentSubtaskIndex:l.number().optional(),subtaskProgress:Ms.optional(),linearId:l.string().optional(),linearUuid:l.string().optional(),linkedSpecId:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional(),modelMetadata:Ht.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional(),parentDescription:l.string().optional(),branch:l.string().optional(),prUrl:l.string().optional()}),Ls=l.object({id:l.string(),description:l.string(),status:l.literal("paused"),startedAt:l.string(),pausedAt:l.string(),pauseReason:l.string().optional(),type:xt.optional(),sessionId:l.string().optional(),featureId:l.string().optional(),subtasks:l.array(Os).optional(),currentSubtaskIndex:l.number().optional(),subtaskProgress:Ms.optional(),linearId:l.string().optional(),linearUuid:l.string().optional(),estimatedPoints:l.number().optional(),estimatedMinutes:l.number().optional(),modelMetadata:Ht.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional()}),Bn=l.object({stackConfirmed:l.array(l.string()).optional(),patternsDiscovered:l.array(l.string()).optional(),agentAccuracy:l.array(l.object({agent:l.string(),rating:l.enum(["helpful","neutral","inaccurate"]),note:l.string().optional()})).optional(),issuesEncountered:l.array(l.string()).optional()}),Hn=l.object({taskId:l.string(),title:l.string(),classification:xt,startedAt:l.string(),completedAt:l.string(),subtaskCount:l.number(),subtaskSummaries:l.array(le),outcome:l.string(),branchName:l.string(),linearId:l.string().optional(),linearUuid:l.string().optional(),prUrl:l.string().optional(),feedback:Bn.optional(),tokensIn:l.number().optional(),tokensOut:l.number().optional()}),qn=Fs.extend({workspaceId:l.string(),worktreePath:l.string().optional(),agentSessionId:l.string().optional(),jiraId:l.string().optional(),jiraUuid:l.string().optional(),dispatchedFrom:l.string().optional()}),Us=l.object({currentTask:Fs.nullable(),previousTask:Ls.nullable().optional(),pausedTasks:l.array(Ls).optional(),taskHistory:l.array(Hn).optional(),activeTasks:l.array(qn).optional(),lastUpdated:l.string()}),Gn=l.object({id:l.string(),description:l.string(),body:l.string().optional(),priority:$n,type:xt,featureId:l.string().optional(),originFeature:l.string().optional(),completed:l.boolean(),completedAt:l.string().optional(),createdAt:l.string(),section:Xn,agent:l.string().optional(),groupName:l.string().optional(),groupId:l.string().optional()}),$s=l.object({tasks:l.array(Gn),lastUpdated:l.string()});var lt={idle:{transitions:["task"],prompt:"prjct task <description> Start working",description:"No active task"},working:{transitions:["done","pause"],prompt:"prjct status done Complete task | prjct status paused Switch context",description:"Task in progress"},paused:{transitions:["resume","task","ship"],prompt:"prjct status active Continue | prjct task <new> Start different | prjct ship Ship directly",description:"Task paused"},completed:{transitions:["ship","task","pause","reopen"],prompt:"prjct ship Ship it | prjct task <next> Start next | prjct status active Reopen",description:"Task completed"},shipped:{transitions:["task"],prompt:"prjct task <description> Start new task",description:"Feature shipped"}},pe=class{static{c(this,"WorkflowStateMachine")}getCurrentState(t,e){let s=null;if(e&&t?.activeTasks?.length&&(s=t.activeTasks.find(i=>i.workspaceId===e)),s||(s=t?.currentTask),!s)return(t?.pausedTasks?.length||0)>0||t?.previousTask?.status==="paused"?"paused":"idle";switch((typeof s.status=="string"?s.status:"").toLowerCase()){case"in_progress":case"working":return"working";case"paused":return"paused";case"completed":case"done":return"completed";case"shipped":return"shipped";default:return s?"working":"idle"}}canTransition(t,e){if(lt[t].transitions.includes(e))return{valid:!0};let n=this.formatNextSteps(t).join(" | ");return{valid:!1,error:`Cannot transition to '${e}' from '${t}' state`,suggestion:`Valid next steps: ${n}`}}getNextState(t,e){switch(e){case"task":return"working";case"done":return"completed";case"pause":return"paused";case"resume":return"working";case"ship":return"shipped";case"reopen":return"working";default:return t}}getStateInfo(t){return lt[t]}getPrompt(t){return lt[t].prompt}getValidCommands(t){return lt[t].transitions}formatNextSteps(t){return lt[t].transitions.map(s=>{switch(s){case"task":return"prjct task <desc> Start new task";case"done":return"prjct status done Complete current task";case"pause":return"prjct status paused Pause and switch context";case"resume":return"prjct status active Continue paused task";case"ship":return"prjct ship Ship the feature";case"reopen":return"prjct status active Reopen completed task";default:return`prjct ${s}`}})}},de=new pe;import Jn from"node:crypto";function F(){return Jn.randomUUID()}c(F,"generateUUID");var pt={SHIPPED_RETENTION_DAYS:90,IDEA_DORMANT_DAYS:180,QUEUE_COMPLETED_DAYS:7,PAUSED_TASK_DAYS:30,MEMORY_MAX_ENTRIES:500},me=class{static{c(this,"ArchiveStorage")}archive(t,e){let s=F(),n=g();return k.run(t,"INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)",s,e.entityType,e.entityId,JSON.stringify(e.entityData),e.summary??null,n,e.reason),s}archiveMany(t,e){if(e.length===0)return 0;let s=g();return k.transaction(t,n=>{let i=n.prepare("INSERT INTO archives (id, entity_type, entity_id, entity_data, summary, archived_at, reason) VALUES (?, ?, ?, ?, ?, ?, ?)");for(let o of e)i.run(F(),o.entityType,o.entityId,JSON.stringify(o.entityData),o.summary??null,s,o.reason)}),e.length}getArchived(t,e,s=50){return e?k.query(t,"SELECT * FROM archives WHERE entity_type = ? ORDER BY archived_at DESC LIMIT ?",e,s):k.query(t,"SELECT * FROM archives ORDER BY archived_at DESC LIMIT ?",s)}getStats(t){let e=k.query(t,"SELECT entity_type, COUNT(*) as count FROM archives GROUP BY entity_type"),s={shipped:0,idea:0,queue_task:0,paused_task:0,memory_entry:0,total:0};for(let n of e){let i=n.entity_type;i in s&&(s[i]=n.count),s.total+=n.count}return s}restore(t,e){let s=k.get(t,"SELECT * FROM archives WHERE id = ?",e);return s?(k.run(t,"DELETE FROM archives WHERE id = ?",e),JSON.parse(s.entity_data)):null}pruneOldArchives(t,e){let s=new Date(Date.now()-e*24*60*60*1e3).toISOString(),n=this.getTotalCount(t);k.run(t,"DELETE FROM archives WHERE archived_at < ?",s);let i=this.getTotalCount(t);return n-i}getTotalCount(t){return k.get(t,"SELECT COUNT(*) as count FROM archives")?.count??0}},tt=new me;async function Xs(r,t,e){let s=await r.read(t);if(!s.currentTask)return null;r.validateTransition(s,"pause");let n={...s.currentTask,status:"paused",pausedAt:g(),pauseReason:e},i=r.getPausedTasksFromState(s),o=[n,...i].slice(0,r.maxPausedTasks);return await r.update(t,a=>({...a,currentTask:null,previousTask:null,pausedTasks:o,lastUpdated:g()})),await r.publish(t,"task.paused",{taskId:n.id,description:n.description,pausedAt:n.pausedAt,reason:e,pausedCount:o.length}),n}c(Xs,"pauseTask");async function Ws(r,t,e){let s=await r.read(t),n=r.getPausedTasksFromState(s);if(n.length===0)return null;r.validateTransition(s,"resume");let i=0;if(e&&(i=n.findIndex(y=>y.id===e),i===-1))return null;let o=n[i],a=n.filter((y,D)=>D!==i),{status:u,pausedAt:p,pauseReason:m,...d}=o,h={...d,startedAt:g(),sessionId:o.sessionId??F()};return await r.update(t,y=>({...y,currentTask:h,previousTask:null,pausedTasks:a,lastUpdated:g()})),await r.publish(t,"task.resumed",{taskId:h.id,description:h.description,resumedAt:h.startedAt,remainingPaused:a.length}),h}c(Ws,"resumeTask");async function Bs(r,t){let e=await r.read(t),s=r.getPausedTasksFromState(e),n=Date.now()-r.stalenessThresholdDays*24*60*60*1e3;return s.filter(i=>new Date(i.pausedAt).getTime()<n)}c(Bs,"getStalePausedTasks");async function Hs(r,t){let e=await r.read(t),s=r.getPausedTasksFromState(e),n=Date.now()-r.stalenessThresholdDays*24*60*60*1e3,i=s.filter(a=>new Date(a.pausedAt).getTime()<n),o=s.filter(a=>new Date(a.pausedAt).getTime()>=n);if(i.length===0)return[];tt.archiveMany(t,i.map(a=>({entityType:"paused_task",entityId:a.id,entityData:a,summary:a.description,reason:"staleness"}))),await r.update(t,a=>({...a,pausedTasks:o,previousTask:null,lastUpdated:g()}));for(let a of i)await r.publish(t,"task.archived",{taskId:a.id,description:a.description,pausedAt:a.pausedAt,reason:"staleness"});return i}c(Hs,"archiveStalePausedTasks");async function qs(r,t){await r.update(t,()=>({currentTask:null,previousTask:null,pausedTasks:[],activeTasks:[],lastUpdated:g()}))}c(qs,"clearTask");async function Gs(r,t){let e=await r.read(t),s=r.getPausedTasksFromState(e);return e.currentTask!==null||s.length>0}c(Gs,"hasTask");async function Js(r,t){let e=await r.read(t);return r.getPausedTasksFromState(e)[0]||null}c(Js,"getPausedTask");async function Ys(r,t){let e=await r.read(t);return r.getPausedTasksFromState(e)}c(Ys,"getAllPausedTasks");async function ge(r,t){let e=await r.read(t);return r.getTaskHistoryFromState(e)}c(ge,"getTaskHistory");async function zs(r,t){let e=await r.read(t);return r.getTaskHistoryFromState(e)[0]||null}c(zs,"getMostRecentTask");async function Ks(r,t,e){let s=await r.read(t);return r.getTaskHistoryFromState(s).filter(i=>i.classification===e)}c(Ks,"getTaskHistoryByType");async function Vs(r,t){let s=(await ge(r,t)).filter(h=>h.feedback),n=[],i=[],o=[],a=[];for(let h of s){let y=h.feedback;Array.isArray(y.stackConfirmed)&&n.push(...y.stackConfirmed),Array.isArray(y.patternsDiscovered)&&i.push(...y.patternsDiscovered),Array.isArray(y.agentAccuracy)&&o.push(...y.agentAccuracy),Array.isArray(y.issuesEncountered)&&a.push(...y.issuesEncountered)}let u=[...new Set(n)],p=[...new Set(i)],m=new Map;for(let h of a)m.set(h,(m.get(h)||0)+1);let d=[...m.entries()].filter(([h,y])=>y>=2).map(([h])=>h);return{stackConfirmed:u,patternsDiscovered:p,agentAccuracy:o,issuesEncountered:[...new Set(a)],knownGotchas:d}}c(Vs,"getAggregatedFeedback");async function Qs(r,t,e){let s=await r.read(t);if(!s.currentTask)return;let n=e.map((i,o)=>({...i,status:o===0?"in_progress":"pending",startedAt:o===0?g():void 0,dependsOn:i.dependsOn||[]}));await r.update(t,i=>({...i,currentTask:{...i.currentTask,subtasks:n,currentSubtaskIndex:0,subtaskProgress:{completed:0,total:n.length,percentage:0}},lastUpdated:g()})),await r.publish(t,"subtasks.created",{taskId:s.currentTask.id,subtaskCount:n.length,subtasks:n.map(i=>({id:i.id,description:i.description,domain:i.domain}))})}c(Qs,"createSubtasks");async function Zs(r,t,e){let s=js.safeParse(e);if(!s.success){let D=s.error.issues.map(mt=>`${mt.path.join(".")}: ${mt.message}`);throw new Error(`Subtask completion requires handoff data:
|
|
520
|
+
${D.join(`
|
|
521
|
+
`)}`)}let{output:n,summary:i}=s.data,o=await r.read(t);if(!o.currentTask?.subtasks)return null;let a=o.currentTask.currentSubtaskIndex||0,u=o.currentTask.subtasks[a];if(!u)return null;let p=[...o.currentTask.subtasks];p[a]={...u,status:"completed",completedAt:g(),output:n,summary:i};let m=p.filter(D=>D.status==="completed").length,d=p.length,h=Math.round(m/d*100),y=a+1;return y<p.length&&(p[y]={...p[y],status:"in_progress",startedAt:g()}),await r.update(t,D=>({...D,currentTask:{...D.currentTask,subtasks:p,currentSubtaskIndex:y<d?y:a,subtaskProgress:{completed:m,total:d,percentage:h}},lastUpdated:g()})),await r.publish(t,"subtask.completed",{taskId:o.currentTask.id,subtaskId:u.id,description:u.description,output:n,handoff:i.outputForNextAgent,filesChanged:i.filesChanged.length,progress:{completed:m,total:d,percentage:h}}),y<d?p[y]:null}c(Zs,"completeSubtask");async function tr(r,t){let e=await r.read(t);if(!e.currentTask?.subtasks)return null;let s=e.currentTask.currentSubtaskIndex||0;return e.currentTask.subtasks[s]||null}c(tr,"getCurrentSubtask");async function er(r,t){let e=await r.read(t);if(!e.currentTask?.subtasks)return null;let s=(e.currentTask.currentSubtaskIndex||0)+1;return e.currentTask.subtasks[s]||null}c(er,"getNextSubtask");async function fe(r,t){let e=await r.read(t);if(!e.currentTask?.subtasks)return null;let s=(e.currentTask.currentSubtaskIndex||0)-1;return s<0?null:e.currentTask.subtasks[s]||null}c(fe,"getPreviousSubtask");async function sr(r,t){let e=await fe(r,t);return e?.summary?.outputForNextAgent?{fromSubtask:e.description,outputForNextAgent:e.summary.outputForNextAgent,filesChanged:e.summary.filesChanged,whatWasDone:e.summary.whatWasDone}:null}c(sr,"getPreviousHandoff");async function rr(r,t){return(await r.read(t)).currentTask?.subtasks||[]}c(rr,"getSubtasks");async function nr(r,t){return(await r.read(t)).currentTask?.subtaskProgress||null}c(nr,"getSubtaskProgress");async function ir(r,t){return((await r.read(t)).currentTask?.subtasks?.length||0)>0}c(ir,"hasSubtasks");async function or(r,t){let e=await r.read(t);return e.currentTask?.subtasks?e.currentTask.subtasks.every(s=>s.status==="completed"||s.status==="failed"||s.status==="skipped"):!0}c(or,"areAllSubtasksComplete");async function ar(r,t,e){let s=await r.read(t);if(!s.currentTask?.subtasks)return null;let n=s.currentTask.currentSubtaskIndex||0,i=s.currentTask.subtasks[n];if(!i)return null;let o=[...s.currentTask.subtasks];o[n]={...i,status:"failed",completedAt:g(),output:`Failed: ${e}`};let a=n+1,u=o.length;a<u&&(o[a]={...o[a],status:"in_progress",startedAt:g()});let p=o.filter(d=>d.status==="completed"||d.status==="failed"||d.status==="skipped").length,m=Math.round(p/u*100);return await r.update(t,d=>({...d,currentTask:{...d.currentTask,subtasks:o,currentSubtaskIndex:a<u?a:n,subtaskProgress:{completed:p,total:u,percentage:m}},lastUpdated:g()})),await r.publish(t,"subtask.failed",{taskId:s.currentTask.id,subtaskId:i.id,description:i.description,error:e}),a<u?o[a]:null}c(ar,"failSubtask");async function cr(r,t,e){let s=await r.read(t);if(!s.currentTask?.subtasks)return null;let n=s.currentTask.currentSubtaskIndex||0,i=s.currentTask.subtasks[n];if(!i)return null;let o=[...s.currentTask.subtasks];o[n]={...i,status:"skipped",completedAt:g(),output:`Skipped: ${e}`,skipReason:e};let a=n+1,u=o.length;a<u&&(o[a]={...o[a],status:"in_progress",startedAt:g()});let p=o.filter(d=>d.status==="completed"||d.status==="failed"||d.status==="skipped").length,m=Math.round(p/u*100);return await r.update(t,d=>({...d,currentTask:{...d.currentTask,subtasks:o,currentSubtaskIndex:a<u?a:n,subtaskProgress:{completed:p,total:u,percentage:m}},lastUpdated:g()})),await r.publish(t,"subtask.skipped",{taskId:s.currentTask.id,subtaskId:i.id,description:i.description,reason:e}),a<u?o[a]:null}c(cr,"skipSubtask");async function ur(r,t,e){let s=await r.read(t);if(!s.currentTask?.subtasks)return null;let n=s.currentTask.currentSubtaskIndex||0,i=s.currentTask.subtasks[n];if(!i)return null;let o=[...s.currentTask.subtasks];o[n]={...i,status:"blocked",output:`Blocked: ${e}`,blockReason:e};let a=n+1,u=o.length;return a<u&&(o[a]={...o[a],status:"in_progress",startedAt:g()}),await r.update(t,p=>({...p,currentTask:{...p.currentTask,subtasks:o,currentSubtaskIndex:a<u?a:n},lastUpdated:g()})),await r.publish(t,"subtask.blocked",{taskId:s.currentTask.id,subtaskId:i.id,description:i.description,blocker:e}),a<u?o[a]:null}c(ur,"blockSubtask");async function lr(r,t,e,s){let n={...e,workspaceId:s,startedAt:g()};return await r.update(t,i=>({...i,activeTasks:[...i.activeTasks||[],n],lastUpdated:g()})),await r.publish(t,"task.started",{taskId:n.id,description:n.description,startedAt:n.startedAt,sessionId:n.sessionId,workspaceId:s}),n}c(lr,"startTaskInWorkspace");async function pr(r,t,e){return((await r.read(t)).activeTasks||[]).find(n=>n.workspaceId===e)??null}c(pr,"getCurrentTaskForWorkspace");async function dr(r,t,e,s){let n=await r.read(t),o=(n.activeTasks||[]).find(d=>d.workspaceId===e);if(!o)return null;let a=g(),u=r.createTaskHistoryEntry(o,a,s),p=r.getTaskHistoryFromState(n),m=[u,...p].slice(0,r.maxTaskHistory);return await r.update(t,d=>({...d,activeTasks:(d.activeTasks||[]).filter(h=>h.workspaceId!==e),taskHistory:m,lastUpdated:a})),await r.publish(t,"task.completed",{taskId:o.id,description:o.description,startedAt:o.startedAt,completedAt:a,workspaceId:e}),o}c(dr,"completeTaskInWorkspace");async function mr(r,t){return(await r.read(t)).activeTasks||[]}c(mr,"getActiveTasks");async function gr(r,t){return((await r.read(t)).activeTasks||[]).length}c(gr,"getActiveTaskCount");async function fr(r,t,e,s){let i=(await r.read(t)).activeTasks||[],o=i.findIndex(u=>u.workspaceId===e);if(o===-1)return null;let a={...i[o],...s,workspaceId:e};return await r.update(t,u=>{let p=[...u.activeTasks||[]];return p[o]=a,{...u,activeTasks:p,lastUpdated:g()}}),a}c(fr,"updateWorkspaceTask");async function hr(r,t,e,s){let n=await r.read(t);if(!n.currentTask)return null;let i=(n.currentTask.tokensIn||0)+e,o=(n.currentTask.tokensOut||0)+s;return await r.update(t,a=>({...a,currentTask:{...a.currentTask,tokensIn:i,tokensOut:o},lastUpdated:g()})),{tokensIn:i,tokensOut:o}}c(hr,"addTokens");X();var he=class{static{c(this,"SyncEventBus")}async publish(t){let e=_.getSyncPendingPath(t.projectId),s=await ft(e,[])??[],n=Array.isArray(s)?s:[];n.push(t),await $(e,n)}async getPending(t){let e=_.getSyncPendingPath(t),s=await ft(e,[])??[];return Array.isArray(s)?s:[]}async clearPending(t){let e=_.getSyncPendingPath(t);await $(e,[])}async updateLastSync(t){let e=_.getLastSyncPath(t),s={timestamp:g(),success:!0};await $(e,s)}async getLastSync(t){let e=_.getLastSyncPath(t);return await ft(e,null)}},yr=new he;Gt();var et=class{static{c(this,"StorageManager")}filename;cache;constructor(t,e){this.filename=t,this.cache=new ht({ttl:5e3,maxSize:50})}getStoreKey(){return this.filename.replace(".json","")}async read(t){let e=this.cache.get(t);if(e!==null)return e;try{let s=k.getDoc(t,this.getStoreKey());if(s!==null)return this.cache.set(t,s),s}catch{}return this.getDefault()}async write(t,e){k.setDoc(t,this.getStoreKey(),e),this.cache.set(t,e)}async update(t,e){let s=await this.read(t),n=e(s);return await this.write(t,n),n}async publishEvent(t,e,s){let n={type:e,path:[this.filename.replace(".json","")],data:s,timestamp:g(),projectId:t};await yr.publish(n)}async publishEntityEvent(t,e,s,n){let i=`${e}.${s}`,o={...n,timestamp:g()};await this.publishEvent(t,i,o)}async exists(t){try{return k.hasDoc(t,this.getStoreKey())}catch{return!1}}clearCache(t){t?this.cache.delete(t):this.cache.clear()}getCacheStats(){return this.cache.stats()}};var ye=class extends et{static{c(this,"StateStorage")}constructor(){super("state.json",Us)}getDefault(){return{currentTask:null,previousTask:null,pausedTasks:[],taskHistory:[],activeTasks:[],lastUpdated:""}}getEventType(t){return`state.${t}d`}validateTransition(t,e){let s=de.getCurrentState(t),n=de.canTransition(s,e);if(!n.valid)throw new Error(`${n.error}. ${n.suggestion||""}`.trim())}async getCurrentTask(t){return(await this.read(t)).currentTask}async getPausedTasks(t){let e=await this.read(t);return this.getPausedTasksFromState(e)}async startTask(t,e){let s=await this.read(t);this.validateTransition(s,"task");let n={...e,startedAt:g()};return await this.update(t,i=>({...i,currentTask:n,lastUpdated:g()})),await this.publishEvent(t,"task.started",{taskId:n.id,description:n.description,startedAt:n.startedAt,sessionId:n.sessionId}),n}async updateCurrentTask(t,e){let s=await this.read(t);if(!s.currentTask)return null;let n={...s.currentTask,...e};return await this.update(t,i=>({...i,currentTask:n,lastUpdated:g()})),n}async completeTask(t,e){let s=await this.read(t),n=s.currentTask;if(!n)return null;this.validateTransition(s,"done");let i=g(),o=this.createTaskHistoryEntry(n,i,e),a=this.getTaskHistoryFromState(s),u=[o,...a].slice(0,this.maxTaskHistory);return await this.update(t,p=>({...p,currentTask:null,previousTask:null,taskHistory:u,lastUpdated:i})),await this.publishEvent(t,"task.completed",{taskId:n.id,description:n.description,startedAt:n.startedAt,completedAt:i}),n}createTaskHistoryEntry(t,e,s){let n=(t.subtasks||[]).filter(a=>a.status==="completed"&&a.summary).map(a=>a.summary),i=n.length>0?n.map(a=>a.title).join(", "):"Task completed",o={taskId:t.id,title:t.parentDescription||t.description,classification:t.type||"improvement",startedAt:t.startedAt,completedAt:e,subtaskCount:t.subtasks?.length||0,subtaskSummaries:n,outcome:i,branchName:t.branch||"unknown",linearId:t.linearId,linearUuid:t.linearUuid,prUrl:t.prUrl};return s&&(o.feedback=s),t.tokensIn&&(o.tokensIn=t.tokensIn),t.tokensOut&&(o.tokensOut=t.tokensOut),o}maxPausedTasks=5;maxTaskHistory=20;stalenessThresholdDays=30;lifecycleBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this),validateTransition:this.validateTransition.bind(this),getPausedTasksFromState:this.getPausedTasksFromState.bind(this),maxPausedTasks:this.maxPausedTasks,stalenessThresholdDays:this.stalenessThresholdDays}}async pauseTask(t,e){return Xs(this.lifecycleBackend(),t,e)}async resumeTask(t,e){return Ws(this.lifecycleBackend(),t,e)}getPausedTasksFromState(t){return Array.isArray(t.pausedTasks)&&t.pausedTasks.length>0?t.pausedTasks:t.previousTask?[t.previousTask]:[]}getTaskHistoryFromState(t){return t.taskHistory||[]}async getStalePausedTasks(t){return Bs(this.lifecycleBackend(),t)}async archiveStalePausedTasks(t){return Hs(this.lifecycleBackend(),t)}queryBackend(){return{read:this.read.bind(this),update:this.update.bind(this),getPausedTasksFromState:this.getPausedTasksFromState.bind(this),getTaskHistoryFromState:this.getTaskHistoryFromState.bind(this)}}async clearTask(t){return qs(this.queryBackend(),t)}async hasTask(t){return Gs(this.queryBackend(),t)}async getPausedTask(t){return Js(this.queryBackend(),t)}async getAllPausedTasks(t){return Ys(this.queryBackend(),t)}async getTaskHistory(t){return ge(this.queryBackend(),t)}async getMostRecentTask(t){return zs(this.queryBackend(),t)}async getTaskHistoryByType(t,e){return Ks(this.queryBackend(),t,e)}async getAggregatedFeedback(t){return Vs(this.queryBackend(),t)}workspaceBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this),createTaskHistoryEntry:this.createTaskHistoryEntry.bind(this),getTaskHistoryFromState:this.getTaskHistoryFromState.bind(this),maxTaskHistory:this.maxTaskHistory}}async startTaskInWorkspace(t,e,s){return lr(this.workspaceBackend(),t,e,s)}async getCurrentTaskForWorkspace(t,e){return pr(this.workspaceBackend(),t,e)}async completeTaskInWorkspace(t,e,s){return dr(this.workspaceBackend(),t,e,s)}async getActiveTasks(t){return mr(this.workspaceBackend(),t)}async getActiveTaskCount(t){return gr(this.workspaceBackend(),t)}async updateWorkspaceTask(t,e,s){return fr(this.workspaceBackend(),t,e,s)}async addTokens(t,e,s){return hr(this.workspaceBackend(),t,e,s)}subtaskBackend(){return{read:this.read.bind(this),update:this.update.bind(this),publish:this.publishEvent.bind(this)}}async createSubtasks(t,e){return Qs(this.subtaskBackend(),t,e)}async completeSubtask(t,e){return Zs(this.subtaskBackend(),t,e)}async getCurrentSubtask(t){return tr(this.subtaskBackend(),t)}async getNextSubtask(t){return er(this.subtaskBackend(),t)}async getPreviousSubtask(t){return fe(this.subtaskBackend(),t)}async getPreviousHandoff(t){return sr(this.subtaskBackend(),t)}async getSubtasks(t){return rr(this.subtaskBackend(),t)}async getSubtaskProgress(t){return nr(this.subtaskBackend(),t)}async hasSubtasks(t){return ir(this.subtaskBackend(),t)}async areAllSubtasksComplete(t){return or(this.subtaskBackend(),t)}async failSubtask(t,e){return ar(this.subtaskBackend(),t,e)}async skipSubtask(t,e){return cr(this.subtaskBackend(),t,e)}async blockSubtask(t,e){return ur(this.subtaskBackend(),t,e)}},st=new ye;J();V();import Qn from"node:fs/promises";import Pt from"node:path";var Tr={frontend:["component","page","view","ui","layout","style","css","scss","sass","hook","context","store","redux","zustand","react","vue","svelte","angular","next","nuxt","app","client"],backend:["api","route","controller","service","middleware","handler","resolver","schema","model","entity","repository","server","socket","graphql","rest","trpc"],database:["migration","seed","schema","model","entity","repository","prisma","drizzle","sequelize","typeorm","mongoose","knex","sql","db"],auth:["auth","login","logout","session","token","jwt","oauth","passport","credential","permission","role","user","account"],testing:["test","spec","e2e","integration","unit","mock","fixture","stub","jest","vitest","cypress","playwright"],config:["config","env","setting","constant","option","tsconfig","eslint","prettier","vite","webpack","rollup"],infra:["docker","compose","kubernetes","k8s","ci","cd","github","gitlab","jenkins","terraform","ansible","deploy"],util:["util","helper","lib","common","shared","core","base","abstract"]},kr=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".py",".go",".rs",".java",".kt",".swift",".rb",".php",".c",".cpp",".h",".hpp",".cs",".vue",".svelte"]),Er=new Set(["node_modules",".git","dist","build",".next",".nuxt",".output","coverage",".cache","__pycache__",".pytest_cache","vendor","target",".turbo",".vercel"]),Sr=new Set(["a","an","the","and","or","but","is","are","was","were","be","been","being","have","has","had","do","does","did","will","would","could","should","may","might","must","shall","can","need","to","of","in","for","on","with","at","by","from","as","into","through","during","before","after","above","below","between","under","again","further","then","once","here","there","when","where","why","how","all","each","few","more","most","other","some","such","no","nor","not","only","own","same","so","than","too","very","just","add","create","make","implement","fix","update","change","modify","remove","delete","new"]);async function wr(r,t,e={}){let s=Date.now(),n=e.maxFiles??30,i=e.minScore??.1,o=e.includeTests??!1,a=Zn(r),u=await ti(t),p=await ei(t),m=[];for(let h of u){if(!o&&ri(h))continue;let y=si(h,a,p,e.historicalBoosts);y.score>=i&&m.push(y)}m.sort((h,y)=>y.score-h.score);let d=m.slice(0,n);return{files:d,metrics:{filesScanned:u.length,filesReturned:d.length,scanDuration:Date.now()-s}}}c(wr,"findRelevantFiles");function Zn(r){return r.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean).filter(e=>!Sr.has(e)&&e.length>2)}c(Zn,"extractKeywords");async function ti(r){let t=[];async function e(s,n=""){try{let i=await Qn.readdir(s,{withFileTypes:!0});for(let o of i){let a=Pt.join(s,o.name),u=Pt.join(n,o.name);if(o.isDirectory()){if(Er.has(o.name)||o.name.startsWith("."))continue;await e(a,u)}else if(o.isFile()){let p=Pt.extname(o.name).toLowerCase();kr.has(p)&&t.push(u)}}}catch(i){N(i)}}return c(e,"walk"),await e(r),t}c(ti,"getAllCodeFiles");async function ei(r){let t=new Map;try{let{stdout:e}=await w(`git log -30 --pretty=format:"%H %ct" --name-only | awk '
|
|
506
522
|
/^[a-f0-9]{40}/ { commit=$1; timestamp=$2; next }
|
|
507
523
|
NF { files[$0]++; if (!lastmod[$0]) lastmod[$0]=timestamp }
|
|
508
524
|
END { for (f in files) print files[f], lastmod[f], f }
|
|
509
|
-
'`,{cwd:
|
|
510
|
-
`).filter(Boolean);for(let
|
|
511
|
-
`);return{file:
|
|
512
|
-
`),n=new Set;for(let
|
|
513
|
-
`).length,d=
|
|
525
|
+
'`,{cwd:r,maxBuffer:10485760}),s=Math.floor(Date.now()/1e3),n=e.trim().split(`
|
|
526
|
+
`).filter(Boolean);for(let i of n){let o=i.match(/^(\d+)\s+(\d+)\s+(.+)$/);if(o){let a=parseInt(o[1],10),u=parseInt(o[2],10),p=o[3],m=Math.floor((s-u)/86400);t.set(p,{commits:a,daysAgo:m})}}}catch{}return t}c(ei,"getGitRecency");function si(r,t,e,s){let n=[],i=0,o=0,a=0,u=0,p=0,m=r.toLowerCase(),d=m.split("/").join(" ").split(/[^a-z0-9]+/);for(let R of t){m.includes(R)&&(i+=.3,n.push(`keyword:${R}`));for(let it of d)if(it.includes(R)||R.includes(it)){i+=.15;break}}i=Math.min(1,i);for(let[R,it]of Object.entries(Tr))for(let Gr of it)if(m.includes(Gr)&&t.some(Nt=>it.includes(Nt)||Nt.includes(R)||R.includes(Nt))){o+=.4,n.push(`domain:${R}`);break}o=Math.min(1,o);let h=e.get(r);h&&(h.daysAgo<=1?(a=1,n.push("recent:1d")):h.daysAgo<=3?(a=.8,n.push("recent:3d")):h.daysAgo<=7?(a=.6,n.push("recent:1w")):h.daysAgo<=30&&(a=.3,n.push("recent:1m")),h.commits>=5&&(a=Math.min(1,a+.2)));let y=Pt.basename(r).toLowerCase();if((y.includes("index")||y.includes("main")||y.includes("app")||y.includes("entry"))&&(u=.5,n.push("import:0")),(m.includes("/core/")||m.includes("/shared/")||m.includes("/lib/"))&&(u=Math.max(u,.3),n.some(R=>R.startsWith("import:"))||n.push("import:1")),s){let R=s.get(r);R!==void 0&&(p=(R+1)/2,R>0?n.push("history:boosted"):R<0&&n.push("history:penalized"))}let mt=s&&s.size>0?i*.54+o*.18+a*.13+u*.05+p*.1:i*.6+o*.2+a*.15+u*.05;return{path:r,score:Math.min(1,mt),reasons:[...new Set(n)]}}c(si,"scoreFile");function ri(r){let t=r.toLowerCase();return t.includes(".test.")||t.includes(".spec.")||t.includes("__tests__")||t.includes("__mocks__")||t.includes("/tests/")||t.includes("/test/")||t.endsWith("_test.go")||t.endsWith("_test.py")}c(ri,"isTestFile");J();import ci from"node:fs/promises";import rt from"node:path";var ii={"claude-opus-4.5":{input:.005,output:.025},"claude-sonnet-4.5":{input:.003,output:.015},"claude-haiku-4.5":{input:.001,output:.005},"claude-opus-4":{input:.015,output:.075},"claude-opus-4-6":{input:.015,output:.075},"gpt-4o":{input:.0025,output:.01},"gpt-4-turbo":{input:.01,output:.03},"gpt-4o-mini":{input:15e-5,output:6e-4},"gemini-1.5-pro":{input:.00125,output:.005},"gemini-1.5-flash":{input:75e-6,output:3e-4}},oi="claude-sonnet-4.5";function Te(r){return!r||r.length===0?0:Math.ceil(r.length/4)}c(Te,"countTokens");var _r=["claude-sonnet-4.5","claude-opus-4.5","claude-opus-4-6","gpt-4o","gemini-1.5-pro"];function br(r,t){let e=ii[t],s=r/1e3*e.input,n=r/1e3*e.output*.3;return{inputSaved:s,outputPotential:n,total:s+n}}c(br,"calculateModelCost");function ai(r){return r<.001?"<$0.01":r<.01?`$${r.toFixed(3)}`:`$${r.toFixed(2)}`}c(ai,"formatCostSaved");function vr(r,t){let e=Te(r),s=Te(t),n=Math.max(0,e-s),i=e>0?(e-s)/e:0,o=br(n,oi),a=_r.map(u=>({model:u,...br(n,u)}));return{tokens:{original:e,filtered:s,saved:n},compression:Math.max(0,Math.min(1,i)),cost:{saved:o.total,formatted:ai(o.total),byModel:a}}}c(vr,"measureCompression");function Rt(r){let t=Te(r);return{tokens:{original:t,filtered:t,saved:0},compression:0,cost:{saved:0,formatted:"$0.00",byModel:_r.map(e=>({model:e,inputSaved:0,outputPotential:0,total:0}))}}}c(Rt,"noCompression");var ui={".ts":"typescript",".tsx":"typescript",".js":"javascript",".jsx":"javascript",".mjs":"javascript",".cjs":"javascript",".py":"python",".go":"go",".rs":"rust",".java":"java",".cs":"csharp",".php":"php",".rb":"ruby"},xr=[{type:"function",pattern:/^export\s+(?:async\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)\s*(?::\s*([^{;]+))?/gm,nameIndex:1,exported:!0},{type:"function",pattern:/^export\s+const\s+(\w+)\s*(?::\s*[^=]+)?\s*=\s*(?:async\s+)?\([^)]*\)\s*(?::\s*[^=]+)?\s*=>/gm,nameIndex:1,exported:!0},{type:"function",pattern:/^(?:async\s+)?function\s+(\w+)\s*(<[^>]*>)?\s*\(([^)]*)\)\s*(?::\s*([^{;]+))?/gm,nameIndex:1},{type:"function",pattern:/^const\s+(\w+)\s*(?::\s*[^=]+)?\s*=\s*(?:async\s+)?\([^)]*\)\s*(?::\s*[^=]+)?\s*=>/gm,nameIndex:1},{type:"interface",pattern:/^export\s+interface\s+(\w+)(?:<[^>]+>)?\s*(?:extends\s+[^{]+)?\s*\{/gm,nameIndex:1,exported:!0},{type:"interface",pattern:/^interface\s+(\w+)(?:<[^>]+>)?\s*(?:extends\s+[^{]+)?\s*\{/gm,nameIndex:1},{type:"type",pattern:/^export\s+type\s+(\w+)(?:<[^>]+>)?\s*=/gm,nameIndex:1,exported:!0},{type:"type",pattern:/^type\s+(\w+)(?:<[^>]+>)?\s*=/gm,nameIndex:1},{type:"class",pattern:/^export\s+(?:abstract\s+)?class\s+(\w+)(?:<[^>]+>)?(?:\s+extends\s+[^{]+)?(?:\s+implements\s+[^{]+)?\s*\{/gm,nameIndex:1,exported:!0},{type:"class",pattern:/^(?:abstract\s+)?class\s+(\w+)(?:<[^>]+>)?(?:\s+extends\s+[^{]+)?(?:\s+implements\s+[^{]+)?\s*\{/gm,nameIndex:1},{type:"enum",pattern:/^export\s+enum\s+(\w+)\s*\{/gm,nameIndex:1,exported:!0},{type:"enum",pattern:/^enum\s+(\w+)\s*\{/gm,nameIndex:1},{type:"const",pattern:/^export\s+const\s+(\w+)\s*(?::\s*([^=]+))?\s*=/gm,nameIndex:1,exported:!0}],li=[{type:"function",pattern:/^def\s+(\w+)\s*\(([^)]*)\)\s*(?:->\s*([^:]+))?\s*:/gm,nameIndex:1},{type:"function",pattern:/^async\s+def\s+(\w+)\s*\(([^)]*)\)\s*(?:->\s*([^:]+))?\s*:/gm,nameIndex:1},{type:"class",pattern:/^class\s+(\w+)(?:\(([^)]*)\))?\s*:/gm,nameIndex:1}],pi=[{type:"function",pattern:/^func\s+(\w+)\s*\(([^)]*)\)\s*(?:\(([^)]*)\)|([^\s{]+))?\s*\{/gm,nameIndex:1},{type:"method",pattern:/^func\s+\([^)]+\)\s+(\w+)\s*\(([^)]*)\)\s*(?:\(([^)]*)\)|([^\s{]+))?\s*\{/gm,nameIndex:1},{type:"type",pattern:/^type\s+(\w+)\s+(?:struct|interface)\s*\{/gm,nameIndex:1}],di=[{type:"function",pattern:/^pub\s+(?:async\s+)?fn\s+(\w+)(?:<[^>]+>)?\s*\(([^)]*)\)\s*(?:->\s*([^{]+))?\s*\{/gm,nameIndex:1,exported:!0},{type:"function",pattern:/^(?:async\s+)?fn\s+(\w+)(?:<[^>]+>)?\s*\(([^)]*)\)\s*(?:->\s*([^{]+))?\s*\{/gm,nameIndex:1},{type:"class",pattern:/^pub\s+struct\s+(\w+)(?:<[^>]+>)?\s*(?:\{|;)/gm,nameIndex:1,exported:!0},{type:"class",pattern:/^struct\s+(\w+)(?:<[^>]+>)?\s*(?:\{|;)/gm,nameIndex:1},{type:"interface",pattern:/^pub\s+trait\s+(\w+)(?:<[^>]+>)?\s*(?:\{|:)/gm,nameIndex:1,exported:!0},{type:"interface",pattern:/^trait\s+(\w+)(?:<[^>]+>)?\s*(?:\{|:)/gm,nameIndex:1},{type:"enum",pattern:/^pub\s+enum\s+(\w+)(?:<[^>]+>)?\s*\{/gm,nameIndex:1,exported:!0},{type:"enum",pattern:/^enum\s+(\w+)(?:<[^>]+>)?\s*\{/gm,nameIndex:1}],Pr=[{type:"class",pattern:/^(?:public\s+)?(?:abstract\s+)?(?:final\s+)?class\s+(\w+)(?:<[^>]+>)?(?:\s+extends\s+\w+)?(?:\s+implements\s+[^{]+)?\s*\{/gm,nameIndex:1,exported:!0},{type:"interface",pattern:/^(?:public\s+)?interface\s+(\w+)(?:<[^>]+>)?(?:\s+extends\s+[^{]+)?\s*\{/gm,nameIndex:1,exported:!0},{type:"method",pattern:/^\s+(?:public|private|protected)?\s*(?:static\s+)?(?:final\s+)?(?:synchronized\s+)?(?:<[^>]+>\s+)?(\w+(?:<[^>]+>)?)\s+(\w+)\s*\([^)]*\)\s*(?:throws\s+[^{]+)?\s*\{/gm,nameIndex:2}],mi={typescript:xr,javascript:xr,python:li,go:pi,rust:di,java:Pr,csharp:Pr,php:[],ruby:[],unknown:[]};async function Rr(r,t=process.cwd()){let e=rt.isAbsolute(r)?r:rt.join(t,r),s=rt.resolve(t),n=rt.resolve(e);if(!n.startsWith(s+rt.sep)&&n!==s)return{file:r,language:"unknown",signatures:[],fallback:!0,fallbackReason:"Path traversal denied: file is outside project directory",metrics:Rt("")};let i;try{i=await ci.readFile(e,"utf-8")}catch(d){if(N(d))return{file:r,language:"unknown",signatures:[],fallback:!0,fallbackReason:"File not found",metrics:Rt("")};throw d}let o=rt.extname(r).toLowerCase(),a=ui[o]||"unknown",u=mi[a];if(!u||u.length===0)return{file:r,language:a,signatures:[],fallback:!0,fallbackReason:`No extraction patterns for ${a}`,metrics:Rt(i)};let p=gi(i,u),m=p.map(d=>`${d.exported?"export ":""}${d.type} ${d.name}: ${d.signature}`).join(`
|
|
527
|
+
`);return{file:r,language:a,signatures:p,fallback:!1,metrics:vr(i,m)}}c(Rr,"extractSignatures");function gi(r,t){let e=[],s=r.split(`
|
|
528
|
+
`),n=new Set;for(let i of t){i.pattern.lastIndex=0;let o;for(;(o=i.pattern.exec(r))!==null;){let a=o[i.nameIndex];if(!a)continue;let u=`${i.type}:${a}`;if(n.has(u))continue;n.add(u);let p=o.index,m=r.substring(0,p).split(`
|
|
529
|
+
`).length,d=o[0].trim(),h;if(m>1){let y=s[m-2]?.trim();(y?.startsWith("/**")||y?.startsWith("///")||y?.startsWith("#"))&&(h=y)}e.push({type:i.type,name:a,signature:fi(d),exported:i.exported||!1,line:m,docstring:h})}}return e.sort((i,o)=>i.line-o.line)}c(gi,"extractFromContent");function fi(r){return r.replace(/\{$/,"").replace(/\s+/g," ").trim()}c(fi,"cleanSignature");function Ar(r){let t=r;t.tool("prjct_relevant_files","BM25-ranked files relevant to a query",{projectPath:z.string().describe("Project directory path"),query:z.string().describe("Task or query to find relevant files for"),maxFiles:z.number().optional().default(10).describe("Max files to return")},E("prjct_relevant_files",async e=>{let s=await wr(e.query,e.projectPath,{maxFiles:e.maxFiles,minScore:.1});if(s.files.length===0)return{content:[{type:"text",text:"No relevant files found."}]};let n=s.files.map(o=>`- \`${o.path}\` (score: ${Math.round(o.score*100)}%) \u2014 ${o.reasons.join(", ")}`);return{content:[{type:"text",text:`## Relevant Files (${s.files.length}/${s.metrics.filesScanned} scanned)
|
|
514
530
|
|
|
515
531
|
${n.join(`
|
|
516
|
-
`)}`}]}})),t.tool("prjct_signatures","Code signatures from a file (90% token reduction vs full content)",{projectPath:
|
|
532
|
+
`)}`}]}})),t.tool("prjct_signatures","Code signatures from a file (90% token reduction vs full content)",{projectPath:z.string().describe("Project directory path"),filePath:z.string().describe("Relative file path to extract signatures from")},E("prjct_signatures",async e=>{let s=await Rr(e.filePath,e.projectPath);if(s.signatures.length===0)return{content:[{type:"text",text:s.fallback?`No signatures extracted: ${s.fallbackReason}`:"No signatures found."}]};let n=s.signatures.map(a=>`${a.exported?"export ":""}${a.type} ${a.name}: ${a.signature}${a.docstring?` // ${a.docstring}`:""}`),i=s.metrics?.compression?` (${Math.round(s.metrics.compression*100)}% reduction)`:"";return{content:[{type:"text",text:`## ${s.file} (${s.language})
|
|
517
533
|
\`\`\`
|
|
518
534
|
${n.join(`
|
|
519
535
|
`)}
|
|
520
|
-
\`\`\`${
|
|
536
|
+
\`\`\`${i}`}]}})),t.tool("prjct_history","Recent completed tasks with outcomes",{projectPath:z.string().describe("Project directory path"),limit:z.number().optional().default(10).describe("Max results")},E("prjct_history",async e=>{let s=await v(e.projectPath),n=await st.getTaskHistory(s);if(n.length===0)return{content:[{type:"text",text:"No task history."}]};let o=n.slice(-e.limit).reverse().map(u=>{let p=[`- **${u.title}**`];return u.completedAt&&p.push(`completed: ${u.completedAt}`),u.classification&&p.push(`type: ${u.classification}`),p.join(" | ")});return{content:[{type:"text",text:`## Task History (${n.length} total)
|
|
537
|
+
|
|
538
|
+
${o.join(`
|
|
539
|
+
`)}`}]}}))}c(Ar,"registerFileTools");import{z as x}from"zod";var ke=class{static{c(this,"MemoryService")}async log(t,e,s,n){try{let i=await W.getProjectId(t);if(!i)return;T.appendEvent(i,`memory.${e}`,{...s,author:n})}catch(i){console.error(`Memory log error: ${i instanceof Error?i.message:String(i)}`)}}async getRecent(t,e=100){try{let s=await W.getProjectId(t);return s?T.query(s,"SELECT type, data, timestamp FROM events WHERE type LIKE 'memory.%' ORDER BY id DESC LIMIT ?",e).reverse().map(i=>{let o=JSON.parse(i.data),{author:a,...u}=o;return{timestamp:i.timestamp,action:i.type.replace("memory.",""),data:u,author:a}}):[]}catch(s){return console.error(`Memory read error: ${s instanceof Error?s.message:String(s)}`),[]}}async search(t,e,s=50){let n=await this.getRecent(t,1e3),i=e.toLowerCase();return n.filter(o=>{let a=o.action.toLowerCase().includes(i),u=JSON.stringify(o.data).toLowerCase().includes(i);return a||u}).slice(-s)}async getByAction(t,e,s=50){try{let n=await W.getProjectId(t);return n?T.query(n,"SELECT type, data, timestamp FROM events WHERE type = ? ORDER BY id DESC LIMIT ?",`memory.${e}`,s).reverse().map(o=>{let a=JSON.parse(o.data),{author:u,...p}=a;return{timestamp:o.timestamp,action:o.type.replace("memory.",""),data:p,author:u}}):[]}catch(n){return console.error(`Memory read error: ${n instanceof Error?n.message:String(n)}`),[]}}async clear(t){try{let e=await W.getProjectId(t);if(!e)return;T.run(e,"DELETE FROM events WHERE type LIKE 'memory.%'")}catch(e){console.error(`Memory clear error: ${e instanceof Error?e.message:String(e)}`)}}async getRecentEvents(t,e=100){try{return T.query(t,"SELECT type, data, timestamp FROM events WHERE type LIKE 'memory.%' ORDER BY id DESC LIMIT ?",e).reverse().map(n=>{let i=JSON.parse(n.data);return{timestamp:n.timestamp,action:n.type.replace("memory.",""),...i}})}catch(s){return console.error(`Memory read error: ${s instanceof Error?s.message:String(s)}`),[]}}async capEntries(t){try{let s=T.get(t,"SELECT COUNT(*) as cnt FROM events WHERE type LIKE 'memory.%'")?.cnt??0;if(s<=pt.MEMORY_MAX_ENTRIES)return 0;let n=s-pt.MEMORY_MAX_ENTRIES,i=T.query(t,"SELECT id, type, data, timestamp FROM events WHERE type LIKE 'memory.%' ORDER BY id ASC LIMIT ?",n);tt.archiveMany(t,i.map((a,u)=>({entityType:"memory_entry",entityId:`memory-${a.timestamp||u}`,entityData:{type:a.type,data:JSON.parse(a.data),timestamp:a.timestamp},summary:a.type.replace("memory.",""),reason:"overflow"})));let o=i[i.length-1]?.id;return o!==void 0&&T.run(t,"DELETE FROM events WHERE type LIKE 'memory.%' AND id <= ?",o),n}catch(e){return console.error(`Memory cap error: ${e instanceof Error?e.message:String(e)}`),0}}},Cr=new ke;var Nr="memory.",Ee="remember.",Se=`${Nr}${Ee}`,Eu=`${Nr}task.tagged`;var Ir=["fact","decision","learning","gotcha","pattern","anti-pattern","shipped","inbox","todo","idea","insight","question","source","person","spec"];var hi=25,yi=4,Ti=100;function Dr(r,t){try{return JSON.parse(r)}catch{return t}}c(Dr,"safeJson");function ki(r){let t=r.type.slice(Se.length),e=Dr(r.data,{});return{id:`mem_${r.id}`,type:t,content:e.content??"",tags:e.tags??{},rememberedAt:r.timestamp,source:e.source,provenance:e.provenance??"declared"}}c(ki,"rowToEntry");function Ei(r){let t=r.data?Dr(r.data,{}):{},e=t.tags??{};return r.type&&(e.type=r.type),{id:`ship_${r.id}`,type:"shipped",content:r.name,tags:e,rememberedAt:r.shipped_at,source:t.taskId,provenance:"extracted"}}c(Ei,"shippedRowToEntry");function Si(r,t){let e=t.toLowerCase();if(r.content.toLowerCase().includes(e))return!0;for(let s of Object.values(r.tags))if(s.toLowerCase().includes(e))return!0;return!1}c(Si,"matchesTopic");function wi(r,t){for(let[e,s]of Object.entries(t))if(r.tags[e]!==s)return!1;return!0}c(wi,"matchesTags");function bi(r){let t=new Set,e=[];for(let s of r){let n=s.tags.key;if(!n){e.push(s);continue}let i=`${s.type}::${n}`;t.has(i)||(t.add(i),e.push(s))}return e}c(bi,"dedupeLatestByKey");var U={async remember(r,t){await Cr.log(r,`${Ee}${t.type}`,{content:t.content,tags:t.tags??{},source:t.source,provenance:t.provenance??"declared"})},recall(r,t={}){let e=t.limit??hi,s=Math.max(e*yi,Ti),n=T.query(r,"SELECT id, type, data, timestamp FROM events WHERE type LIKE ? ORDER BY id DESC LIMIT ?",`${Se}%`,s),i=T.query(r,"SELECT id, name, type, shipped_at, data FROM shipped_features ORDER BY shipped_at DESC LIMIT ?",s),o=[...n.map(ki),...i.map(Ei)];if(t.types&&t.types.length>0){let a=new Set(t.types);o=o.filter(u=>a.has(u.type))}return t.tags&&(o=o.filter(a=>wi(a,t.tags??{}))),t.topic&&(o=o.filter(a=>Si(a,t.topic))),o.sort((a,u)=>u.rememberedAt.localeCompare(a.rememberedAt)),t.dedupeByKey!==!1&&(o=bi(o)),o.slice(0,e)},similar(r,t,e=10){let s=t.toLowerCase().split(/[^a-z0-9]+/).filter(o=>o.length>3);return s.length===0?[]:U.recall(r,{limit:200}).map(o=>{let a=`${o.content} ${Object.values(o.tags).join(" ")}`.toLowerCase(),u=s.reduce((p,m)=>a.includes(m)?p+1:p,0);return{entry:o,hits:u}}).filter(o=>o.hits>0).sort((o,a)=>a.hits-o.hits).slice(0,e).map(o=>o.entry)}};function dt(r){if(r.length===0)return"> No matching memory entries.";let t=new Map;for(let a of r){let u=t.get(a.type)??[];u.push(a),t.set(a.type,u)}let e=["decision","learning","anti-pattern","gotcha","pattern","fact","inbox","todo","idea","insight","question","source","person","shipped"],s=[],n={declared:"DECL",extracted:"EXTR",inferred:"INFR",ambiguous:"AMBG"},i=c((a,u)=>{if(u.length!==0){s.push(`### ${a.toUpperCase()}`);for(let p of u){let m=Object.entries(p.tags).map(([y,D])=>`${y}=${D}`).join(" "),d=m?` _(${m})_`:"",h=n[p.provenance];s.push(`- \`${h}\` [${p.id}] ${p.content}${d}`)}s.push("")}},"renderGroup"),o=new Set;for(let a of e){let u=t.get(a);!u||u.length===0||(i(a,u),o.add(a))}for(let[a,u]of t)o.has(a)||i(a,u);return s.join(`
|
|
540
|
+
`).trim()}c(dt,"formatMemoryMd");var _i=[{name:"sk-\u2026 token",re:/\bsk-[A-Za-z0-9_-]{16,}/},{name:"GitHub PAT",re:/\bghp_[A-Za-z0-9]{30,}/},{name:"GitHub server PAT",re:/\bghs_[A-Za-z0-9]{30,}/},{name:"AWS access key",re:/\bAKIA[0-9A-Z]{16}\b/},{name:"Slack token",re:/\bxox[abps]-[A-Za-z0-9-]{10,}/},{name:"bearer JWT-ish",re:/\beyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\b/}];function Lr(r){let t=[];for(let{name:e,re:s}of _i)s.test(r)&&t.push(e);return t}c(Lr,"scanForSecrets");var jr=`Base types: ${Ir.join(", ")}. Any lowercase identifier is accepted (e.g. "recipe", "okr").`;function Or(r){let t=r;t.tool("prjct_mem_save",`Save a memory entry. ${jr} Secret-like content is refused unless force=true.`,{projectPath:x.string().describe("Project directory path"),type:x.string().describe("Memory type (fact/decision/learning/... or user-defined)"),content:x.string().describe("The memory content. Freeform text."),tags:x.record(x.string(),x.string()).optional().describe('Key:value tags (e.g. {domain: "auth"})'),source:x.string().optional().describe("Task id this memory came from, if any"),force:x.boolean().optional().describe("Bypass the secret-like-content refusal. Default false.")},E("prjct_mem_save",async e=>{await v(e.projectPath);let s=e.type.toLowerCase().trim();if(!s||!/^[a-z][a-z0-9-]*$/.test(s))return{content:[{type:"text",text:`Invalid type '${e.type}'. Lowercase letters + dashes only. ${jr}`}]};let n=Lr(e.content);return n.length>0&&!e.force?{content:[{type:"text",text:`Refused \u2014 content looks like a secret (${n.join(", ")}). Re-call with force=true if intentional.`}]}:(await U.remember(e.projectPath,{type:s,content:e.content,tags:e.tags??{},source:e.source}),{content:[{type:"text",text:`Saved ${s}: ${e.content.slice(0,80)}`}]})})),t.tool("prjct_mem_list","Recall memory entries. Optional filters: topic (keyword across content + tag values), types, tags, limit.",{projectPath:x.string().describe("Project directory path"),topic:x.string().optional().describe("Keyword to match over content + tag values"),types:x.array(x.string()).optional().describe("Restrict to these types"),tags:x.record(x.string(),x.string()).optional().describe("Require exact match on these k:v pairs"),limit:x.number().optional().default(25).describe("Max entries (default 25)")},E("prjct_mem_list",async e=>{let s=await v(e.projectPath),n=U.recall(s,{topic:e.topic,types:e.types,tags:e.tags,limit:e.limit});return{content:[{type:"text",text:dt(n)}]}})),t.tool("prjct_mem_similar","Find memory entries similar to a free-text description. Keyword-based, best-effort.",{projectPath:x.string().describe("Project directory path"),description:x.string().describe("Free-text description to find similar memories for"),limit:x.number().optional().default(10).describe("Max results (default 10)")},E("prjct_mem_similar",async e=>{let s=await v(e.projectPath),n=U.similar(s,e.description,e.limit);return n.length===0?{content:[{type:"text",text:"No similar memories found."}]}:{content:[{type:"text",text:dt(n)}]}})),t.tool("prjct_mem_forget","Remove a memory entry by id. Ids are stable \u2014 pull them from `prjct_mem_list`.",{projectPath:x.string().describe("Project directory path"),id:x.string().describe('Memory id (e.g. "mem_42" or "ship_7")')},E("prjct_mem_forget",async e=>({content:[{type:"text",text:"Forget is not implemented in the projectMemory API yet. Entries persist event-sourced \u2014 filter them out client-side, or drop the underlying event manually."}]})))}c(Or,"registerMemoryTools");import{z as _e}from"zod";var we=class{static{c(this,"LLMAnalysisStorage")}save(t,e){let s=k.getDb(t),n=g();s.transaction(()=>{s.prepare("UPDATE llm_analysis SET status = 'superseded', superseded_at = ? WHERE status = 'active'").run(n),s.prepare("INSERT INTO llm_analysis (commit_hash, status, analysis, analyzed_at) VALUES (?, ?, ?, ?)").run(e.commitHash??null,"active",JSON.stringify(e),e.analyzedAt)})()}getActive(t){let e=k.get(t,"SELECT analysis FROM llm_analysis WHERE status = 'active' LIMIT 1");return e?JSON.parse(e.analysis):null}getActiveSummary(t){let e=this.getActive(t);return e?{commitHash:e.commitHash,architectureStyle:e.architecture.style,patternCount:e.patterns.length,antiPatternCount:e.antiPatterns.length,analyzedAt:e.analyzedAt}:null}isCurrent(t,e){return e?k.get(t,"SELECT commit_hash FROM llm_analysis WHERE status = 'active' LIMIT 1")?.commit_hash===e:!1}getAllFull(t){return k.query(t,"SELECT id, commit_hash, status, analyzed_at, superseded_at, analysis FROM llm_analysis ORDER BY id DESC").map(s=>({id:s.id,status:s.status,commitHash:s.commit_hash,analyzedAt:s.analyzed_at,supersededAt:s.superseded_at,analysis:JSON.parse(s.analysis)}))}getHistory(t,e=10){return k.query(t,"SELECT id, commit_hash, status, analyzed_at, analysis FROM llm_analysis ORDER BY id DESC LIMIT ?",e).map(n=>{let i=JSON.parse(n.analysis);return{id:n.id,commitHash:n.commit_hash,status:n.status,analyzedAt:n.analyzed_at,patternCount:i.patterns.length}})}},vi=new we,Mr=vi;var Fr={critical:0,high:1,medium:2,low:3},Ur={active:0,previously_active:1,backlog:2};function $r(r){return[...r].sort((t,e)=>{let s=Ur[t.section]-Ur[e.section];return s!==0?s:Fr[t.priority]-Fr[e.priority]})}c($r,"sortBySectionAndPriority");var be=class extends et{static{c(this,"QueueStorage")}constructor(){super("queue.json",$s)}getDefault(){return{tasks:[],lastUpdated:""}}getEventType(t){return`queue.${t}d`}async getTasks(t){return(await this.read(t)).tasks}async getActiveTasks(t){return(await this.read(t)).tasks.filter(s=>s.section==="active"&&!s.completed)}async getBacklog(t){return(await this.read(t)).tasks.filter(s=>s.section==="backlog"&&!s.completed)}async getNextTask(t){let e=await this.getActiveTasks(t);return $r(e)[0]||null}async addTask(t,e){let s={...e,id:F(),createdAt:g(),completed:!1};return await this.update(t,n=>({tasks:[...n.tasks,s],lastUpdated:g()})),await this.publishEvent(t,"queue.task_added",{taskId:s.id,description:s.description,priority:s.priority,section:s.section}),s}async addTasks(t,e){let s=g(),n=e.map(i=>({...i,id:F(),createdAt:s,completed:!1}));return await this.update(t,i=>({tasks:[...i.tasks,...n],lastUpdated:s})),await this.publishEvent(t,"queue.tasks_added",{count:n.length,tasks:n.map(i=>({id:i.id,description:i.description}))}),n}async removeTask(t,e){await this.update(t,s=>({tasks:s.tasks.filter(n=>n.id!==e),lastUpdated:g()})),await this.publishEvent(t,"queue.task_removed",{taskId:e})}async completeTask(t,e){let s=null;if(await this.update(t,n=>({tasks:n.tasks.map(o=>o.id===e?(s={...o,completed:!0,completedAt:g()},s):o),lastUpdated:g()})),s){let n=s;await this.publishEvent(t,"queue.task_completed",{taskId:e,description:n.description,completedAt:n.completedAt})}return s}async moveToSection(t,e,s){await this.update(t,n=>({tasks:n.tasks.map(i=>i.id===e?{...i,section:s}:i),lastUpdated:g()}))}async setPriority(t,e,s){await this.update(t,n=>({tasks:n.tasks.map(i=>i.id===e?{...i,priority:s}:i),lastUpdated:g()}))}async getTask(t,e){return(await this.read(t)).tasks.find(n=>n.id===e)||null}async updateTask(t,e,s){let n=null;return await this.update(t,i=>({tasks:i.tasks.map(o=>o.id===e?(n={...o,...s},n):o),lastUpdated:g()})),n&&await this.publishEvent(t,"queue.task_updated",{taskId:e}),n}async clearCompleted(t){let s=(await this.read(t)).tasks.filter(n=>n.completed).length;return await this.update(t,n=>({tasks:n.tasks.filter(i=>!i.completed),lastUpdated:g()})),s}async removeStaleCompleted(t){let e=await this.read(t),s=Ue(pt.QUEUE_COMPLETED_DAYS),n=e.tasks.filter(o=>o.completed&&o.completedAt&&new Date(o.completedAt)<s);if(n.length===0)return 0;tt.archiveMany(t,n.map(o=>({entityType:"queue_task",entityId:o.id,entityData:o,summary:o.description,reason:"age"})));let i=new Set(n.map(o=>o.id));return await this.update(t,o=>({tasks:o.tasks.filter(a=>!i.has(a.id)),lastUpdated:g()})),await this.publishEvent(t,"queue.stale_removed",{count:n.length}),n.length}},Xr=new be;function Wr(r){let t=r;t.tool("prjct_task_status","Current task, duration, subtasks, and queue",{projectPath:_e.string().describe("Project directory path")},E("prjct_task_status",async e=>{let s=await v(e.projectPath),n=await st.getCurrentTask(s),i=await Xr.getActiveTasks(s),o=[];if(n?(o.push(`## Active Task
|
|
541
|
+
**${n.description}**`),n.branch&&o.push(`Branch: ${n.branch}`),o.push(`Started: ${n.startedAt}`)):o.push("No active task."),i.length>0){o.push(`
|
|
542
|
+
## Queue (${i.length} tasks)`);for(let a of i.slice(0,10))o.push(`- ${a.description} [${a.priority||"medium"}]`)}return{content:[{type:"text",text:o.join(`
|
|
543
|
+
`)}]}})),t.tool("prjct_analysis","LLM analysis: stack, patterns, anti-patterns, conventions",{projectPath:_e.string().describe("Project directory path")},E("prjct_analysis",async e=>{let s=await v(e.projectPath),n=Mr.getActive(s);if(!n)return{content:[{type:"text",text:"No analysis available. Run `prjct sync`."}]};let i=["## Project Analysis"];if(n.stack&&(i.push(`
|
|
544
|
+
### Stack`),n.stack.languages?.length&&i.push(`Languages: ${n.stack.languages.join(", ")}`),n.stack.frameworks?.length&&i.push(`Frameworks: ${n.stack.frameworks.join(", ")}`),n.stack.packageManager&&i.push(`Package Manager: ${n.stack.packageManager}`)),n.patterns?.length){i.push(`
|
|
545
|
+
### Patterns (${n.patterns.length})`);for(let o of n.patterns)i.push(`- **${o.name}**: ${o.description}`)}if(n.antiPatterns?.length){i.push(`
|
|
546
|
+
### Anti-Patterns (${n.antiPatterns.length})`);for(let o of n.antiPatterns)i.push(`- **${o.issue}**: ${o.suggestion}`)}if(n.conventions?.length){i.push(`
|
|
547
|
+
### Conventions (${n.conventions.length})`);for(let o of n.conventions)i.push(`- [${o.category}] ${o.rule}`)}return{content:[{type:"text",text:i.join(`
|
|
548
|
+
`)}]}})),t.tool("prjct_patterns","Project memory grouped by type (decision / pattern / anti-pattern / gotcha). Powered by projectMemory \u2014 same source the CLI memory verbs read.",{projectPath:_e.string().describe("Project directory path")},E("prjct_patterns",async e=>{let s=await v(e.projectPath),n=U.recall(s,{types:["decision","pattern","anti-pattern","gotcha"],limit:50});return n.length===0?{content:[{type:"text",text:"No decisions or patterns captured yet."}]}:{content:[{type:"text",text:dt(n)}]}}))}c(Wr,"registerProjectTools");import{z as f}from"zod";import{z as b}from"zod";var nt=["draft","reviewed","in_progress","shipped","archived"],xe=["strategic","architecture","design"],ve=b.object({verdict:b.enum(["pass","fail"]),notes:b.string(),ts:b.string()}),xi=b.object({risk:b.string().min(1),mitigation:b.string().min(1)}),G=b.object({goal:b.string().min(1),eli10:b.string().default(""),stakes:b.string().default(""),acceptance_criteria:b.array(b.string().min(1)).default([]),scope:b.array(b.string()).default([]),out_of_scope:b.array(b.string()).default([]),risks:b.array(xi).default([]),test_plan:b.array(b.string()).default([]),reviews:b.object({strategic:ve.optional(),architecture:ve.optional(),design:ve.optional()}).optional(),linked_tasks:b.array(b.string()).default([]),notes:b.string().default("")});var Pe=class{static{c(this,"SpecStorage")}create(t,e){let s=F(),n=g(),i=G.parse(e.content);return T.run(t,`INSERT INTO specs (id, title, status, content, tags, created_at, updated_at)
|
|
549
|
+
VALUES (?, ?, 'draft', ?, ?, ?, ?)`,s,e.title,JSON.stringify(i),e.tags?JSON.stringify(e.tags):null,n,n),{id:s,title:e.title,status:"draft",content:i,tags:e.tags??{},createdAt:n,updatedAt:n,shippedAt:null,shippedPr:null,archivedAt:null}}get(t,e){let s=T.get(t,"SELECT * FROM specs WHERE id = ?",e);return s?this.rowToSpec(s):null}list(t,e={}){let s="SELECT * FROM specs WHERE 1=1",n=[];return e.status&&(s+=" AND status = ?",n.push(e.status)),!e.includeArchived&&!e.status&&(s+=" AND status != 'archived'"),s+=" ORDER BY created_at DESC",T.query(t,s,...n).map(o=>this.rowToSpec(o))}search(t,e){let s=`%${e}%`;return T.query(t,"SELECT * FROM specs WHERE title LIKE ? OR content LIKE ? ORDER BY created_at DESC",s,s).map(i=>this.rowToSpec(i))}updateContent(t,e,s){let n=G.parse(s),i=g();return T.run(t,"UPDATE specs SET content = ?, updated_at = ? WHERE id = ?",JSON.stringify(n),i,e),this.get(t,e)}setStatus(t,e,s){if(!nt.includes(s))throw new Error(`invalid spec status: ${s}`);let n=g(),i=[],o=[s,n];s==="shipped"&&(i.push("shipped_at = ?"),o.push(n)),s==="archived"&&(i.push("archived_at = ?"),o.push(n));let a=["status = ?","updated_at = ?",...i].join(", ");return o.push(e),T.run(t,`UPDATE specs SET ${a} WHERE id = ?`,...o),this.get(t,e)}setShippedPr(t,e,s){return T.run(t,"UPDATE specs SET shipped_pr = ?, updated_at = ? WHERE id = ?",s,g(),e),this.get(t,e)}linkTask(t,e,s){let n=this.get(t,e);if(!n)return null;if(n.content.linked_tasks.includes(s))return n;let i={...n.content,linked_tasks:[...n.content.linked_tasks,s]};return this.updateContent(t,e,i)}delete(t,e){return this.get(t,e)?(T.run(t,"DELETE FROM specs WHERE id = ?",e),!0):!1}count(t){let e=T.query(t,"SELECT status, COUNT(*) AS n FROM specs GROUP BY status"),s={total:0,draft:0,shipped:0};for(let n of e)s.total+=n.n,n.status==="draft"&&(s.draft=n.n),n.status==="shipped"&&(s.shipped=n.n);return s}rowToSpec(t){return{id:t.id,title:t.title,status:nt.includes(t.status)?t.status:"draft",content:G.parse(JSON.parse(t.content)),tags:t.tags?JSON.parse(t.tags):{},createdAt:t.created_at,updatedAt:t.updated_at,shippedAt:t.shipped_at,shippedPr:t.shipped_pr,archivedAt:t.archived_at}}},I=new Pe;var Re=class{static{c(this,"SpecService")}async create(t,e){let s=await this.requireProjectId(t),n=G.parse({goal:e.content.goal,eli10:e.content.eli10??"",stakes:e.content.stakes??"",acceptance_criteria:e.content.acceptance_criteria??[],scope:e.content.scope??[],out_of_scope:e.content.out_of_scope??[],risks:e.content.risks??[],test_plan:e.content.test_plan??[],reviews:e.content.reviews,linked_tasks:e.content.linked_tasks??[],notes:e.content.notes??""}),i=I.create(s,{title:e.title,content:n,tags:e.tags});return await U.remember(t,{type:"spec",content:`${i.title}
|
|
550
|
+
|
|
551
|
+
Goal: ${i.content.goal}`,tags:{...e.tags??{},spec_id:i.id,status:i.status},source:i.id,provenance:"declared"}),i}async get(t,e){let s=await this.requireProjectId(t);return I.get(s,e)}async list(t,e={}){let s=await this.requireProjectId(t);return I.list(s,e)}async setStatus(t,e,s){let n=await this.requireProjectId(t),i=I.setStatus(n,e,s);return i&&await U.remember(t,{type:"spec",content:`Spec status \u2192 ${s}: ${i.title}`,tags:{spec_id:e,status:s,event:"status_change"},source:e}),i}async update(t,e,s){let n=await this.requireProjectId(t);return I.updateContent(n,e,s)}async recordReview(t,e,s,n){let i=await this.requireProjectId(t),o=I.get(i,e);if(!o)return null;let a={...n,ts:g()},u={...o.content,reviews:{...o.content.reviews??{},[s]:a}},p=I.updateContent(i,e,u);return p&&this.allReviewsPass(p.content)&&p.status==="draft"?I.setStatus(i,e,"reviewed"):p}async linkTask(t,e,s){let n=await this.requireProjectId(t);return I.linkTask(n,e,s)}async ship(t,e,s){let n=await this.requireProjectId(t);return s!==void 0&&I.setShippedPr(n,e,s),I.setStatus(n,e,"shipped")}unmetCriteria(t,e=new Set){return t.content.acceptance_criteria.filter(s=>!e.has(s))}allReviewsPass(t){let e=t.reviews;return e?e.strategic?.verdict==="pass"&&e.architecture?.verdict==="pass"&&e.design?.verdict==="pass":!1}async requireProjectId(t){let e=await W.readConfig(t);if(!e?.projectId)throw new Error("not a prjct project (run `prjct init` first)");return e.projectId}},B=new Re;function Br(r){let t=r;t.tool("prjct_spec_create",'CALL THIS when the user describes a feature, fix, or initiative WITH goals or stakes attached (e.g. "we need rate limiting on auth", "fix onboarding", "let\'s build SDD"). Drafts a spec \u2014 Goal/ELI10/Stakes/Acceptance criteria/Scope/Out-of-scope/Risks/Test plan. The structured fields default to empty; populate them by calling `prjct_spec_update` once you have the answers. Skip this tool only for routine work (single-file fix, doc tweak, GTD capture) \u2014 for that, use `prjct_capture` or the matching memory tool.',{projectPath:f.string().describe("Project directory path"),title:f.string().describe("One-line title (what you'd say to a coworker walking by)"),goal:f.string().describe("What success looks like, 1-3 sentences. Concrete, observable."),eli10:f.string().optional().describe("Plain English a 16-year-old follows, 2-4 sentences"),stakes:f.string().optional().describe("What breaks if we ship the wrong thing"),acceptance_criteria:f.array(f.string()).optional().describe("Testable, observable list. Each item ends in a verifiable claim."),scope:f.array(f.string()).optional().describe("What's IN \u2014 file paths, modules, surfaces"),out_of_scope:f.array(f.string()).optional().describe("What's OUT \u2014 anti-creep shield"),risks:f.array(f.object({risk:f.string(),mitigation:f.string()})).optional().describe("Each risk has a mitigation; a risk without one is just a complaint"),test_plan:f.array(f.string()).optional().describe("How you prove acceptance criteria"),tags:f.record(f.string(),f.string()).optional().describe('Key:value tags (e.g. {domain: "auth", priority: "high"})')},E("prjct_spec_create",async e=>{let s=await B.create(e.projectPath,{title:e.title,content:{goal:e.goal,eli10:e.eli10,stakes:e.stakes,acceptance_criteria:e.acceptance_criteria,scope:e.scope,out_of_scope:e.out_of_scope,risks:e.risks,test_plan:e.test_plan},tags:e.tags});return{content:[{type:"text",text:[`\u2713 spec drafted: ${s.title}`,"",`id: ${s.id}`,`status: ${s.status}`,`goal: ${s.content.goal}`,"","Next: `prjct_spec_audit` to dispatch the three review subagents (strategic / architecture / design) in parallel."].join(`
|
|
552
|
+
`)}]}})),t.tool("prjct_spec_list","List specs in this project. Use to check what specs exist before drafting a new one (avoid duplicates) or to find the right spec to link a task to.",{projectPath:f.string().describe("Project directory path"),status:f.enum(nt).optional().describe("Filter by status: draft|reviewed|in_progress|shipped|archived"),includeArchived:f.boolean().optional().describe("Include archived specs (default: false)")},E("prjct_spec_list",async e=>{let s=await v(e.projectPath),n=I.list(s,{status:e.status,includeArchived:e.includeArchived});if(n.length===0)return{content:[{type:"text",text:"_No specs match. Start one with `prjct_spec_create`._"}]};let i=["# Specs",""];for(let o of n){let a=o.content.acceptance_criteria.length,u=o.content.linked_tasks.length;i.push(`## ${o.title}
|
|
553
|
+
- id: \`${o.id}\`
|
|
554
|
+
- status: ${o.status}
|
|
555
|
+
- acceptance criteria: ${a}
|
|
556
|
+
- linked tasks: ${u}
|
|
557
|
+
- created: ${o.createdAt}`),i.push("")}return{content:[{type:"text",text:i.join(`
|
|
558
|
+
`)}]}})),t.tool("prjct_spec_get","Fetch one spec by id, including all structured fields (goal, acceptance criteria, scope, risks, reviews, linked tasks).",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id")},E("prjct_spec_get",async e=>{let s=await B.get(e.projectPath,e.id);return s?{content:[{type:"text",text:Pi(s)}]}:{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]}})),t.tool("prjct_spec_update","Replace a spec's structured content. Pass the FULL content object (this is a replace, not a merge) \u2014 when filling in acceptance_criteria for the first time, fetch with `prjct_spec_get` first and merge in your changes.",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id"),content:f.object({goal:f.string(),eli10:f.string().optional(),stakes:f.string().optional(),acceptance_criteria:f.array(f.string()).optional(),scope:f.array(f.string()).optional(),out_of_scope:f.array(f.string()).optional(),risks:f.array(f.object({risk:f.string(),mitigation:f.string()})).optional(),test_plan:f.array(f.string()).optional(),notes:f.string().optional(),linked_tasks:f.array(f.string()).optional()}).describe("Full SpecContent shape \u2014 Zod-validated server-side")},E("prjct_spec_update",async e=>{let s=G.parse(e.content),n=await B.update(e.projectPath,e.id,s);return n?{content:[{type:"text",text:`\u2713 spec updated: ${n.title}`}]}:{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]}})),t.tool("prjct_spec_set_status","Promote / demote a spec lifecycle state. Reviewers passing is auto-promoting (draft \u2192 reviewed); use this tool to mark a spec `in_progress` when work starts, `archived` when superseded, or `shipped` (use `prjct_spec_ship` instead when shipping for the first time, since it also records the PR).",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id"),status:f.enum(nt).describe("Target status")},E("prjct_spec_set_status",async e=>await B.setStatus(e.projectPath,e.id,e.status)?{content:[{type:"text",text:`\u2713 spec ${e.id} \u2192 ${e.status}`}]}:{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]})),t.tool("prjct_spec_audit","CALL THIS before any implementation work begins on a spec. Returns a dispatch prompt for THREE review subagents (strategic / architecture / design). RUN ALL THREE IN PARALLEL via your Agent / Task tool \u2014 one tool-use block per reviewer in the SAME message. Each returns a verdict (pass | fail) + notes. Persist each via `prjct_spec_record_review`. All three pass \u2192 the spec auto-promotes draft \u2192 reviewed and is safe to start a task against.",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id to audit")},E("prjct_spec_audit",async e=>{let s=await B.get(e.projectPath,e.id);return s?{content:[{type:"text",text:Ri(s.id,s.title,s.content)}]}:{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]}})),t.tool("prjct_spec_record_review","Persist one reviewer's verdict from `prjct_spec_audit` dispatch. Call once per reviewer (strategic, architecture, design). When all three are recorded with verdict=pass, the spec auto-promotes draft \u2192 reviewed.",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id"),reviewer:f.enum(xe).describe("Which reviewer"),verdict:f.enum(["pass","fail"]).describe("Verdict"),notes:f.string().describe("2-4 sentence notes from the subagent")},E("prjct_spec_record_review",async e=>{let s=await B.recordReview(e.projectPath,e.id,e.reviewer,{verdict:e.verdict,notes:e.notes});if(!s)return{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]};let n=s.status==="reviewed"?" (all reviewers passed \u2192 status: reviewed)":"";return{content:[{type:"text",text:`\u2713 ${e.reviewer} \u2192 ${e.verdict}${n}`}]}})),t.tool("prjct_spec_link_task","Link a task to its spec. Call this AFTER starting the task (when the user begins implementation) so `prjct_ship` later knows which spec to gate against. Idempotent \u2014 re-linking the same task is a no-op.",{projectPath:f.string().describe("Project directory path"),specId:f.string().describe("Spec id"),taskId:f.string().describe("Task id (from `prjct_session_start_task` or stateStorage)")},E("prjct_spec_link_task",async e=>await B.linkTask(e.projectPath,e.specId,e.taskId)?{content:[{type:"text",text:`\u2713 linked task ${e.taskId} to spec ${e.specId}`}]}:{content:[{type:"text",text:`_Spec not found: ${e.specId}_`}]})),t.tool("prjct_spec_ship","Mark a spec as shipped (after the linked PR merges). Records the PR number on the spec for provenance.",{projectPath:f.string().describe("Project directory path"),id:f.string().describe("Spec id"),pr:f.number().optional().describe("PR / MR number that delivered the spec")},E("prjct_spec_ship",async e=>{let s=await B.ship(e.projectPath,e.id,e.pr);return s?{content:[{type:"text",text:`\u2713 spec shipped: ${s.title}${e.pr?` (PR #${e.pr})`:""}`}]}:{content:[{type:"text",text:`_Spec not found: ${e.id}_`}]}}))}c(Br,"registerSpecTools");function Pi(r){let t=r.content,e=[`# ${r.title}`,"",`**id:** \`${r.id}\` \xB7 **status:** ${r.status} \xB7 **created:** ${r.createdAt}`,"","## Goal",t.goal];if(t.eli10&&e.push("","## ELI10",t.eli10),t.stakes&&e.push("","## Stakes",t.stakes),t.acceptance_criteria.length>0){e.push("","## Acceptance criteria");for(let s of t.acceptance_criteria)e.push(`- [ ] ${s}`)}if(t.scope.length>0){e.push("","## Scope");for(let s of t.scope)e.push(`- ${s}`)}if(t.out_of_scope.length>0){e.push("","## Out of scope");for(let s of t.out_of_scope)e.push(`- ${s}`)}if(t.risks.length>0){e.push("","## Risks");for(let s of t.risks)e.push(`- **${s.risk}** \u2014 ${s.mitigation}`)}if(t.test_plan.length>0){e.push("","## Test plan");for(let s of t.test_plan)e.push(`- ${s}`)}if(t.reviews){e.push("","## Reviews");for(let s of xe){let n=t.reviews[s];n&&e.push(`- **${s}:** ${n.verdict} \u2014 ${n.notes} _(${n.ts})_`)}}return t.linked_tasks.length>0&&e.push("","## Linked tasks",...t.linked_tasks.map(s=>`- ${s}`)),t.notes&&e.push("","## Notes",t.notes),e.join(`
|
|
559
|
+
`)}c(Pi,"renderSpecMarkdown");function Ri(r,t,e){let s=JSON.stringify(e);return[`# audit-spec dispatch \u2014 ${t}`,"",`Spec id: \`${r}\``,"","Run three review subagents IN PARALLEL via your Agent / Task tool \u2014 one tool-use block per reviewer, all in the SAME message so they run concurrently. Each subagent reads the spec body and applies its rubric, then returns a structured verdict (pass | fail + 2-4 sentence notes).","","## Reviewer A \u2014 strategic (scope sanity)",'Subagent prompt: "Review this spec for strategic soundness. Does it solve a real problem? Is the goal worth the cost? Is out_of_scope coherent with goal? Is the spec OVER- or UNDER-scoped? Return verdict (pass|fail) and 2-4 sentence notes."',"","## Reviewer B \u2014 architecture (eng feasibility)",'Subagent prompt: "Review this spec for engineering feasibility. Can this be built? Is the data flow / state machine implicit in the acceptance criteria coherent? What failure modes / dependencies / edge cases are missing? Include a short ASCII diagram of the proposed architecture in notes if applicable. Return verdict (pass|fail) and 2-4 sentence notes."',"","## Reviewer C \u2014 design (UX/DX)",'Subagent prompt: "Review this spec for design quality. Rate 0-10 across {clarity, ergonomics, consistency, accessibility} for the user-facing or developer-facing surface this spec defines. Note the lowest-scoring dimension and why. Return verdict (pass if all dimensions \u22656, fail otherwise) and notes including the four scores."',"","## Spec body (verbatim, pass to each reviewer)","```json",s,"```","","## After dispatch","For each reviewer that returns:",` Call \`prjct_spec_record_review\` with id="${r}", reviewer=<strategic|architecture|design>, verdict=<pass|fail>, notes="<their notes>"`,"","When all three are recorded with verdict=pass, the spec auto-promotes from `draft` \u2192 `reviewed`."].join(`
|
|
560
|
+
`)}c(Ri,"renderAuditDispatch");import{z as Ct}from"zod";var Ae=class{static{c(this,"CustomWorkflowStorage")}createWorkflow(t,e){let s=new Date().toISOString();T.run(t,`INSERT INTO custom_workflows (name, description, created_at, updated_at, is_builtin, enabled, metadata)
|
|
561
|
+
VALUES (?, ?, ?, ?, 0, 1, ?)`,e.name,e.description??null,s,s,e.metadata?JSON.stringify(e.metadata):null);let n=T.get(t,"SELECT id FROM custom_workflows WHERE name = ?",e.name);if(!n)throw new Error(`Failed to create workflow: ${e.name}`);return n.id}getWorkflow(t,e){let s=T.get(t,"SELECT * FROM custom_workflows WHERE name = ?",e);return s?this.rowToWorkflow(s):null}getAllWorkflows(t,e=!1){let s=e?"SELECT * FROM custom_workflows ORDER BY is_builtin DESC, name ASC":"SELECT * FROM custom_workflows WHERE enabled = 1 ORDER BY is_builtin DESC, name ASC";return T.query(t,s).map(i=>this.rowToWorkflow(i))}updateWorkflow(t,e,s){if(!this.getWorkflow(t,e))return!1;let i=new Date().toISOString(),o=[],a=[];return s.description!==void 0&&(o.push("description = ?"),a.push(s.description)),s.enabled!==void 0&&(o.push("enabled = ?"),a.push(s.enabled?1:0)),s.metadata!==void 0&&(o.push("metadata = ?"),a.push(JSON.stringify(s.metadata))),o.length===0?!1:(o.push("updated_at = ?"),a.push(i),a.push(e),T.run(t,`UPDATE custom_workflows SET ${o.join(", ")} WHERE name = ?`,...a),!0)}deleteWorkflow(t,e){let s=this.getWorkflow(t,e);if(!s)return!1;if(s.isBuiltin)throw new Error(`Cannot delete built-in workflow: ${e}`);return T.run(t,"UPDATE custom_workflows SET enabled = 0 WHERE name = ?",e),!0}isBuiltin(t,e){return this.getWorkflow(t,e)?.isBuiltin??!1}isReservedName(t){let e=["task","done","ship","sync"],s=["add","rm","gate","list","create","delete","run","help","reset","init"];return e.includes(t)||s.includes(t)}isValidName(t){return/^[a-z0-9-]+$/.test(t)}rowToWorkflow(t){return{id:t.id,name:t.name,description:t.description,createdAt:t.created_at,updatedAt:t.updated_at,isBuiltin:t.is_builtin===1,enabled:t.enabled===1,metadata:t.metadata?JSON.parse(t.metadata):null}}},At=new Ae;function Ce(r){let t=r.trust_source==="imported"?"imported":"local";return{id:r.id,type:r.type,command:r.command,position:r.position,action:r.action,description:r.description,enabled:r.enabled===1,timeoutMs:r.timeout_ms,createdAt:r.created_at,sortOrder:r.sort_order,whenExpr:r.when_expr??null,parallel:r.parallel===null?!0:r.parallel===1,trustSource:t}}c(Ce,"rowToRule");var Ne=class{static{c(this,"WorkflowRuleStorage")}addRule(t,e){let s=k.get(t,"SELECT MAX(sort_order) as m FROM workflow_rules WHERE command = ?",e.command),n=e.sortOrder||(s?.m??-1)+1;return k.run(t,`INSERT INTO workflow_rules (type, command, position, action, description, enabled, timeout_ms, created_at, sort_order, when_expr, parallel, trust_source)
|
|
562
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,e.type,e.command,e.position,e.action,e.description??null,e.enabled?1:0,e.timeoutMs,e.createdAt,n,e.whenExpr??null,e.parallel===!1?0:1,e.trustSource??"local"),k.get(t,"SELECT last_insert_rowid() as id")?.id??0}removeRule(t,e){return k.get(t,"SELECT id FROM workflow_rules WHERE id = ?",e)?(k.run(t,"DELETE FROM workflow_rules WHERE id = ?",e),!0):!1}updateRule(t,e,s){if(!k.get(t,"SELECT id FROM workflow_rules WHERE id = ?",e))return!1;let i={type:{column:"type"},command:{column:"command"},position:{column:"position"},action:{column:"action"},description:{column:"description"},enabled:{column:"enabled",transform:c(u=>u?1:0,"transform")},timeoutMs:{column:"timeout_ms"},createdAt:{column:"created_at"},sortOrder:{column:"sort_order"},whenExpr:{column:"when_expr"},parallel:{column:"parallel",transform:c(u=>u===!1?0:1,"transform")},trustSource:{column:"trust_source"}},o=[],a=[];for(let[u,p]of Object.entries(s)){let m=i[u];if(!m)continue;o.push(`${m.column} = ?`);let d=p;a.push(m.transform?m.transform(d):d)}return o.length===0||(a.push(e),k.run(t,`UPDATE workflow_rules SET ${o.join(", ")} WHERE id = ?`,...a)),!0}getRuleById(t,e){let s=k.get(t,"SELECT * FROM workflow_rules WHERE id = ?",e);return s?Ce(s):null}getRulesForCommand(t,e){let s=At.getWorkflow(t,e);return!s||!s.enabled?[]:k.query(t,"SELECT * FROM workflow_rules WHERE command = ? AND enabled = 1 ORDER BY sort_order ASC",e).map(Ce)}getAllRules(t){return k.query(t,"SELECT * FROM workflow_rules ORDER BY command ASC, sort_order ASC").map(Ce)}resetRules(t){let e=k.get(t,"SELECT COUNT(*) as c FROM workflow_rules");return k.run(t,"DELETE FROM workflow_rules"),e?.c??0}},Ie=new Ne;function Hr(r){let t=r;t.tool("prjct_workflow_rules","Get workflow rules for a command (gates, hooks, steps, instructions)",{projectPath:Ct.string().describe("Project directory path"),command:Ct.string().describe("Command name (task, done, ship, sync, etc.)")},E("prjct_workflow_rules",async e=>{let s=await v(e.projectPath),n=Ie.getRulesForCommand(s,e.command);if(n.length===0)return{content:[{type:"text",text:`No workflow rules for \`${e.command}\`.`}]};let i={};for(let a of n){let u=`${a.type}:${a.position}`;i[u]||(i[u]=[]),i[u].push(a)}let o=[`## Workflow Rules for \`${e.command}\``];for(let[a,u]of Object.entries(i)){o.push(`
|
|
563
|
+
### ${a}`);for(let p of u){let m=p.enabled?"":" (disabled)";o.push(`- ${p.action}${p.description?` \u2014 ${p.description}`:""}${m}`)}}return{content:[{type:"text",text:o.join(`
|
|
564
|
+
`)}]}})),t.tool("prjct_workflow_list","List all workflows for this project (built-in + custom)",{projectPath:Ct.string().describe("Project directory path")},E("prjct_workflow_list",async e=>{let s=await v(e.projectPath),n=At.getAllWorkflows(s);if(n.length===0)return{content:[{type:"text",text:"No workflows configured."}]};let i=n.map(o=>{let a=o.isBuiltin?"(built-in)":"(custom)",u=o.enabled?"":" [disabled]";return`- **${o.name}** ${a}${u}${o.description?`: ${o.description}`:""}`});return{content:[{type:"text",text:`## Workflows (${n.length})
|
|
521
565
|
|
|
522
566
|
${i.join(`
|
|
523
|
-
`)}`}]}}))
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
### Patterns (${n.patterns.length})`);for(let i of n.patterns)o.push(`- **${i.name}**: ${i.description}`)}if(n.antiPatterns?.length){o.push(`
|
|
530
|
-
### Anti-Patterns (${n.antiPatterns.length})`);for(let i of n.antiPatterns)o.push(`- **${i.issue}**: ${i.suggestion}`)}if(n.conventions?.length){o.push(`
|
|
531
|
-
### Conventions (${n.conventions.length})`);for(let i of n.conventions)o.push(`- [${i.category}] ${i.rule}`)}return{content:[{type:"text",text:o.join(`
|
|
532
|
-
`)}]}})),t.tool("prjct_patterns","Project memory grouped by type (decision / pattern / anti-pattern / gotcha). Powered by projectMemory \u2014 same source the CLI memory verbs read.",{projectPath:Te.string().describe("Project directory path")},w("prjct_patterns",async e=>{let r=await x(e.projectPath),n=H.recall(r,{types:["decision","pattern","anti-pattern","gotcha"],limit:50});return n.length===0?{content:[{type:"text",text:"No decisions or patterns captured yet."}]}:{content:[{type:"text",text:it(n)}]}}))}c(Is,"registerProjectTools");import{z as xt}from"zod";var ke=class{static{c(this,"CustomWorkflowStorage")}createWorkflow(t,e){let r=new Date().toISOString();k.run(t,`INSERT INTO custom_workflows (name, description, created_at, updated_at, is_builtin, enabled, metadata)
|
|
533
|
-
VALUES (?, ?, ?, ?, 0, 1, ?)`,e.name,e.description??null,r,r,e.metadata?JSON.stringify(e.metadata):null);let n=k.get(t,"SELECT id FROM custom_workflows WHERE name = ?",e.name);if(!n)throw new Error(`Failed to create workflow: ${e.name}`);return n.id}getWorkflow(t,e){let r=k.get(t,"SELECT * FROM custom_workflows WHERE name = ?",e);return r?this.rowToWorkflow(r):null}getAllWorkflows(t,e=!1){let r=e?"SELECT * FROM custom_workflows ORDER BY is_builtin DESC, name ASC":"SELECT * FROM custom_workflows WHERE enabled = 1 ORDER BY is_builtin DESC, name ASC";return k.query(t,r).map(o=>this.rowToWorkflow(o))}updateWorkflow(t,e,r){if(!this.getWorkflow(t,e))return!1;let o=new Date().toISOString(),i=[],a=[];return r.description!==void 0&&(i.push("description = ?"),a.push(r.description)),r.enabled!==void 0&&(i.push("enabled = ?"),a.push(r.enabled?1:0)),r.metadata!==void 0&&(i.push("metadata = ?"),a.push(JSON.stringify(r.metadata))),i.length===0?!1:(i.push("updated_at = ?"),a.push(o),a.push(e),k.run(t,`UPDATE custom_workflows SET ${i.join(", ")} WHERE name = ?`,...a),!0)}deleteWorkflow(t,e){let r=this.getWorkflow(t,e);if(!r)return!1;if(r.isBuiltin)throw new Error(`Cannot delete built-in workflow: ${e}`);return k.run(t,"UPDATE custom_workflows SET enabled = 0 WHERE name = ?",e),!0}isBuiltin(t,e){return this.getWorkflow(t,e)?.isBuiltin??!1}isReservedName(t){let e=["task","done","ship","sync"],r=["add","rm","gate","list","create","delete","run","help","reset","init"];return e.includes(t)||r.includes(t)}isValidName(t){return/^[a-z0-9-]+$/.test(t)}rowToWorkflow(t){return{id:t.id,name:t.name,description:t.description,createdAt:t.created_at,updatedAt:t.updated_at,isBuiltin:t.is_builtin===1,enabled:t.enabled===1,metadata:t.metadata?JSON.parse(t.metadata):null}}},St=new ke;function Ee(s){let t=s.trust_source==="imported"?"imported":"local";return{id:s.id,type:s.type,command:s.command,position:s.position,action:s.action,description:s.description,enabled:s.enabled===1,timeoutMs:s.timeout_ms,createdAt:s.created_at,sortOrder:s.sort_order,whenExpr:s.when_expr??null,parallel:s.parallel===null?!0:s.parallel===1,trustSource:t}}c(Ee,"rowToRule");var be=class{static{c(this,"WorkflowRuleStorage")}addRule(t,e){let r=y.get(t,"SELECT MAX(sort_order) as m FROM workflow_rules WHERE command = ?",e.command),n=e.sortOrder||(r?.m??-1)+1;return y.run(t,`INSERT INTO workflow_rules (type, command, position, action, description, enabled, timeout_ms, created_at, sort_order, when_expr, parallel, trust_source)
|
|
534
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,e.type,e.command,e.position,e.action,e.description??null,e.enabled?1:0,e.timeoutMs,e.createdAt,n,e.whenExpr??null,e.parallel===!1?0:1,e.trustSource??"local"),y.get(t,"SELECT last_insert_rowid() as id")?.id??0}removeRule(t,e){return y.get(t,"SELECT id FROM workflow_rules WHERE id = ?",e)?(y.run(t,"DELETE FROM workflow_rules WHERE id = ?",e),!0):!1}updateRule(t,e,r){if(!y.get(t,"SELECT id FROM workflow_rules WHERE id = ?",e))return!1;let o={type:{column:"type"},command:{column:"command"},position:{column:"position"},action:{column:"action"},description:{column:"description"},enabled:{column:"enabled",transform:c(u=>u?1:0,"transform")},timeoutMs:{column:"timeout_ms"},createdAt:{column:"created_at"},sortOrder:{column:"sort_order"},whenExpr:{column:"when_expr"},parallel:{column:"parallel",transform:c(u=>u===!1?0:1,"transform")},trustSource:{column:"trust_source"}},i=[],a=[];for(let[u,p]of Object.entries(r)){let m=o[u];if(!m)continue;i.push(`${m.column} = ?`);let d=p;a.push(m.transform?m.transform(d):d)}return i.length===0||(a.push(e),y.run(t,`UPDATE workflow_rules SET ${i.join(", ")} WHERE id = ?`,...a)),!0}getRuleById(t,e){let r=y.get(t,"SELECT * FROM workflow_rules WHERE id = ?",e);return r?Ee(r):null}getRulesForCommand(t,e){let r=St.getWorkflow(t,e);return!r||!r.enabled?[]:y.query(t,"SELECT * FROM workflow_rules WHERE command = ? AND enabled = 1 ORDER BY sort_order ASC",e).map(Ee)}getAllRules(t){return y.query(t,"SELECT * FROM workflow_rules ORDER BY command ASC, sort_order ASC").map(Ee)}resetRules(t){let e=y.get(t,"SELECT COUNT(*) as c FROM workflow_rules");return y.run(t,"DELETE FROM workflow_rules"),e?.c??0}},we=new be;function Ds(s){let t=s;t.tool("prjct_workflow_rules","Get workflow rules for a command (gates, hooks, steps, instructions)",{projectPath:xt.string().describe("Project directory path"),command:xt.string().describe("Command name (task, done, ship, sync, etc.)")},w("prjct_workflow_rules",async e=>{let r=await x(e.projectPath),n=we.getRulesForCommand(r,e.command);if(n.length===0)return{content:[{type:"text",text:`No workflow rules for \`${e.command}\`.`}]};let o={};for(let a of n){let u=`${a.type}:${a.position}`;o[u]||(o[u]=[]),o[u].push(a)}let i=[`## Workflow Rules for \`${e.command}\``];for(let[a,u]of Object.entries(o)){i.push(`
|
|
535
|
-
### ${a}`);for(let p of u){let m=p.enabled?"":" (disabled)";i.push(`- ${p.action}${p.description?` \u2014 ${p.description}`:""}${m}`)}}return{content:[{type:"text",text:i.join(`
|
|
536
|
-
`)}]}})),t.tool("prjct_workflow_list","List all workflows for this project (built-in + custom)",{projectPath:xt.string().describe("Project directory path")},w("prjct_workflow_list",async e=>{let r=await x(e.projectPath),n=St.getAllWorkflows(r);if(n.length===0)return{content:[{type:"text",text:"No workflows configured."}]};let o=n.map(i=>{let a=i.isBuiltin?"(built-in)":"(custom)",u=i.enabled?"":" [disabled]";return`- **${i.name}** ${a}${u}${i.description?`: ${i.description}`:""}`});return{content:[{type:"text",text:`## Workflows (${n.length})
|
|
567
|
+
`)}`}]}})),t.tool("prjct_workflow_status","Current workflow execution state + active rules",{projectPath:Ct.string().describe("Project directory path")},E("prjct_workflow_status",async e=>{let s=await v(e.projectPath),n=await st.getCurrentTask(s),i=Ie.getAllRules(s),o=["## Workflow Status"];n?(o.push(`
|
|
568
|
+
Active task: **${n.description}**`),o.push(`Started: ${n.startedAt}`)):o.push(`
|
|
569
|
+
No active task.`);let a=i.filter(u=>u.enabled);if(a.length>0){o.push(`
|
|
570
|
+
### Active Rules (${a.length})`);for(let u of a)o.push(`- [${u.type}] ${u.command}:${u.position} \u2192 ${u.action}`)}else o.push(`
|
|
571
|
+
No active workflow rules.`);return{content:[{type:"text",text:o.join(`
|
|
572
|
+
`)}]}}))}c(Hr,"registerWorkflowTools");var Ci=`# prjct \u2014 Spec-Driven Development + project memory
|
|
537
573
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
No active workflow rules.`);return{content:[{type:"text",text:i.join(`
|
|
544
|
-
`)}]}}))}c(Ds,"registerWorkflowTools");var yo=`# prjct \u2014 persona-aware context broker
|
|
574
|
+
Use when the user describes work, asks for project memory, or wants to run a registered workflow. **Recognize intent \u2014 don't wait for the user to type prjct commands.**
|
|
575
|
+
|
|
576
|
+
## SDD canonical sequence
|
|
577
|
+
|
|
578
|
+
When the user describes a feature, fix, or initiative *with goals or stakes attached*, default to the SDD flow:
|
|
545
579
|
|
|
546
|
-
|
|
580
|
+
\`\`\`
|
|
581
|
+
spec \u2192 audit-spec \u2192 task (linked to spec) \u2192 implement \u2192 ship (acceptance gate) \u2192 remember learning
|
|
582
|
+
\`\`\`
|
|
583
|
+
|
|
584
|
+
- **\`prjct_spec_create\`** \u2014 when the user describes WHAT they want to build / fix and WHY ("we need rate limiting", "the onboarding is broken"). Draft a spec with goal, eli10, stakes, acceptance_criteria, scope, out_of_scope, risks, test_plan.
|
|
585
|
+
- **\`prjct_spec_audit\`** \u2014 before any code: dispatch three review subagents in PARALLEL (strategic / architecture / design). Persist verdicts via \`prjct_spec_record_review\`. All three pass \u2192 spec auto-promotes draft \u2192 reviewed.
|
|
586
|
+
- **\`prjct_spec_link_task\`** \u2014 when the user starts implementing, link the task to the spec so ship can gate.
|
|
587
|
+
- **\`prjct_spec_ship\`** \u2014 after merge, mark the spec shipped + record the PR number.
|
|
588
|
+
|
|
589
|
+
Skip the SDD flow only for: routine captures, single-file fixes, doc tweaks, conversational Q&A. If work touches >1 file, ships to users, or takes >30 min \u2014 default to spec first.
|
|
547
590
|
|
|
548
591
|
## What's here
|
|
549
|
-
|
|
550
|
-
- **
|
|
592
|
+
|
|
593
|
+
- **Specs** \u2014 first-class SDD artifacts (Goal/Acceptance/Scope/Risks). Tools: \`prjct_spec_*\`.
|
|
594
|
+
- **Memory** (facts, decisions, learnings, gotchas, patterns, anti-patterns, insights, questions, sources, people, okrs, shipped work, inbox, **spec**). Save/recall via memory tools.
|
|
595
|
+
- **Session + task state** via the session and project tools. Tasks accept a \`linked_spec_id\` for the SDD gate.
|
|
551
596
|
- **Workflows** registered in this project (can be run, listed, edited).
|
|
552
597
|
- **Code intelligence** helpers (impact, related context) for navigating repos.
|
|
553
598
|
- **Patterns** detected by analysis.
|
|
554
599
|
|
|
555
600
|
## Gotchas
|
|
601
|
+
|
|
602
|
+
- Recognize intent in any language (es/en) \u2014 the verbs are language-agnostic.
|
|
556
603
|
- Memory is best-effort \u2014 never assume recall returned everything; it's a query, not a lookup.
|
|
557
604
|
- Topic keys are free-form strings; don't invent new vocabularies when existing ones fit.
|
|
558
605
|
- Not every project defines every memory type \u2014 if one is empty, that's fine.
|
|
559
|
-
- Saving a secret-looking string is refused by default. Re-save with a scrubbed version
|
|
606
|
+
- Saving a secret-looking string is refused by default. Re-save with a scrubbed version.
|
|
607
|
+
- A spec without acceptance_criteria is just an inbox item \u2014 fill them.`;function qr(){let r=new Ai({name:"prjct",version:"1.0.0"},{instructions:Ci});return Or(r),Wr(r),Ar(r),Hr(r),Ds(r),Br(r),r}c(qr,"createServer");async function Ii(){let r=qr(),t=new Ni;await r.connect(t)}c(Ii,"main");Ii().catch(r=>{console.error("prjct MCP server failed:",r),process.exit(1)});
|