prjct-cli 1.56.12 → 2.0.0-alpha.12

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/dist/cli/jira.mjs DELETED
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __createRequire } from 'module';
3
- import { fileURLToPath as __fileURLToPath } from 'url';
4
- import { dirname as __pathDirname } from 'path';
5
- var require = __createRequire(import.meta.url);
6
- var __filename = __fileURLToPath(import.meta.url);
7
- var __dirname = __pathDirname(__filename);
8
- var Dt=Object.defineProperty;var o=(t,e)=>Dt(t,"name",{value:e,configurable:!0}),y=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,r)=>(typeof require<"u"?require:e)[r]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});import jt from"node:fs/promises";import xt from"node:os";import nt from"node:path";import gt from"node:fs";import ht from"node:path";import{z as l}from"zod";var S={create(t,e){class r extends Error{static{o(this,"TypedError")}errorName;data;isOperational=!0;constructor(i){let a=e.parse(i);super(`${t}: ${JSON.stringify(a)}`),this.name=t,this.errorName=t,this.data=a,Error.captureStackTrace?.(this,this.constructor)}static throw(i){throw new r(i)}static is(i){return i instanceof r&&i.errorName===t}static create(i){return new r(i)}}return r}},ue=S.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),le=S.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),pe=S.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),de=S.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),fe=S.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),me=S.create("SyncError",l.object({projectId:l.string().optional(),operation:l.enum(["push","pull","auth","connect"]),reason:l.string()}));import K from"node:fs";import V from"node:path";function $t(t){return t instanceof Error&&"code"in t}o($t,"isNodeError");function _(t){return $t(t)&&t.code==="ENOENT"}o(_,"isNotFoundError");function x(t){return t instanceof Error?t.message:typeof t=="string"?t:"Unknown error"}o(x,"getErrorMessage");var L=null,It=null,A=null;function ft(){if(A)return A;let t=__dirname;for(let e=0;e<5;e++){let r=V.join(t,"package.json");if(K.existsSync(r))try{if(JSON.parse(K.readFileSync(r,"utf-8")).name==="prjct-cli")return A=t,t}catch{}t=V.dirname(t)}return A=V.join(__dirname,"..","..",".."),A}o(ft,"getPackageRoot");function Z(){if(L)return L;try{let t=V.join(ft(),"package.json"),e=JSON.parse(K.readFileSync(t,"utf-8"));return L=e.version,It=e,L}catch(t){return console.error("Failed to read version from package.json:",x(t)),"0.0.0"}}o(Z,"getVersion");var Pe=Z(),Q=ft();var tt=null,mt=!1;function Jt(){if(mt)return tt;mt=!0;let t=ht.join(Q,"dist","templates.json");try{let e=gt.readFileSync(t,"utf-8");return tt=JSON.parse(e),tt}catch{return null}}o(Jt,"loadBundle");function yt(t){let e=Jt();if(e?.[t])return e[t];let r=ht.join(Q,"templates",t);try{return gt.readFileSync(r,"utf-8")}catch{return null}}o(yt,"getTemplateContent");import{exec as Lt,execFile as Vt}from"node:child_process";import{promisify as vt}from"node:util";var Fe=vt(Lt),wt=vt(Vt);import et from"node:fs/promises";import qt from"node:path";async function q(t,e,r=2){let n=qt.dirname(t);await et.mkdir(n,{recursive:!0});let i=JSON.stringify(e,null,r);await et.writeFile(t,i,"utf-8")}o(q,"writeJson");async function rt(t){try{return(await et.stat(t)).isDirectory()}catch(e){if(_(e))return!1;throw e}}o(rt,"dirExists");var it={command:"npx",args:["-y","@upstash/context7-mcp@latest"]},k=null;function Ut(){let t=yt("mcp-config.json");if(!t)return{mcpServers:{context7:it}};try{return JSON.parse(t)}catch{return{mcpServers:{context7:it}}}}o(Ut,"parseTemplateConfig");function St(){return Ut().mcpServers?.context7||it}o(St,"getContext7Config");function Et(){return process.env.PRJCT_CONTEXT7_CONFIG?process.env.PRJCT_CONTEXT7_CONFIG:process.env.NODE_ENV==="test"?nt.join(xt.tmpdir(),"prjct-context7-test","mcp.json"):nt.join(xt.homedir(),".claude","mcp.json")}o(Et,"getConfigPath");async function Pt(t){try{let e=await jt.readFile(t,"utf-8");return JSON.parse(e)}catch(e){if(_(e))return{};throw e}}o(Pt,"readConfig");async function Wt(){if(process.env.PRJCT_SKIP_CONTEXT7_SMOKE==="1"||process.env.NODE_ENV==="test")return;let t=St(),e=[...t.args||[],"--help"];await wt(t.command||"npx",e,{timeout:15e3})}o(Wt,"runSmokeCheck");var ot=class{static{o(this,"Context7Service")}async install(){let e=Et(),r=nt.dirname(e);await jt.mkdir(r,{recursive:!0});let n=await Pt(e),i=n.mcpServers||{};return i.context7=St(),n.mcpServers=i,await q(e,n),k=null,{installed:!0,verified:!1,configPath:e,message:"Context7 MCP configured"}}async verify(){if(k&&Date.now()-k.at<3e5)return k.status;let e=Et(),i=((await Pt(e)).mcpServers||{}).context7;if(!i?.command||!Array.isArray(i.args)||i.args.length===0)return{installed:!1,verified:!1,configPath:e,message:"Context7 MCP not configured in ~/.claude/mcp.json"};try{await Wt();let a={installed:!0,verified:!0,configPath:e};return k={at:Date.now(),status:a},a}catch(a){let s={installed:!0,verified:!1,configPath:e,message:`Context7 smoke check failed: ${x(a)}`};return k={at:Date.now(),status:s},s}}async ensureReady(){await this.install();let e=await this.verify();if(!e.verified){let r=e.message||"Context7 MCP is required but not ready. Run `prjct start` to repair configuration.";throw new Error(r)}return e}},kt=new ot;import Ct from"node:fs";import B from"node:path";function Ht(){return typeof globalThis<"u"&&"Bun"in globalThis?"bun":"node"}o(Ht,"detectRuntime");function Tt(){return Ht()==="bun"}o(Tt,"isBun");function Xt(t){if(Tt()){let{Database:i}=y("bun:sqlite");return new i(t,{create:!0})}let e=y("better-sqlite3"),r=new e(t),n=r.exec.bind(r);return r.run=i=>n(i),r}o(Xt,"openDatabase");var st=class{static{o(this,"SystemDatabase")}db=null;dbPath;constructor(){let e=process.env.PRJCT_CLI_HOME?.trim(),r=e?B.resolve(e):B.join(y("node:os").homedir(),".prjct-cli");this.dbPath=B.join(r,"system.db")}getDb(){if(this.db)return this.db;let e=B.dirname(this.dbPath);Ct.existsSync(e)||Ct.mkdirSync(e,{recursive:!0});let r=Xt(this.dbPath);return r.run("PRAGMA journal_mode = WAL"),r.run("PRAGMA synchronous = NORMAL"),r.run("PRAGMA cache_size = -1000"),r.run("PRAGMA temp_store = MEMORY"),this.runMigrations(r),this.db=r,r}runMigrations(e){e.run(`
9
- CREATE TABLE IF NOT EXISTS _system_migrations (
10
- version INTEGER PRIMARY KEY,
11
- name TEXT NOT NULL,
12
- applied_at TEXT NOT NULL
13
- )
14
- `);let r=new Set(e.prepare("SELECT version FROM _system_migrations").all().map(i=>i.version)),n=[{version:1,name:"mcp-health-table",up:o(i=>{i.run(`
15
- CREATE TABLE mcp_health (
16
- provider TEXT PRIMARY KEY,
17
- status TEXT NOT NULL,
18
- last_checked TEXT NOT NULL,
19
- last_error TEXT,
20
- token_version TEXT,
21
- config_valid INTEGER NOT NULL DEFAULT 0,
22
- oauth_valid INTEGER NOT NULL DEFAULT 0,
23
- updated_at TEXT NOT NULL
24
- )
25
- `)},"up")}];for(let i of n)r.has(i.version)||(i.up(e),e.prepare("INSERT INTO _system_migrations (version, name, applied_at) VALUES (?, ?, ?)").run(i.version,i.name,new Date().toISOString()))}getMcpHealth(e){return this.getDb().prepare("SELECT * FROM mcp_health WHERE provider = ?").get(e)??null}setMcpHealth(e,r){let n=this.getDb(),i=new Date().toISOString();n.prepare(`
26
- INSERT OR REPLACE INTO mcp_health
27
- (provider, status, last_checked, last_error, token_version, config_valid, oauth_valid, updated_at)
28
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
29
- `).run(e,r.status,i,r.lastError??null,r.tokenVersion??null,r.configValid?1:0,r.oauthValid?1:0,i)}clearMcpHealth(e){this.getDb().prepare("DELETE FROM mcp_health WHERE provider = ?").run(e)}close(){this.db&&(this.db.close(),this.db=null)}},T=new st;import g from"node:fs/promises";import C from"node:os";import d from"node:path";var N="mcp-remote@0.1.38";function Gt(){try{let t=d.dirname(y.resolve("prjct-cli/package.json"));return{command:"node",args:[d.join(t,"dist","mcp","server.mjs")],description:"prjct data layer (memories, analysis, files, workflows)"}}catch{return{command:"npx",args:["-y","prjct-cli","mcp"],description:"prjct data layer (memories, analysis, files, workflows)"}}}o(Gt,"getPrjctMcpConfig");var at={prjct:Gt(),linear:{command:"npx",args:["-y",N,"https://mcp.linear.app/mcp"],description:"Linear MCP server (OAuth)"},jira:{command:"npx",args:["-y",N,"https://mcp.atlassian.com/v1/mcp"],description:"Atlassian MCP server for Jira (OAuth)"}},P={linear:`npx -y ${N} https://mcp.linear.app/mcp`,jira:`npx -y ${N} https://mcp.atlassian.com/v1/mcp`};function b(){return N.split("@")[1]}o(b,"getMcpRemoteVersion");function F(){return process.env.PRJCT_TEST_MODE==="1"?d.join(C.tmpdir(),"prjct-context7-test","mcp.json"):d.join(C.homedir(),".claude","mcp.json")}o(F,"getClaudeMcpConfigPath");async function ct(){if(process.env.PRJCT_TEST_MODE==="1")return[{provider:"claude",configPath:F(),mergeIntoExisting:!1}];let t=C.homedir(),e=[],r=d.join(t,".claude");await rt(r)&&e.push({provider:"claude",configPath:d.join(r,"mcp.json"),mergeIntoExisting:!1});let n=d.join(t,".gemini");return await rt(n)&&e.push({provider:"gemini",configPath:d.join(n,"settings.json"),mergeIntoExisting:!0}),e}o(ct,"getActiveMcpConfigPaths");async function bt(t,e){let r=await ct();return Promise.all(r.map(async n=>{let i=await Yt(t,e,n.configPath);return{provider:n.provider,...i}}))}o(bt,"upsertMcpServerAll");async function R(t){let e=await ct(),r=await Promise.all(e.map(async n=>({provider:n.provider,configured:await zt(t,n.configPath),path:n.configPath})));return{configured:r.some(n=>n.configured),providers:r}}o(R,"hasMcpServerAny");async function U(t){let e;try{e=await g.readdir(t)}catch{return{valid:!1,reason:"directory not found"}}if(e.length===0)return{valid:!1,reason:"directory empty"};let r=e.filter(n=>n.endsWith("_tokens.json")||n.endsWith(".json"));if(r.length===0)return{valid:!1,reason:"no token files found"};for(let n of r){let i=d.join(t,n);try{let a=await g.readFile(i,"utf-8"),s=JSON.parse(a);if(s.access_token||s.refresh_token)return{valid:!0}}catch{return{valid:!1,reason:`corrupt JSON in ${n}`}}}return{valid:!1,reason:"no valid tokens (missing access_token/refresh_token)"}}o(U,"validateTokenFiles");async function W(){let t=b(),e=d.join(C.homedir(),".mcp-auth"),r=d.join(e,`mcp-remote-${t}`);if((await U(r)).valid)return{migrated:!1,from:null,to:r};let i;try{i=await g.readdir(e)}catch{return{migrated:!1,from:null,to:r}}let a=i.filter(s=>s.startsWith("mcp-remote-")&&s!==`mcp-remote-${t}`).sort().reverse();for(let s of a){let c=d.join(e,s);if((await U(c)).valid){await g.mkdir(r,{recursive:!0});let p=await g.readdir(c);for(let u of p)await g.copyFile(d.join(c,u),d.join(r,u));return{migrated:!0,from:c,to:r}}}return{migrated:!1,from:null,to:r}}o(W,"migrateOAuthTokens");async function H(t){if((await U(t)).valid)return!1;try{let r=await g.readdir(t);for(let n of r)await g.unlink(d.join(t,n));return await g.rmdir(t),!0}catch{return!1}}o(H,"cleanCorruptedTokens");async function X(t){let e=[],r=!1,n=await ct();for(let i of n){let a=await ut(i.configPath),s=a.mcpServers?.[t];if(!s){e.push(`${i.provider}: no ${t} entry in mcp.json`);continue}let c=at[t];if(s.command!==c.command||JSON.stringify(s.args)!==JSON.stringify(c.args)){e.push(`${i.provider}: ${t} config doesn't match preset (stale version?)`);let m={...a.mcpServers||{}};m[t]=c,a.mcpServers=m,await Mt(a,i.configPath),r=!0}}return{valid:e.length===0,issues:e,autoFixed:r}}o(X,"validateMcpConfig");async function G(t){let e=b(),r=d.join(C.homedir(),".mcp-auth"),n=d.join(r,`mcp-remote-${e}`),i=!1,a=!1,s=await U(n);if(s.valid)return T.setMcpHealth(t,{status:"healthy",tokenVersion:e,oauthValid:!0}),{ready:!0,tokenDir:n,hint:"OAuth tokens verified \u2014 restart your AI client.",validated:!0,migrated:!1,cleaned:!1};s.reason&&s.reason!=="directory not found"&&s.reason!=="directory empty"&&(a=await H(n));let c=await W();if(c.migrated)return i=!0,T.setMcpHealth(t,{status:"healthy",tokenVersion:e,oauthValid:!0}),{ready:!0,tokenDir:n,hint:`Tokens migrated from ${d.basename(c.from)} \u2014 restart your AI client.`,validated:!0,migrated:!0,cleaned:a};let m=[];try{m=(await g.readdir(r)).filter(v=>v.startsWith("mcp-remote-")&&v!==`mcp-remote-${e}`)}catch{}let p=a?`Previous tokens were invalid and cleaned. Run in a terminal: ${P[t]}`:m.length>0?`Legacy tokens found (${m.join(", ")}) but invalid. Run: ${P[t]}`:`OAuth not completed. Run in a terminal: ${P[t]}`;return T.setMcpHealth(t,{status:"unhealthy",lastError:p,tokenVersion:e,oauthValid:!1}),{ready:!1,tokenDir:null,hint:p,validated:!1,migrated:!1,cleaned:a}}o(G,"checkOAuthTokens");async function Rt(){let t=b(),e=d.join(C.homedir(),".mcp-auth"),r=[],n;try{n=await g.readdir(e)}catch{return{expectedVersion:t,dirs:r}}let i=n.filter(a=>a.startsWith("mcp-remote-")).sort();for(let a of i){let s=d.join(e,a),c=a.replace("mcp-remote-",""),m=c===t,p=[];try{if(!(await g.stat(s)).isDirectory())continue;p=await g.readdir(s)}catch{continue}let u=p.find(E=>E.endsWith("_tokens.json"))??null,v=!1,h,M=!1,O=!1,z;if(u)try{let E=await g.readFile(d.join(s,u),"utf-8"),w=JSON.parse(E);M=!!w.access_token,O=!!w.refresh_token,w.expires_in&&(z=w.expires_in),v=M||O,v||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${u}`}else{let E=p.filter(w=>w.endsWith(".json"));if(E.length===0)h="no token files found";else{for(let w of E)try{let Ft=await g.readFile(d.join(s,w),"utf-8"),J=JSON.parse(Ft);J.access_token&&(M=!0),J.refresh_token&&(O=!0),J.expires_in&&(z=J.expires_in)}catch{h=`corrupt JSON in ${w}`}v=M||O,!v&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}r.push({version:c,path:s,isCurrent:m,files:p,tokenFile:u,valid:v,reason:h,hasAccessToken:M,hasRefreshToken:O,expiresIn:z})}return{expectedVersion:t,dirs:r}}o(Rt,"scanTokenDirectories");async function ut(t=F()){try{let e=await g.readFile(t,"utf-8");return JSON.parse(e)}catch(e){let r=x(e).toLowerCase();if(r.includes("no such file")||r.includes("enoent"))return{};throw new Error(`Failed to read MCP config at ${t}: ${x(e)}`)}}o(ut,"readMcpConfig");async function Mt(t,e=F()){await q(e,t)}o(Mt,"writeMcpConfig");async function Yt(t,e,r=F()){let n=await ut(r),i={...n.mcpServers||{}},a=i[t];i[t]=e,n.mcpServers=i;let s=JSON.stringify(a)!==JSON.stringify(e);return await Mt(n,r),{path:r,changed:s}}o(Yt,"upsertMcpServer");async function zt(t,e=F()){return!!(await ut(e)).mcpServers?.[t]}o(zt,"hasMcpServer");function Kt(){return"---"}o(Kt,"mdHeader");function Zt(){return`---
30
- prjct v${Z()}`}o(Zt,"mdFooter");function Y(...t){return Qt(Kt(),...t.filter(Boolean),Zt())}o(Y,"mdOutput");function D(t,e){let r=`| ${t.join(" | ")} |`,n=`|${t.map(()=>"---").join("|")}|`,i=e.map(a=>`| ${a.join(" | ")} |`);return[r,n,...i].join(`
31
- `)}o(D,"mdTable");function Ot(t,e=""){return`\`\`\`${e}
32
- ${t}
33
- \`\`\``}o(Ot,"mdCodeBlock");function f(t,e){return`> **${{success:"OK",warn:"WARNING",error:"ERROR",info:"INFO"}[t]}:** ${e}`}o(f,"mdCallout");function $(t,e,r=3){return`### ${t}
34
- ${e}`}o($,"mdSection");function _t(t,e=!1){return t.map((r,n)=>e?`${n+1}. ${r}`:`- ${r}`).join(`
35
- `)}o(_t,"mdList");function Qt(...t){return t.filter(Boolean).join(`
36
-
37
- `)}o(Qt,"mdJoin");function At(t=process.argv){let e=t.slice(2),r=e.indexOf("--json"),n=r!==-1;n&&e.splice(r,1);let i=e.indexOf("--md"),a=i!==-1;a&&e.splice(i,1);let[s,...c]=e;return{command:s,commandArgs:c,jsonMode:n,mdMode:a}}o(At,"parseCliArgs");var{command:lt,commandArgs:pt,jsonMode:Nt,mdMode:dt}=At();function j(t){if(Nt){console.log(JSON.stringify(t,null,2));return}if(typeof t=="string"){console.log(t);return}console.log(JSON.stringify(t,null,2))}o(j,"output");function I(t,e=1){console.error(Nt?JSON.stringify({error:t}):`Error: ${t}`),process.exit(e)}o(I,"error");async function te(){let t=b(),e=y("node:path").join(y("node:os").homedir(),".mcp-auth",`mcp-remote-${t}`),r=await X("jira"),n=await H(e),i=await bt("jira",at.jira),a=await W(),s=await G("jira");if(T.setMcpHealth("jira",{status:s.ready?"healthy":"unhealthy",tokenVersion:t,configValid:!0,oauthValid:s.ready,lastError:s.ready?null:s.hint}),dt){let c=[];c.push("## Jira MCP Setup"),r.autoFixed&&c.push(f("warn","MCP config was outdated and has been auto-fixed.")),n&&c.push(f("warn","Corrupted token files were cleaned up."));let m=i.map(p=>[p.provider,p.path,p.changed?"updated":"unchanged"]);c.push($("MCP Config",D(["Provider","Path","Status"],m))),a.migrated&&c.push(f("success",`Tokens migrated from ${y("node:path").basename(a.from)}.`)),s.ready?c.push(f("success","Jira MCP is ready. Restart your AI client to activate.")):(c.push(f("info","OAuth required \u2014 complete the steps below.")),c.push($("Next Steps",_t([`Open a NEW terminal and run:
38
- ${Ot(P.jira,"bash")}`,"Complete OAuth authorization in the browser.","Run `prjct jira verify --md` to confirm tokens were saved.","Restart your AI client. Jira MCP tools will be ready."],!0)))),console.log(Y(...c));return}j({success:!0,provider:"jira",mode:"mcp",configAutoFixed:r.autoFixed,tokensCleaned:n,tokensMigrated:a.migrated,oauthReady:s.ready,installedIn:i.map(c=>({provider:c.provider,path:c.path,updated:c.changed})),nextSteps:s.ready?["Restart your AI client \u2014 Jira MCP is ready."]:[`STEP 1 (done): MCP config written to ${i.map(c=>c.provider).join(", ")}.`,`STEP 2: Open a NEW terminal and run: ${P.jira}`,"STEP 2: A browser will open for OAuth \u2014 complete the authorization.","STEP 3: Run `prjct jira verify` to confirm tokens were saved.","STEP 4: Restart your AI client. Jira MCP tools will be ready."],authCommand:P.jira})}o(te,"setup");async function ee(){let t=await Rt(),e=await X("jira"),r=await R("jira"),n=await W(),i=b(),a=y("node:path").join(y("node:os").homedir(),".mcp-auth",`mcp-remote-${i}`),s=!1,c=t.dirs.find(u=>u.isCurrent);c&&!c.valid&&c.files.length>0&&!n.migrated&&(s=await H(a));let m=await G("jira"),p={installed:!1,verified:!1};try{p=await kt.verify()}catch(u){p={installed:!1,verified:!1,message:`check failed: ${u instanceof Error?u.message:"unknown"}`}}if(dt){let u=[];if(u.push("## Jira MCP Verification"),r.configured?e.autoFixed&&u.push(f("warn","MCP config was outdated and has been auto-fixed.")):u.push(f("error","Jira MCP not configured. Run `prjct jira setup` first.")),t.dirs.length===0)u.push(f("error","No token directories found in `~/.mcp-auth/`. OAuth has not been completed."));else{let v=t.dirs.map(h=>[`mcp-remote-${h.version}`,h.isCurrent?"yes":"no",h.valid?"valid":"invalid",h.tokenFile??"\u2014",h.reason??(h.valid?"OK":"\u2014")]);u.push($("Token Directories",D(["Directory","Current","Status","Token File","Details"],v)))}n.migrated&&u.push(f("success",`Tokens auto-migrated from ${y("node:path").basename(n.from)}.`)),s&&u.push(f("warn","Corrupted token files were cleaned up.")),p.installed?p.verified?u.push(f("success","Context7 MCP is healthy.")):u.push(f("warn",`Context7 MCP configured but not working: ${p.message??"smoke check failed"}. Run \`prjct sync\` to repair.`)):u.push(f("warn","Context7 MCP not configured. Run `prjct sync` to install.")),m.ready?u.push(f("success","READY \u2014 Jira OAuth tokens verified. Restart your AI client to activate.")):u.push(f("error",`NOT READY \u2014 ${m.hint}`)),console.log(Y(...u));return}j({provider:"jira",command:"verify",expectedVersion:t.expectedVersion,dirs:t.dirs.map(u=>({version:u.version,isCurrent:u.isCurrent,valid:u.valid,tokenFile:u.tokenFile,reason:u.reason,hasAccessToken:u.hasAccessToken,hasRefreshToken:u.hasRefreshToken})),configValid:e.valid,configAutoFixed:e.autoFixed,migrated:n.migrated,migratedFrom:n.from,cleaned:s,ready:m.ready,hint:m.hint,context7:{installed:p.installed,verified:p.verified,message:p.message}})}o(ee,"verify");async function re(){let t=await R("jira"),e=await X("jira"),r=t.configured?await G("jira"):null;if(dt){let n=[];n.push("## Jira MCP Status");let i=[["MCP configured",t.configured?"yes":"no"],["Config valid",e.valid?"yes":`no (${e.issues.join(", ")})`]];r&&(i.push(["OAuth tokens",r.ready?"valid":"missing/invalid"]),r.migrated&&i.push(["Tokens migrated","yes"]),r.cleaned&&i.push(["Corrupted cleaned","yes"]));let a=t.providers.map(s=>[s.provider,s.configured?"yes":"no",s.path]);n.push(D(["Check","Result"],i)),n.push($("Providers",D(["Provider","Configured","Path"],a))),t.configured?r?.ready?n.push(f("success","Jira MCP is healthy. Restart your AI client if tools are not visible.")):n.push(f("warn",r?.hint??"OAuth tokens not found.")):n.push(f("error","Jira MCP not configured. Run `prjct jira setup` to configure.")),e.autoFixed&&n.push(f("info","MCP config was auto-fixed during this check.")),console.log(Y(...n));return}j({provider:"jira",mode:"mcp",configured:t.configured,configValid:e.valid,configAutoFixed:e.autoFixed,oauthReady:r?.ready??!1,oauthValidated:r?.validated??!1,oauthMigrated:r?.migrated??!1,oauthCleaned:r?.cleaned??!1,providers:t.providers,hint:t.configured?r?.hint??"":"Run `prjct jira setup` to configure Jira MCP."})}o(re,"status");async function ne(t,e,r){let{configured:n}=await R("jira");n||I("Jira MCP is not configured. Run `prjct jira setup` first.");let i={success:!0,provider:"jira",mode:"mcp",delegated:!0,command:t,args:e,hint:r?.hint??"Run this operation using Jira MCP tools in your current AI client session.",nextSteps:["Open your MCP-enabled AI client/session.",`Execute the Jira MCP operation for "${t}".`]};r?.jql&&(i.jql=r.jql),r?.scope&&(i.scope=r.scope),j(i)}o(ne,"runMcpOperation");async function ie(t){let{configured:e}=await R("jira");e||I("Jira MCP is not configured. Run `prjct jira setup` first."),j({success:!0,provider:"jira",mode:"mcp",delegated:!0,command:"sprint",scope:"active_sprint",args:t,jql:"sprint = currentSprint() AND assignee = currentUser() ORDER BY priority DESC",hint:"Fetch your issues in the active sprint via Jira MCP tools.",nextSteps:["Use the Jira MCP search tool with the JQL above to list your active sprint issues.","Issues returned include sprint metadata (sprint name, start/end dates)."]})}o(ie,"sprintOperation");async function oe(t){let{configured:e}=await R("jira");e||I("Jira MCP is not configured. Run `prjct jira setup` first."),j({success:!0,provider:"jira",mode:"mcp",delegated:!0,command:"backlog",scope:"backlog",args:t,jql:"sprint is EMPTY AND assignee = currentUser() AND statusCategory != Done ORDER BY priority DESC",hint:"Fetch your backlog issues (not in any sprint) via Jira MCP tools.",nextSteps:["Use the Jira MCP search tool with the JQL above to list your backlog issues.","Backlog issues have no sprint assigned \u2014 differentiate from sprint issues by the sprint field being empty."]})}o(oe,"backlogOperation");async function se(){try{switch(lt){case"setup":await te();break;case"verify":await ee();break;case"status":await re();break;case"help":case"--help":case"-h":case void 0:j({usage:"prjct jira <command>",commands:{setup:"Configure Jira MCP server",verify:"Verify OAuth tokens after completing authorization",status:"Check Jira MCP configuration",sprint:"List your issues in the active sprint (MCP)",backlog:"List your backlog issues not in any sprint (MCP)",sync:"Delegate issue sync via MCP tools",list:"Delegate issue listing via MCP tools",get:"Delegate issue retrieval via MCP tools",create:"Delegate issue creation via MCP tools",update:"Delegate issue update via MCP tools",start:"Delegate status transition to in-progress via MCP tools",done:"Delegate status transition to done via MCP tools",transition:"Delegate workflow transition via MCP tools"},note:"Jira is MCP-only. sprint/backlog provide JQL for your AI client MCP session."});break;case"sprint":await ie(pt);break;case"backlog":await oe(pt);break;case"sync":case"start":case"done":case"list":case"get":case"create":case"update":case"transition":case"comment":case"projects":case"boards":await ne(lt,pt);break;default:I(`Unknown command: ${lt}. Use --help to see available commands.`)}}catch(t){I(x(t))}}o(se,"main");se();
@@ -1,38 +0,0 @@
1
- #!/usr/bin/env node
2
- import { createRequire as __createRequire } from 'module';
3
- import { fileURLToPath as __fileURLToPath } from 'url';
4
- import { dirname as __pathDirname } from 'path';
5
- var require = __createRequire(import.meta.url);
6
- var __filename = __fileURLToPath(import.meta.url);
7
- var __dirname = __pathDirname(__filename);
8
- var Ne=Object.defineProperty;var o=(e,t)=>Ne(e,"name",{value:t,configurable:!0}),y=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import Pe from"node:fs/promises";import we from"node:os";import re from"node:path";import me from"node:fs";import ge from"node:path";import{z as l}from"zod";var S={create(e,t){class r extends Error{static{o(this,"TypedError")}errorName;data;isOperational=!0;constructor(i){let a=t.parse(i);super(`${e}: ${JSON.stringify(a)}`),this.name=e,this.errorName=e,this.data=a,Error.captureStackTrace?.(this,this.constructor)}static throw(i){throw new r(i)}static is(i){return i instanceof r&&i.errorName===e}static create(i){return new r(i)}}return r}},at=S.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),ct=S.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),ut=S.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),lt=S.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),dt=S.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),pt=S.create("SyncError",l.object({projectId:l.string().optional(),operation:l.enum(["push","pull","auth","connect"]),reason:l.string()}));import K from"node:fs";import L from"node:path";function $e(e){return e instanceof Error&&"code"in e}o($e,"isNodeError");function M(e){return $e(e)&&e.code==="ENOENT"}o(M,"isNotFoundError");function x(e){return e instanceof Error?e.message:typeof e=="string"?e:"Unknown error"}o(x,"getErrorMessage");var I=null,De=null,O=null;function pe(){if(O)return O;let e=__dirname;for(let t=0;t<5;t++){let r=L.join(e,"package.json");if(K.existsSync(r))try{if(JSON.parse(K.readFileSync(r,"utf-8")).name==="prjct-cli")return O=e,e}catch{}e=L.dirname(e)}return O=L.join(__dirname,"..","..",".."),O}o(pe,"getPackageRoot");function Y(){if(I)return I;try{let e=L.join(pe(),"package.json"),t=JSON.parse(K.readFileSync(e,"utf-8"));return I=t.version,De=t,I}catch(e){return console.error("Failed to read version from package.json:",x(e)),"0.0.0"}}o(Y,"getVersion");var xt=Y(),Z=pe();var Q=null,fe=!1;function Ie(){if(fe)return Q;fe=!0;let e=ge.join(Z,"dist","templates.json");try{let t=me.readFileSync(e,"utf-8");return Q=JSON.parse(t),Q}catch{return null}}o(Ie,"loadBundle");function he(e){let t=Ie();if(t?.[e])return t[e];let r=ge.join(Z,"templates",e);try{return me.readFileSync(r,"utf-8")}catch{return null}}o(he,"getTemplateContent");import{exec as Le,execFile as Ve}from"node:child_process";import{promisify as ye}from"node:util";var At=ye(Le),ve=ye(Ve);import ee from"node:fs/promises";import Je from"node:path";async function V(e,t,r=2){let n=Je.dirname(e);await ee.mkdir(n,{recursive:!0});let i=JSON.stringify(t,null,r);await ee.writeFile(e,i,"utf-8")}o(V,"writeJson");async function te(e){try{return(await ee.stat(e)).isDirectory()}catch(t){if(M(t))return!1;throw t}}o(te,"dirExists");var ne={command:"npx",args:["-y","@upstash/context7-mcp@latest"]},T=null;function Be(){let e=he("mcp-config.json");if(!e)return{mcpServers:{context7:ne}};try{return JSON.parse(e)}catch{return{mcpServers:{context7:ne}}}}o(Be,"parseTemplateConfig");function Se(){return Be().mcpServers?.context7||ne}o(Se,"getContext7Config");function xe(){return process.env.PRJCT_CONTEXT7_CONFIG?process.env.PRJCT_CONTEXT7_CONFIG:process.env.NODE_ENV==="test"?re.join(we.tmpdir(),"prjct-context7-test","mcp.json"):re.join(we.homedir(),".claude","mcp.json")}o(xe,"getConfigPath");async function Ee(e){try{let t=await Pe.readFile(e,"utf-8");return JSON.parse(t)}catch(t){if(M(t))return{};throw t}}o(Ee,"readConfig");async function We(){if(process.env.PRJCT_SKIP_CONTEXT7_SMOKE==="1"||process.env.NODE_ENV==="test")return;let e=Se(),t=[...e.args||[],"--help"];await ve(e.command||"npx",t,{timeout:15e3})}o(We,"runSmokeCheck");var ie=class{static{o(this,"Context7Service")}async install(){let t=xe(),r=re.dirname(t);await Pe.mkdir(r,{recursive:!0});let n=await Ee(t),i=n.mcpServers||{};return i.context7=Se(),n.mcpServers=i,await V(t,n),T=null,{installed:!0,verified:!1,configPath:t,message:"Context7 MCP configured"}}async verify(){if(T&&Date.now()-T.at<3e5)return T.status;let t=xe(),i=((await Ee(t)).mcpServers||{}).context7;if(!i?.command||!Array.isArray(i.args)||i.args.length===0)return{installed:!1,verified:!1,configPath:t,message:"Context7 MCP not configured in ~/.claude/mcp.json"};try{await We();let a={installed:!0,verified:!0,configPath:t};return T={at:Date.now(),status:a},a}catch(a){let s={installed:!0,verified:!1,configPath:t,message:`Context7 smoke check failed: ${x(a)}`};return T={at:Date.now(),status:s},s}}async ensureReady(){await this.install();let t=await this.verify();if(!t.verified){let r=t.message||"Context7 MCP is required but not ready. Run `prjct start` to repair configuration.";throw new Error(r)}return t}},Te=new ie;import Ce from"node:fs";import J from"node:path";function Ue(){return typeof globalThis<"u"&&"Bun"in globalThis?"bun":"node"}o(Ue,"detectRuntime");function ke(){return Ue()==="bun"}o(ke,"isBun");function He(e){if(ke()){let{Database:i}=y("bun:sqlite");return new i(e,{create:!0})}let t=y("better-sqlite3"),r=new t(e),n=r.exec.bind(r);return r.run=i=>n(i),r}o(He,"openDatabase");var oe=class{static{o(this,"SystemDatabase")}db=null;dbPath;constructor(){let t=process.env.PRJCT_CLI_HOME?.trim(),r=t?J.resolve(t):J.join(y("node:os").homedir(),".prjct-cli");this.dbPath=J.join(r,"system.db")}getDb(){if(this.db)return this.db;let t=J.dirname(this.dbPath);Ce.existsSync(t)||Ce.mkdirSync(t,{recursive:!0});let r=He(this.dbPath);return r.run("PRAGMA journal_mode = WAL"),r.run("PRAGMA synchronous = NORMAL"),r.run("PRAGMA cache_size = -1000"),r.run("PRAGMA temp_store = MEMORY"),this.runMigrations(r),this.db=r,r}runMigrations(t){t.run(`
9
- CREATE TABLE IF NOT EXISTS _system_migrations (
10
- version INTEGER PRIMARY KEY,
11
- name TEXT NOT NULL,
12
- applied_at TEXT NOT NULL
13
- )
14
- `);let r=new Set(t.prepare("SELECT version FROM _system_migrations").all().map(i=>i.version)),n=[{version:1,name:"mcp-health-table",up:o(i=>{i.run(`
15
- CREATE TABLE mcp_health (
16
- provider TEXT PRIMARY KEY,
17
- status TEXT NOT NULL,
18
- last_checked TEXT NOT NULL,
19
- last_error TEXT,
20
- token_version TEXT,
21
- config_valid INTEGER NOT NULL DEFAULT 0,
22
- oauth_valid INTEGER NOT NULL DEFAULT 0,
23
- updated_at TEXT NOT NULL
24
- )
25
- `)},"up")}];for(let i of n)r.has(i.version)||(i.up(t),t.prepare("INSERT INTO _system_migrations (version, name, applied_at) VALUES (?, ?, ?)").run(i.version,i.name,new Date().toISOString()))}getMcpHealth(t){return this.getDb().prepare("SELECT * FROM mcp_health WHERE provider = ?").get(t)??null}setMcpHealth(t,r){let n=this.getDb(),i=new Date().toISOString();n.prepare(`
26
- INSERT OR REPLACE INTO mcp_health
27
- (provider, status, last_checked, last_error, token_version, config_valid, oauth_valid, updated_at)
28
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
29
- `).run(t,r.status,i,r.lastError??null,r.tokenVersion??null,r.configValid?1:0,r.oauthValid?1:0,i)}clearMcpHealth(t){this.getDb().prepare("DELETE FROM mcp_health WHERE provider = ?").run(t)}close(){this.db&&(this.db.close(),this.db=null)}},k=new oe;import g from"node:fs/promises";import C from"node:os";import p from"node:path";var _="mcp-remote@0.1.38";function Xe(){try{let e=p.dirname(y.resolve("prjct-cli/package.json"));return{command:"node",args:[p.join(e,"dist","mcp","server.mjs")],description:"prjct data layer (memories, analysis, files, workflows)"}}catch{return{command:"npx",args:["-y","prjct-cli","mcp"],description:"prjct data layer (memories, analysis, files, workflows)"}}}o(Xe,"getPrjctMcpConfig");var se={prjct:Xe(),linear:{command:"npx",args:["-y",_,"https://mcp.linear.app/mcp"],description:"Linear MCP server (OAuth)"},jira:{command:"npx",args:["-y",_,"https://mcp.atlassian.com/v1/mcp"],description:"Atlassian MCP server for Jira (OAuth)"}},P={linear:`npx -y ${_} https://mcp.linear.app/mcp`,jira:`npx -y ${_} https://mcp.atlassian.com/v1/mcp`};function R(){return _.split("@")[1]}o(R,"getMcpRemoteVersion");function A(){return process.env.PRJCT_TEST_MODE==="1"?p.join(C.tmpdir(),"prjct-context7-test","mcp.json"):p.join(C.homedir(),".claude","mcp.json")}o(A,"getClaudeMcpConfigPath");async function ae(){if(process.env.PRJCT_TEST_MODE==="1")return[{provider:"claude",configPath:A(),mergeIntoExisting:!1}];let e=C.homedir(),t=[],r=p.join(e,".claude");await te(r)&&t.push({provider:"claude",configPath:p.join(r,"mcp.json"),mergeIntoExisting:!1});let n=p.join(e,".gemini");return await te(n)&&t.push({provider:"gemini",configPath:p.join(n,"settings.json"),mergeIntoExisting:!0}),t}o(ae,"getActiveMcpConfigPaths");async function Re(e,t){let r=await ae();return Promise.all(r.map(async n=>{let i=await Ge(e,t,n.configPath);return{provider:n.provider,...i}}))}o(Re,"upsertMcpServerAll");async function B(e){let t=await ae(),r=await Promise.all(t.map(async n=>({provider:n.provider,configured:await ze(e,n.configPath),path:n.configPath})));return{configured:r.some(n=>n.configured),providers:r}}o(B,"hasMcpServerAny");async function q(e){let t;try{t=await g.readdir(e)}catch{return{valid:!1,reason:"directory not found"}}if(t.length===0)return{valid:!1,reason:"directory empty"};let r=t.filter(n=>n.endsWith("_tokens.json")||n.endsWith(".json"));if(r.length===0)return{valid:!1,reason:"no token files found"};for(let n of r){let i=p.join(e,n);try{let a=await g.readFile(i,"utf-8"),s=JSON.parse(a);if(s.access_token||s.refresh_token)return{valid:!0}}catch{return{valid:!1,reason:`corrupt JSON in ${n}`}}}return{valid:!1,reason:"no valid tokens (missing access_token/refresh_token)"}}o(q,"validateTokenFiles");async function W(){let e=R(),t=p.join(C.homedir(),".mcp-auth"),r=p.join(t,`mcp-remote-${e}`);if((await q(r)).valid)return{migrated:!1,from:null,to:r};let i;try{i=await g.readdir(t)}catch{return{migrated:!1,from:null,to:r}}let a=i.filter(s=>s.startsWith("mcp-remote-")&&s!==`mcp-remote-${e}`).sort().reverse();for(let s of a){let c=p.join(t,s);if((await q(c)).valid){await g.mkdir(r,{recursive:!0});let d=await g.readdir(c);for(let u of d)await g.copyFile(p.join(c,u),p.join(r,u));return{migrated:!0,from:c,to:r}}}return{migrated:!1,from:null,to:r}}o(W,"migrateOAuthTokens");async function U(e){if((await q(e)).valid)return!1;try{let r=await g.readdir(e);for(let n of r)await g.unlink(p.join(e,n));return await g.rmdir(e),!0}catch{return!1}}o(U,"cleanCorruptedTokens");async function H(e){let t=[],r=!1,n=await ae();for(let i of n){let a=await ce(i.configPath),s=a.mcpServers?.[e];if(!s){t.push(`${i.provider}: no ${e} entry in mcp.json`);continue}let c=se[e];if(s.command!==c.command||JSON.stringify(s.args)!==JSON.stringify(c.args)){t.push(`${i.provider}: ${e} config doesn't match preset (stale version?)`);let m={...a.mcpServers||{}};m[e]=c,a.mcpServers=m,await be(a,i.configPath),r=!0}}return{valid:t.length===0,issues:t,autoFixed:r}}o(H,"validateMcpConfig");async function X(e){let t=R(),r=p.join(C.homedir(),".mcp-auth"),n=p.join(r,`mcp-remote-${t}`),i=!1,a=!1,s=await q(n);if(s.valid)return k.setMcpHealth(e,{status:"healthy",tokenVersion:t,oauthValid:!0}),{ready:!0,tokenDir:n,hint:"OAuth tokens verified \u2014 restart your AI client.",validated:!0,migrated:!1,cleaned:!1};s.reason&&s.reason!=="directory not found"&&s.reason!=="directory empty"&&(a=await U(n));let c=await W();if(c.migrated)return i=!0,k.setMcpHealth(e,{status:"healthy",tokenVersion:t,oauthValid:!0}),{ready:!0,tokenDir:n,hint:`Tokens migrated from ${p.basename(c.from)} \u2014 restart your AI client.`,validated:!0,migrated:!0,cleaned:a};let m=[];try{m=(await g.readdir(r)).filter(v=>v.startsWith("mcp-remote-")&&v!==`mcp-remote-${t}`)}catch{}let d=a?`Previous tokens were invalid and cleaned. Run in a terminal: ${P[e]}`:m.length>0?`Legacy tokens found (${m.join(", ")}) but invalid. Run: ${P[e]}`:`OAuth not completed. Run in a terminal: ${P[e]}`;return k.setMcpHealth(e,{status:"unhealthy",lastError:d,tokenVersion:t,oauthValid:!1}),{ready:!1,tokenDir:null,hint:d,validated:!1,migrated:!1,cleaned:a}}o(X,"checkOAuthTokens");async function je(){let e=R(),t=p.join(C.homedir(),".mcp-auth"),r=[],n;try{n=await g.readdir(t)}catch{return{expectedVersion:e,dirs:r}}let i=n.filter(a=>a.startsWith("mcp-remote-")).sort();for(let a of i){let s=p.join(t,a),c=a.replace("mcp-remote-",""),m=c===e,d=[];try{if(!(await g.stat(s)).isDirectory())continue;d=await g.readdir(s)}catch{continue}let u=d.find(E=>E.endsWith("_tokens.json"))??null,v=!1,h,j=!1,b=!1,z;if(u)try{let E=await g.readFile(p.join(s,u),"utf-8"),w=JSON.parse(E);j=!!w.access_token,b=!!w.refresh_token,w.expires_in&&(z=w.expires_in),v=j||b,v||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${u}`}else{let E=d.filter(w=>w.endsWith(".json"));if(E.length===0)h="no token files found";else{for(let w of E)try{let Fe=await g.readFile(p.join(s,w),"utf-8"),D=JSON.parse(Fe);D.access_token&&(j=!0),D.refresh_token&&(b=!0),D.expires_in&&(z=D.expires_in)}catch{h=`corrupt JSON in ${w}`}v=j||b,!v&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}r.push({version:c,path:s,isCurrent:m,files:d,tokenFile:u,valid:v,reason:h,hasAccessToken:j,hasRefreshToken:b,expiresIn:z})}return{expectedVersion:e,dirs:r}}o(je,"scanTokenDirectories");async function ce(e=A()){try{let t=await g.readFile(e,"utf-8");return JSON.parse(t)}catch(t){let r=x(t).toLowerCase();if(r.includes("no such file")||r.includes("enoent"))return{};throw new Error(`Failed to read MCP config at ${e}: ${x(t)}`)}}o(ce,"readMcpConfig");async function be(e,t=A()){await V(t,e)}o(be,"writeMcpConfig");async function Ge(e,t,r=A()){let n=await ce(r),i={...n.mcpServers||{}},a=i[e];i[e]=t,n.mcpServers=i;let s=JSON.stringify(a)!==JSON.stringify(t);return await be(n,r),{path:r,changed:s}}o(Ge,"upsertMcpServer");async function ze(e,t=A()){return!!(await ce(t)).mcpServers?.[e]}o(ze,"hasMcpServer");function Ke(){return"---"}o(Ke,"mdHeader");function Ye(){return`---
30
- prjct v${Y()}`}o(Ye,"mdFooter");function G(...e){return Ze(Ke(),...e.filter(Boolean),Ye())}o(G,"mdOutput");function F(e,t){let r=`| ${e.join(" | ")} |`,n=`|${e.map(()=>"---").join("|")}|`,i=t.map(a=>`| ${a.join(" | ")} |`);return[r,n,...i].join(`
31
- `)}o(F,"mdTable");function Me(e,t=""){return`\`\`\`${t}
32
- ${e}
33
- \`\`\``}o(Me,"mdCodeBlock");function f(e,t){return`> **${{success:"OK",warn:"WARNING",error:"ERROR",info:"INFO"}[e]}:** ${t}`}o(f,"mdCallout");function N(e,t,r=3){return`### ${e}
34
- ${t}`}o(N,"mdSection");function Oe(e,t=!1){return e.map((r,n)=>t?`${n+1}. ${r}`:`- ${r}`).join(`
35
- `)}o(Oe,"mdList");function Ze(...e){return e.filter(Boolean).join(`
36
-
37
- `)}o(Ze,"mdJoin");function _e(e=process.argv){let t=e.slice(2),r=t.indexOf("--json"),n=r!==-1;n&&t.splice(r,1);let i=t.indexOf("--md"),a=i!==-1;a&&t.splice(i,1);let[s,...c]=t;return{command:s,commandArgs:c,jsonMode:n,mdMode:a}}o(_e,"parseCliArgs");var{command:ue,commandArgs:Qe,jsonMode:Ae,mdMode:de}=_e();function $(e){if(Ae){console.log(JSON.stringify(e,null,2));return}if(typeof e=="string"){console.log(e);return}console.log(JSON.stringify(e,null,2))}o($,"output");function le(e,t=1){console.error(Ae?JSON.stringify({error:e}):`Error: ${e}`),process.exit(t)}o(le,"error");async function et(){let e=R(),t=y("node:path").join(y("node:os").homedir(),".mcp-auth",`mcp-remote-${e}`),r=await H("linear"),n=await U(t),i=await Re("linear",se.linear),a=await W(),s=await X("linear");if(k.setMcpHealth("linear",{status:s.ready?"healthy":"unhealthy",tokenVersion:e,configValid:!0,oauthValid:s.ready,lastError:s.ready?null:s.hint}),de){let c=[];c.push("## Linear MCP Setup"),r.autoFixed&&c.push(f("warn","MCP config was outdated and has been auto-fixed.")),n&&c.push(f("warn","Corrupted token files were cleaned up."));let m=i.map(d=>[d.provider,d.path,d.changed?"updated":"unchanged"]);c.push(N("MCP Config",F(["Provider","Path","Status"],m))),a.migrated&&c.push(f("success",`Tokens migrated from ${y("node:path").basename(a.from)}.`)),s.ready?c.push(f("success","Linear MCP is ready. Restart your AI client to activate.")):(c.push(f("info","OAuth required \u2014 complete the steps below.")),c.push(N("Next Steps",Oe([`Open a NEW terminal and run:
38
- ${Me(P.linear,"bash")}`,"Complete OAuth authorization in the browser.","Run `prjct linear verify --md` to confirm tokens were saved.","Restart your AI client. Linear MCP tools will be ready."],!0)))),console.log(G(...c));return}$({success:!0,provider:"linear",mode:"mcp",configAutoFixed:r.autoFixed,tokensCleaned:n,tokensMigrated:a.migrated,oauthReady:s.ready,installedIn:i.map(c=>({provider:c.provider,path:c.path,updated:c.changed})),nextSteps:s.ready?["Restart your AI client \u2014 Linear MCP is ready."]:[`STEP 1 (done): MCP config written to ${i.map(c=>c.provider).join(", ")}.`,`STEP 2: Open a NEW terminal and run: ${P.linear}`,"STEP 2: A browser will open for OAuth \u2014 complete the authorization.","STEP 3: Run `prjct linear verify` to confirm tokens were saved.","STEP 4: Restart your AI client. Linear MCP tools will be ready."],authCommand:P.linear})}o(et,"setup");async function tt(){let e=await je(),t=await H("linear"),r=await B("linear"),n=await W(),i=R(),a=y("node:path").join(y("node:os").homedir(),".mcp-auth",`mcp-remote-${i}`),s=!1,c=e.dirs.find(u=>u.isCurrent);c&&!c.valid&&c.files.length>0&&!n.migrated&&(s=await U(a));let m=await X("linear"),d={installed:!1,verified:!1};try{d=await Te.verify()}catch(u){d={installed:!1,verified:!1,message:`check failed: ${u instanceof Error?u.message:"unknown"}`}}if(de){let u=[];if(u.push("## Linear MCP Verification"),r.configured?t.autoFixed&&u.push(f("warn","MCP config was outdated and has been auto-fixed.")):u.push(f("error","Linear MCP not configured. Run `prjct linear setup` first.")),e.dirs.length===0)u.push(f("error","No token directories found in `~/.mcp-auth/`. OAuth has not been completed."));else{let v=e.dirs.map(h=>[`mcp-remote-${h.version}`,h.isCurrent?"yes":"no",h.valid?"valid":"invalid",h.tokenFile??"\u2014",h.reason??(h.valid?"OK":"\u2014")]);u.push(N("Token Directories",F(["Directory","Current","Status","Token File","Details"],v)))}n.migrated&&u.push(f("success",`Tokens auto-migrated from ${y("node:path").basename(n.from)}.`)),s&&u.push(f("warn","Corrupted token files were cleaned up.")),d.installed?d.verified?u.push(f("success","Context7 MCP is healthy.")):u.push(f("warn",`Context7 MCP configured but not working: ${d.message??"smoke check failed"}. Run \`prjct sync\` to repair.`)):u.push(f("warn","Context7 MCP not configured. Run `prjct sync` to install.")),m.ready?u.push(f("success","READY \u2014 Linear OAuth tokens verified. Restart your AI client to activate.")):u.push(f("error",`NOT READY \u2014 ${m.hint}`)),console.log(G(...u));return}$({provider:"linear",command:"verify",expectedVersion:e.expectedVersion,dirs:e.dirs.map(u=>({version:u.version,isCurrent:u.isCurrent,valid:u.valid,tokenFile:u.tokenFile,reason:u.reason,hasAccessToken:u.hasAccessToken,hasRefreshToken:u.hasRefreshToken})),configValid:t.valid,configAutoFixed:t.autoFixed,migrated:n.migrated,migratedFrom:n.from,cleaned:s,ready:m.ready,hint:m.hint,context7:{installed:d.installed,verified:d.verified,message:d.message}})}o(tt,"verify");async function rt(){let e=await B("linear"),t=await H("linear"),r=e.configured?await X("linear"):null;if(de){let n=[];n.push("## Linear MCP Status");let i=[["MCP configured",e.configured?"yes":"no"],["Config valid",t.valid?"yes":`no (${t.issues.join(", ")})`]];r&&(i.push(["OAuth tokens",r.ready?"valid":"missing/invalid"]),r.migrated&&i.push(["Tokens migrated","yes"]),r.cleaned&&i.push(["Corrupted cleaned","yes"]));let a=e.providers.map(s=>[s.provider,s.configured?"yes":"no",s.path]);n.push(F(["Check","Result"],i)),n.push(N("Providers",F(["Provider","Configured","Path"],a))),e.configured?r?.ready?n.push(f("success","Linear MCP is healthy. Restart your AI client if tools are not visible.")):n.push(f("warn",r?.hint??"OAuth tokens not found.")):n.push(f("error","Linear MCP not configured. Run `prjct linear setup` to configure.")),t.autoFixed&&n.push(f("info","MCP config was auto-fixed during this check.")),console.log(G(...n));return}$({provider:"linear",mode:"mcp",configured:e.configured,configValid:t.valid,configAutoFixed:t.autoFixed,oauthReady:r?.ready??!1,oauthValidated:r?.validated??!1,oauthMigrated:r?.migrated??!1,oauthCleaned:r?.cleaned??!1,providers:e.providers,hint:e.configured?r?.hint??"":"Run `prjct linear setup` to configure Linear MCP."})}o(rt,"status");async function nt(e,t){let{configured:r}=await B("linear");r||le("Linear MCP is not configured. Run `prjct linear setup` first."),$({success:!0,provider:"linear",mode:"mcp",delegated:!0,command:e,args:t,hint:"Run this operation using Linear MCP tools in your current AI client session.",nextSteps:["Open your MCP-enabled AI client/session.",`Execute the Linear MCP operation for "${e}".`]})}o(nt,"runMcpOperation");async function it(){try{switch(ue){case"setup":await et();break;case"verify":await tt();break;case"status":await rt();break;case"help":case"--help":case"-h":case void 0:$({usage:"prjct linear <command>",commands:{setup:"Configure Linear MCP server",verify:"Verify OAuth tokens after completing authorization",status:"Check Linear MCP configuration",sync:"Delegate issue sync via MCP tools",list:"Delegate issue listing via MCP tools",get:"Delegate issue retrieval via MCP tools",create:"Delegate issue creation via MCP tools",update:"Delegate issue update via MCP tools",start:"Delegate status transition to in-progress via MCP tools",done:"Delegate status transition to done via MCP tools",comment:"Delegate comment creation via MCP tools"},note:"Linear is MCP-only."});break;case"sync":case"list":case"get":case"create":case"update":case"start":case"done":case"comment":case"teams":case"projects":await nt(ue,Qe);break;default:le(`Unknown command: ${ue}. Use --help to see available commands.`)}}catch(e){le(x(e))}}o(it,"main");it();
@@ -1,84 +0,0 @@
1
- ---
2
- allowed-tools: [Read, Bash]
3
- description: 'Analyze codebase and generate comprehensive summary'
4
- ---
5
-
6
- # /p:analyze
7
-
8
- ## Instructions for Claude
9
-
10
- You are analyzing a codebase to generate a comprehensive summary. **NO predetermined patterns** - analyze based on what you actually find.
11
-
12
- ## Your Task
13
-
14
- 1. **Read project files** using the analyzer helpers:
15
- - package.json, Cargo.toml, go.mod, requirements.txt, etc.
16
- - Directory structure
17
- - Git history and stats
18
- - Key source files
19
-
20
- 2. **Understand the stack** - DON'T use predetermined lists:
21
- - What language(s) are used?
22
- - What frameworks are used?
23
- - What tools and libraries are important?
24
- - What's the architecture?
25
-
26
- 3. **Identify features** - based on actual code, not assumptions:
27
- - What has been built?
28
- - What's the current state?
29
- - What patterns do you see?
30
-
31
- 4. **Generate agents** - create specialists for THIS project:
32
- - Read the stack you identified
33
- - Create agents for each major technology
34
- - Use descriptive names (e.g., 'express-backend', 'react-frontend', 'postgres-db')
35
- - Include specific versions and tools found
36
-
37
- ## Guidelines
38
-
39
- - **No assumptions** - only report what you find
40
- - **No predefined maps** - don't assume express = "REST API server"
41
- - **Read and understand** - look at actual code structure
42
- - **Any stack works** - Elixir, Rust, Go, Python, Ruby, whatever exists
43
- - **Be specific** - include versions, specific tools, actual patterns
44
-
45
- ## Output Format
46
-
47
- Generate `analysis/repo-summary.md` with:
48
-
49
- ```markdown
50
- # Project Analysis
51
-
52
- ## Stack
53
-
54
- [What you found - languages, frameworks, tools with versions]
55
-
56
- ## Architecture
57
-
58
- [How it's organized - based on actual structure]
59
-
60
- ## Features
61
-
62
- [What has been built - based on code and git history]
63
-
64
- ## Statistics
65
-
66
- - Total files: [count]
67
- - Contributors: [count]
68
- - Age: [age]
69
- - Last activity: [date]
70
-
71
- ## Recommendations
72
-
73
- [What agents to generate, what's next, etc.]
74
- ```
75
-
76
- ## After Analysis
77
-
78
- 1. Save summary to `analysis/repo-summary.md`
79
- 2. Generate agents using `generator.generateDynamicAgent()`
80
- 3. Report what was found
81
-
82
- ---
83
-
84
- **Remember**: You decide EVERYTHING based on analysis. No if/else, no predetermined patterns.
@@ -1,60 +0,0 @@
1
- ---
2
- allowed-tools: [Read, Glob, Grep]
3
- description: 'Analyze code patterns and conventions'
4
- ---
5
-
6
- # Code Pattern Analysis
7
-
8
- ## Detection Steps
9
-
10
- 1. **Structure** (5-10 files): File org, exports, modules
11
- 2. **Patterns**: SOLID, DRY, factory/singleton/observer
12
- 3. **Conventions**: Naming, style, error handling, async
13
- 4. **Anti-patterns**: God class, spaghetti, copy-paste, magic numbers
14
- 5. **Performance**: Memoization, N+1 queries, leaks
15
-
16
- ## Output: analysis/patterns.md
17
-
18
- ```markdown
19
- # Code Patterns - {Project}
20
-
21
- > Generated: {GetTimestamp()}
22
-
23
- ## Patterns Detected
24
- - **{Pattern}**: {Where} - {Example}
25
-
26
- ## SOLID Compliance
27
- | Principle | Status | Evidence |
28
- |-----------|--------|----------|
29
- | Single Responsibility | ✅/⚠️/❌ | {evidence} |
30
- | Open/Closed | ✅/⚠️/❌ | {evidence} |
31
- | Liskov Substitution | ✅/⚠️/❌ | {evidence} |
32
- | Interface Segregation | ✅/⚠️/❌ | {evidence} |
33
- | Dependency Inversion | ✅/⚠️/❌ | {evidence} |
34
-
35
- ## Conventions (MUST FOLLOW)
36
- - Functions: {camelCase/snake_case}
37
- - Classes: {PascalCase}
38
- - Files: {kebab-case/camelCase}
39
- - Quotes: {single/double}
40
- - Async: {async-await/promises}
41
-
42
- ## Anti-Patterns ⚠️
43
-
44
- ### High Priority
45
- 1. **{Issue}**: {file:line} - Fix: {action}
46
-
47
- ### Medium Priority
48
- 1. **{Issue}**: {file:line} - Fix: {action}
49
-
50
- ## Recommendations
51
- 1. {Immediate action}
52
- 2. {Best practice}
53
- ```
54
-
55
- ## Rules
56
-
57
- 1. Check patterns.md FIRST before writing code
58
- 2. Match conventions exactly
59
- 3. NEVER introduce anti-patterns
60
- 4. Warn if asked to violate patterns
@@ -1,67 +0,0 @@
1
- ---
2
- name: architect-discovery
3
- description: Discovery phase for architecture generation
4
- allowed-tools: [Read, AskUserQuestion]
5
- ---
6
-
7
- # Discovery Phase
8
-
9
- Conduct discovery for the given idea to understand requirements and constraints.
10
-
11
- ## Input
12
- - Idea: {{idea}}
13
- - Context: {{context}}
14
-
15
- ## Discovery Steps
16
-
17
- 1. **Understand the Problem**
18
- - What problem does this solve?
19
- - Who experiences this problem?
20
- - How critical is it?
21
-
22
- 2. **Identify Target Users**
23
- - Who are the primary users?
24
- - What are their goals?
25
- - What's their technical level?
26
-
27
- 3. **Define Constraints**
28
- - Budget limitations?
29
- - Timeline requirements?
30
- - Team size?
31
- - Regulatory needs?
32
-
33
- 4. **Set Success Metrics**
34
- - How will we measure success?
35
- - What's the MVP threshold?
36
- - Key performance indicators?
37
-
38
- ## Output Format
39
-
40
- Return structured discovery:
41
- ```json
42
- {
43
- "problem": {
44
- "statement": "...",
45
- "painPoints": ["..."],
46
- "impact": "high|medium|low"
47
- },
48
- "users": {
49
- "primary": { "persona": "...", "goals": ["..."] },
50
- "secondary": [...]
51
- },
52
- "constraints": {
53
- "budget": "...",
54
- "timeline": "...",
55
- "teamSize": 1
56
- },
57
- "successMetrics": {
58
- "primary": "...",
59
- "mvpThreshold": "..."
60
- }
61
- }
62
- ```
63
-
64
- ## Guidelines
65
- - Ask clarifying questions if needed
66
- - Be realistic about constraints
67
- - Focus on MVP scope
@@ -1,59 +0,0 @@
1
- ---
2
- name: architect-phases
3
- description: Determine which architecture phases are needed
4
- allowed-tools: [Read]
5
- ---
6
-
7
- # Architecture Phase Selection
8
-
9
- Analyze the idea and context to determine which phases are needed.
10
-
11
- ## Input
12
- - Idea: {{idea}}
13
- - Discovery results: {{discovery}}
14
-
15
- ## Available Phases
16
-
17
- 1. **discovery** - Problem definition, users, constraints
18
- 2. **user-flows** - User journeys and interactions
19
- 3. **domain-modeling** - Entities and relationships
20
- 4. **api-design** - API contracts and endpoints
21
- 5. **architecture** - System components and patterns
22
- 6. **data-design** - Database schema and storage
23
- 7. **tech-stack** - Technology choices
24
- 8. **roadmap** - Implementation plan
25
-
26
- ## Phase Selection Rules
27
-
28
- **Always include**:
29
- - discovery (foundation)
30
- - roadmap (execution plan)
31
-
32
- **Include if building**:
33
- - user-flows: Has UI/UX
34
- - domain-modeling: Has data entities
35
- - api-design: Has backend API
36
- - architecture: Complex system
37
- - data-design: Needs database
38
- - tech-stack: Greenfield project
39
-
40
- **Skip if**:
41
- - Simple script: Skip most phases
42
- - Frontend only: Skip api-design, data-design
43
- - CLI tool: Skip user-flows
44
- - Existing stack: Skip tech-stack
45
-
46
- ## Output Format
47
-
48
- Return array of needed phases:
49
- ```json
50
- {
51
- "phases": ["discovery", "domain-modeling", "api-design", "roadmap"],
52
- "reasoning": "Simple CRUD app needs data model and API"
53
- }
54
- ```
55
-
56
- ## Guidelines
57
- - Don't over-architect
58
- - Match complexity to project
59
- - MVP first, expand later
@@ -1,6 +0,0 @@
1
- # /bug - Report a bug
2
-
3
- **ARGUMENTS**: {{args}}
4
-
5
- Run: `prjct bug {{args}} --md`
6
- Follow CLI output.
@@ -1,4 +0,0 @@
1
- # /done - Complete current subtask
2
-
3
- Run: `prjct done --md`
4
- Follow CLI output.
@@ -1,6 +0,0 @@
1
- # /pause - Pause current task
2
-
3
- **ARGUMENTS**: {{args}}
4
-
5
- Run: `prjct pause {{args}} --md`
6
- Follow CLI output.
@@ -1,4 +0,0 @@
1
- # /resume - Resume paused task
2
-
3
- Run: `prjct resume --md`
4
- Follow CLI output.
@@ -1,4 +0,0 @@
1
- # /sync - Analyze project
2
-
3
- Run: `prjct sync --md`
4
- Follow CLI output.
@@ -1,95 +0,0 @@
1
- ---
2
- name: api-design
3
- description: Design API endpoints and contracts
4
- allowed-tools: [Read, Glob, Grep]
5
- ---
6
-
7
- # API Design
8
-
9
- Design RESTful API endpoints for the given feature.
10
-
11
- ## Input
12
- - Target: {{target}}
13
- - Requirements: {{requirements}}
14
-
15
- ## Analysis Steps
16
-
17
- 1. **Identify Resources**
18
- - What entities are involved?
19
- - What operations are needed?
20
- - What relationships exist?
21
-
22
- 2. **Review Existing APIs**
23
- - Read existing route files
24
- - Match naming conventions
25
- - Use consistent patterns
26
-
27
- 3. **Design Endpoints**
28
- - RESTful resource naming
29
- - Appropriate HTTP methods
30
- - Request/response shapes
31
-
32
- 4. **Define Validation**
33
- - Input validation rules
34
- - Error responses
35
- - Edge cases
36
-
37
- ## Output Format
38
-
39
- ```markdown
40
- # API Design: {target}
41
-
42
- ## Endpoints
43
-
44
- ### GET /api/{resource}
45
- **Description**: List all resources
46
-
47
- **Query Parameters**:
48
- - `limit`: number (default: 20)
49
- - `offset`: number (default: 0)
50
-
51
- **Response** (200):
52
- ```json
53
- {
54
- "data": [...],
55
- "total": 100,
56
- "limit": 20,
57
- "offset": 0
58
- }
59
- ```
60
-
61
- ### POST /api/{resource}
62
- **Description**: Create resource
63
-
64
- **Request Body**:
65
- ```json
66
- {
67
- "field": "value"
68
- }
69
- ```
70
-
71
- **Response** (201):
72
- ```json
73
- {
74
- "id": "...",
75
- "field": "value"
76
- }
77
- ```
78
-
79
- **Errors**:
80
- - 400: Invalid input
81
- - 401: Unauthorized
82
- - 409: Conflict
83
-
84
- ## Authentication
85
- - Method: Bearer token / API key
86
- - Required for: POST, PUT, DELETE
87
-
88
- ## Rate Limiting
89
- - 100 requests/minute per user
90
- ```
91
-
92
- ## Guidelines
93
- - Follow REST conventions
94
- - Use consistent error format
95
- - Document all parameters
@@ -1,77 +0,0 @@
1
- ---
2
- name: architecture-design
3
- description: Design system architecture
4
- allowed-tools: [Read, Glob, Grep]
5
- ---
6
-
7
- # Architecture Design
8
-
9
- Design the system architecture for the given requirements.
10
-
11
- ## Input
12
- - Target: {{target}}
13
- - Requirements: {{requirements}}
14
- - Project context
15
-
16
- ## Analysis Steps
17
-
18
- 1. **Understand Requirements**
19
- - What problem are we solving?
20
- - What are the constraints?
21
- - What scale do we need?
22
-
23
- 2. **Review Existing Architecture**
24
- - Read current codebase structure
25
- - Identify existing patterns
26
- - Note integration points
27
-
28
- 3. **Design Components**
29
- - Core modules and responsibilities
30
- - Data flow between components
31
- - External dependencies
32
-
33
- 4. **Define Interfaces**
34
- - API contracts
35
- - Data structures
36
- - Event/message formats
37
-
38
- ## Output Format
39
-
40
- Generate markdown document:
41
-
42
- ```markdown
43
- # Architecture: {target}
44
-
45
- ## Overview
46
- Brief description of the architecture.
47
-
48
- ## Components
49
- - **Component A**: Responsibility
50
- - **Component B**: Responsibility
51
-
52
- ## Data Flow
53
- ```
54
- [Diagram using ASCII or mermaid]
55
- ```
56
-
57
- ## Interfaces
58
- ### API Endpoints
59
- - `GET /resource` - Description
60
- - `POST /resource` - Description
61
-
62
- ### Data Models
63
- - `Model`: { field: type }
64
-
65
- ## Dependencies
66
- - External service X
67
- - Library Y
68
-
69
- ## Decisions
70
- - Decision 1: Rationale
71
- - Decision 2: Rationale
72
- ```
73
-
74
- ## Guidelines
75
- - Match existing project patterns
76
- - Keep it simple - avoid over-engineering
77
- - Document decisions and trade-offs