prjct-cli 1.47.0 → 1.47.4

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.
Files changed (95) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/bin/prjct +8 -27
  3. package/dist/bin/prjct-core.mjs +519 -753
  4. package/dist/cli/jira.mjs +13 -13
  5. package/dist/cli/linear.mjs +12 -12
  6. package/dist/daemon/entry.mjs +506 -740
  7. package/dist/templates.json +1 -1
  8. package/package.json +1 -1
  9. package/templates/antigravity/SKILL.md +12 -31
  10. package/templates/codex/SKILL.md +7 -23
  11. package/templates/cursor/commands/bug.md +2 -4
  12. package/templates/cursor/commands/done.md +2 -2
  13. package/templates/cursor/commands/pause.md +2 -2
  14. package/templates/cursor/commands/resume.md +2 -2
  15. package/templates/cursor/commands/ship.md +3 -5
  16. package/templates/cursor/commands/sync.md +2 -2
  17. package/templates/cursor/commands/task.md +2 -4
  18. package/templates/cursor/p.md +2 -25
  19. package/templates/cursor/router.mdc +2 -21
  20. package/templates/global/ANTIGRAVITY.md +7 -8
  21. package/templates/global/CURSOR.mdc +7 -6
  22. package/templates/global/GEMINI.md +7 -8
  23. package/templates/global/WINDSURF.md +7 -8
  24. package/templates/windsurf/router.md +2 -21
  25. package/templates/windsurf/workflows/bug.md +2 -4
  26. package/templates/windsurf/workflows/done.md +2 -2
  27. package/templates/windsurf/workflows/pause.md +4 -2
  28. package/templates/windsurf/workflows/resume.md +2 -2
  29. package/templates/windsurf/workflows/ship.md +2 -4
  30. package/templates/windsurf/workflows/sync.md +2 -2
  31. package/templates/windsurf/workflows/task.md +2 -4
  32. package/templates/agentic/agent-routing.md +0 -45
  33. package/templates/agentic/agents/uxui.md +0 -63
  34. package/templates/baseline/anti-patterns/nextjs.json +0 -18
  35. package/templates/baseline/anti-patterns/react.json +0 -18
  36. package/templates/baseline/anti-patterns/typescript.json +0 -18
  37. package/templates/baseline/patterns/nextjs.json +0 -18
  38. package/templates/baseline/patterns/react.json +0 -18
  39. package/templates/baseline/patterns/typescript.json +0 -18
  40. package/templates/commands/analyze.md +0 -11
  41. package/templates/commands/auth.md +0 -15
  42. package/templates/commands/bug.md +0 -28
  43. package/templates/commands/cleanup.md +0 -11
  44. package/templates/commands/dash.md +0 -16
  45. package/templates/commands/design.md +0 -11
  46. package/templates/commands/done.md +0 -46
  47. package/templates/commands/enrich.md +0 -20
  48. package/templates/commands/git.md +0 -17
  49. package/templates/commands/history.md +0 -13
  50. package/templates/commands/idea.md +0 -13
  51. package/templates/commands/impact.md +0 -13
  52. package/templates/commands/init.md +0 -11
  53. package/templates/commands/jira.md +0 -94
  54. package/templates/commands/learnings.md +0 -11
  55. package/templates/commands/linear.md +0 -88
  56. package/templates/commands/merge.md +0 -25
  57. package/templates/commands/next.md +0 -12
  58. package/templates/commands/p.md +0 -62
  59. package/templates/commands/p.toml +0 -37
  60. package/templates/commands/pause.md +0 -16
  61. package/templates/commands/plan.md +0 -13
  62. package/templates/commands/prd.md +0 -21
  63. package/templates/commands/resume.md +0 -12
  64. package/templates/commands/review.md +0 -20
  65. package/templates/commands/serve.md +0 -11
  66. package/templates/commands/sessions.md +0 -13
  67. package/templates/commands/setup.md +0 -11
  68. package/templates/commands/ship.md +0 -46
  69. package/templates/commands/skill.md +0 -13
  70. package/templates/commands/spec.md +0 -20
  71. package/templates/commands/status.md +0 -11
  72. package/templates/commands/sync.md +0 -23
  73. package/templates/commands/task.md +0 -69
  74. package/templates/commands/test.md +0 -22
  75. package/templates/commands/update.md +0 -11
  76. package/templates/commands/verify.md +0 -11
  77. package/templates/commands/workflow.md +0 -69
  78. package/templates/global/CLAUDE.md +0 -20
  79. package/templates/global/modules/CLAUDE-commands.md +0 -1
  80. package/templates/global/modules/CLAUDE-core.md +0 -16
  81. package/templates/global/modules/CLAUDE-git.md +0 -1
  82. package/templates/global/modules/CLAUDE-intelligence.md +0 -1
  83. package/templates/global/modules/CLAUDE-storage.md +0 -1
  84. package/templates/global/modules/module-config.json +0 -12
  85. package/templates/subagents/agent-base.md +0 -21
  86. package/templates/subagents/domain/backend.md +0 -109
  87. package/templates/subagents/domain/database.md +0 -121
  88. package/templates/subagents/domain/devops.md +0 -152
  89. package/templates/subagents/domain/frontend.md +0 -103
  90. package/templates/subagents/domain/testing.md +0 -169
  91. package/templates/subagents/pm-expert.md +0 -366
  92. package/templates/subagents/workflow/chief-architect.md +0 -653
  93. package/templates/subagents/workflow/prjct-planner.md +0 -120
  94. package/templates/subagents/workflow/prjct-shipper.md +0 -175
  95. package/templates/subagents/workflow/prjct-workflow.md +0 -82
package/dist/cli/jira.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 $e=Object.defineProperty;var o=(e,t)=>$e(e,"name",{value:t,configurable:!0}),x=(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{execFile as Fe}from"node:child_process";import te from"node:fs/promises";import ye from"node:os";import re from"node:path";import{promisify as Je}from"node:util";import me from"node:fs";import he from"node:path";import{z as l}from"zod";var b={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}},ot=b.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),st=b.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),at=b.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),ct=b.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),ut=b.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),lt=b.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 pe(e){return _e(e)&&e.code==="ENOENT"}o(pe,"isNotFoundError");function E(e){return e instanceof Error?e.message:typeof e=="string"?e:"Unknown error"}o(E,"getErrorMessage");var V=null,Ne=null,A=null;function fe(){if(A)return A;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 A=e,e}catch{}e=L.dirname(e)}return A=L.join(__dirname,"..","..",".."),A}o(fe,"getPackageRoot");function Q(){if(V)return V;try{let e=L.join(fe(),"package.json"),t=JSON.parse(K.readFileSync(e,"utf-8"));return V=t.version,Ne=t,V}catch(e){return console.error("Failed to read version from package.json:",E(e)),"0.0.0"}}o(Q,"getVersion");var yt=Q(),Z=fe();var ee=null,ge=!1;function De(){if(ge)return ee;ge=!0;let e=he.join(Z,"dist","templates.json");try{let t=me.readFileSync(e,"utf-8");return ee=JSON.parse(t),ee}catch{return null}}o(De,"loadBundle");function ve(e){let t=De();if(t?.[e])return t[e];let r=he.join(Z,"templates",e);try{return me.readFileSync(r,"utf-8")}catch{return null}}o(ve,"getTemplateContent");var Ie=Je(Fe),ne={command:"npx",args:["-y","@upstash/context7-mcp@latest"]},Ve=300*1e3,S=null;function Le(){let e=ve("mcp-config.json");if(!e)return{mcpServers:{context7:ne}};try{return JSON.parse(e)}catch{return{mcpServers:{context7:ne}}}}o(Le,"parseTemplateConfig");function Pe(){return Le().mcpServers?.context7||ne}o(Pe,"getContext7Config");function xe(){return process.env.PRJCT_CONTEXT7_CONFIG?process.env.PRJCT_CONTEXT7_CONFIG:process.env.NODE_ENV==="test"?re.join(ye.tmpdir(),"prjct-context7-test","mcp.json"):re.join(ye.homedir(),".claude","mcp.json")}o(xe,"getConfigPath");async function Ee(e){try{let t=await te.readFile(e,"utf-8");return JSON.parse(t)}catch(t){if(pe(t))return{};throw t}}o(Ee,"readConfig");async function qe(){if(process.env.PRJCT_SKIP_CONTEXT7_SMOKE==="1"||process.env.NODE_ENV==="test")return;let e=Pe(),t=[...e.args||[],"--help"];await Ie(e.command||"npx",t,{timeout:15e3})}o(qe,"runSmokeCheck");var ie=class{static{o(this,"Context7Service")}async install(){let t=xe(),r=re.dirname(t);await te.mkdir(r,{recursive:!0});let n=await Ee(t),i=n.mcpServers||{};return i.context7=Pe(),n.mcpServers=i,await te.writeFile(t,JSON.stringify(n,null,2),"utf-8"),S=null,{installed:!0,verified:!1,configPath:t,message:"Context7 MCP configured"}}async verify(){if(S&&Date.now()-S.at<Ve)return S.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 qe();let a={installed:!0,verified:!0,configPath:t};return S={at:Date.now(),status:a},a}catch(a){let s={installed:!0,verified:!1,configPath:t,message:`Context7 smoke check failed: ${E(a)}`};return S={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}},we=new ie;import be from"node:fs";import q from"node:path";function Be(){return typeof globalThis<"u"&&"Bun"in globalThis?"bun":"node"}o(Be,"detectRuntime");function Ce(){return Be()==="bun"}o(Ce,"isBun");function Ue(e){if(Ce()){let{Database:i}=x("bun:sqlite");return new i(e,{create:!0})}let t=x("better-sqlite3"),r=new t(e),n=r.exec.bind(r);return r.run=i=>n(i),r}o(Ue,"openDatabase");var oe=class{static{o(this,"SystemDatabase")}db=null;dbPath;constructor(){let t=process.env.PRJCT_CLI_HOME?.trim(),r=t?q.resolve(t):q.join(x("node:os").homedir(),".prjct-cli");this.dbPath=q.join(r,"system.db")}getDb(){if(this.db)return this.db;let t=q.dirname(this.dbPath);be.existsSync(t)||be.mkdirSync(t,{recursive:!0});let r=Ue(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(`
8
+ var Ft=Object.defineProperty;var o=(t,e)=>Ft(t,"name",{value:e,configurable:!0}),w=(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 St 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 T={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}},ce=T.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),ue=T.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),le=T.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),pe=T.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),de=T.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),fe=T.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 Nt(t){return t instanceof Error&&"code"in t}o(Nt,"isNodeError");function _(t){return Nt(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 Ee=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 $e=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"]},j=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 Tt(){return Ut().mcpServers?.context7||it}o(Tt,"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 St.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=Tt(),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 St.mkdir(r,{recursive:!0});let n=await Pt(e),i=n.mcpServers||{};return i.context7=Tt(),n.mcpServers=i,await q(e,n),j=null,{installed:!0,verified:!1,configPath:e,message:"Context7 MCP configured"}}async verify(){if(j&&Date.now()-j.at<3e5)return j.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 j={at:Date.now(),status:a},a}catch(a){let s={installed:!0,verified:!1,configPath:e,message:`Context7 smoke check failed: ${x(a)}`};return j={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}},jt=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 kt(){return Ht()==="bun"}o(kt,"isBun");function Xt(t){if(kt()){let{Database:i}=w("bun:sqlite");return new i(t,{create:!0})}let e=w("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(w("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
9
  CREATE TABLE IF NOT EXISTS _system_migrations (
10
10
  version INTEGER PRIMARY KEY,
11
11
  name TEXT NOT NULL,
12
12
  applied_at TEXT NOT NULL
13
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(`
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
15
  CREATE TABLE mcp_health (
16
16
  provider TEXT PRIMARY KEY,
17
17
  status TEXT NOT NULL,
@@ -22,19 +22,19 @@ var $e=Object.defineProperty;var o=(e,t)=>$e(e,"name",{value:t,configurable:!0})
22
22
  oauth_valid INTEGER NOT NULL DEFAULT 0,
23
23
  updated_at TEXT NOT NULL
24
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(`
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
26
  INSERT OR REPLACE INTO mcp_health
27
27
  (provider, status, last_checked, last_error, token_version, config_valid, oauth_valid, updated_at)
28
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 f from"node:fs/promises";import T from"node:os";import p from"node:path";var $="mcp-remote@0.1.38",se={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)"}},w={linear:`npx -y ${$} https://mcp.linear.app/mcp`,jira:`npx -y ${$} https://mcp.atlassian.com/v1/mcp`};function j(){return $.split("@")[1]}o(j,"getMcpRemoteVersion");function _(){return process.env.PRJCT_TEST_MODE==="1"?p.join(T.tmpdir(),"prjct-context7-test","mcp.json"):p.join(T.homedir(),".claude","mcp.json")}o(_,"getClaudeMcpConfigPath");async function ae(){if(process.env.PRJCT_TEST_MODE==="1")return[{provider:"claude",configPath:_(),mergeIntoExisting:!1}];let e=T.homedir(),t=[],r=p.join(e,".claude");try{await f.access(r),t.push({provider:"claude",configPath:p.join(r,"mcp.json"),mergeIntoExisting:!1})}catch{}let n=p.join(e,".gemini");try{await f.access(n),t.push({provider:"gemini",configPath:p.join(n,"settings.json"),mergeIntoExisting:!0})}catch{}return t}o(ae,"getActiveMcpConfigPaths");async function Se(e,t){let r=await ae();return Promise.all(r.map(async n=>{let i=await He(e,t,n.configPath);return{provider:n.provider,...i}}))}o(Se,"upsertMcpServerAll");async function R(e){let t=await ae(),r=await Promise.all(t.map(async n=>({provider:n.provider,configured:await We(e,n.configPath),path:n.configPath})));return{configured:r.some(n=>n.configured),providers:r}}o(R,"hasMcpServerAny");async function B(e){let t;try{t=await f.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 f.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(B,"validateTokenFiles");async function U(){let e=j(),t=p.join(T.homedir(),".mcp-auth"),r=p.join(t,`mcp-remote-${e}`);if((await B(r)).valid)return{migrated:!1,from:null,to:r};let i;try{i=await f.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 u=p.join(t,s);if((await B(u)).valid){await f.mkdir(r,{recursive:!0});let d=await f.readdir(u);for(let c of d)await f.copyFile(p.join(u,c),p.join(r,c));return{migrated:!0,from:u,to:r}}}return{migrated:!1,from:null,to:r}}o(U,"migrateOAuthTokens");async function H(e){if((await B(e)).valid)return!1;try{let r=await f.readdir(e);for(let n of r)await f.unlink(p.join(e,n));return await f.rmdir(e),!0}catch{return!1}}o(H,"cleanCorruptedTokens");async function W(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 u=se[e];if(s.command!==u.command||JSON.stringify(s.args)!==JSON.stringify(u.args)){t.push(`${i.provider}: ${e} config doesn't match preset (stale version?)`);let m={...a.mcpServers||{}};m[e]=u,a.mcpServers=m,await Te(a,i.configPath),r=!0}}return{valid:t.length===0,issues:t,autoFixed:r}}o(W,"validateMcpConfig");async function X(e){let t=j(),r=p.join(T.homedir(),".mcp-auth"),n=p.join(r,`mcp-remote-${t}`),i=!1,a=!1,s=await B(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 H(n));let u=await U();if(u.migrated)return i=!0,k.setMcpHealth(e,{status:"healthy",tokenVersion:t,oauthValid:!0}),{ready:!0,tokenDir:n,hint:`Tokens migrated from ${p.basename(u.from)} \u2014 restart your AI client.`,validated:!0,migrated:!0,cleaned:a};let m=[];try{m=(await f.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: ${w[e]}`:m.length>0?`Legacy tokens found (${m.join(", ")}) but invalid. Run: ${w[e]}`:`OAuth not completed. Run in a terminal: ${w[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 ke(){let e=j(),t=p.join(T.homedir(),".mcp-auth"),r=[],n;try{n=await f.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),u=a.replace("mcp-remote-",""),m=u===e,d=[];try{if(!(await f.stat(s)).isDirectory())continue;d=await f.readdir(s)}catch{continue}let c=d.find(P=>P.endsWith("_tokens.json"))??null,v=!1,h,M=!1,O=!1,z;if(c)try{let P=await f.readFile(p.join(s,c),"utf-8"),y=JSON.parse(P);M=!!y.access_token,O=!!y.refresh_token,y.expires_in&&(z=y.expires_in),v=M||O,v||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${c}`}else{let P=d.filter(y=>y.endsWith(".json"));if(P.length===0)h="no token files found";else{for(let y of P)try{let Ae=await f.readFile(p.join(s,y),"utf-8"),I=JSON.parse(Ae);I.access_token&&(M=!0),I.refresh_token&&(O=!0),I.expires_in&&(z=I.expires_in)}catch{h=`corrupt JSON in ${y}`}v=M||O,!v&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}r.push({version:u,path:s,isCurrent:m,files:d,tokenFile:c,valid:v,reason:h,hasAccessToken:M,hasRefreshToken:O,expiresIn:z})}return{expectedVersion:e,dirs:r}}o(ke,"scanTokenDirectories");async function ce(e=_()){try{let t=await f.readFile(e,"utf-8");return JSON.parse(t)}catch(t){let r=E(t).toLowerCase();if(r.includes("no such file")||r.includes("enoent"))return{};throw new Error(`Failed to read MCP config at ${e}: ${E(t)}`)}}o(ce,"readMcpConfig");async function Te(e,t=_()){await f.mkdir(p.dirname(t),{recursive:!0}),await f.writeFile(t,JSON.stringify(e,null,2),"utf-8")}o(Te,"writeMcpConfig");async function He(e,t,r=_()){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 Te(n,r),{path:r,changed:s}}o(He,"upsertMcpServer");async function We(e,t=_()){return!!(await ce(t)).mcpServers?.[e]}o(We,"hasMcpServer");function Xe(){return`\u26A1 prjct
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)}},k=new st;import g from"node:fs/promises";import C from"node:os";import d from"node:path";var $="mcp-remote@0.1.38",at={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 b(){return $.split("@")[1]}o(b,"getMcpRemoteVersion");function D(){return process.env.PRJCT_TEST_MODE==="1"?d.join(C.tmpdir(),"prjct-context7-test","mcp.json"):d.join(C.homedir(),".claude","mcp.json")}o(D,"getClaudeMcpConfigPath");async function ct(){if(process.env.PRJCT_TEST_MODE==="1")return[{provider:"claude",configPath:D(),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 Gt(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 Yt(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 k.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,k.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(y=>y.startsWith("mcp-remote-")&&y!==`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 k.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,y=!1,h,M=!1,O=!1,z;if(u)try{let E=await g.readFile(d.join(s,u),"utf-8"),v=JSON.parse(E);M=!!v.access_token,O=!!v.refresh_token,v.expires_in&&(z=v.expires_in),y=M||O,y||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${u}`}else{let E=p.filter(v=>v.endsWith(".json"));if(E.length===0)h="no token files found";else{for(let v of E)try{let Dt=await g.readFile(d.join(s,v),"utf-8"),J=JSON.parse(Dt);J.access_token&&(M=!0),J.refresh_token&&(O=!0),J.expires_in&&(z=J.expires_in)}catch{h=`corrupt JSON in ${v}`}y=M||O,!y&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}r.push({version:c,path:s,isCurrent:m,files:p,tokenFile:u,valid:y,reason:h,hasAccessToken:M,hasRefreshToken:O,expiresIn:z})}return{expectedVersion:t,dirs:r}}o(Rt,"scanTokenDirectories");async function ut(t=D()){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=D()){await q(e,t)}o(Mt,"writeMcpConfig");async function Gt(t,e,r=D()){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(Gt,"upsertMcpServer");async function Yt(t,e=D()){return!!(await ut(e)).mcpServers?.[t]}o(Yt,"hasMcpServer");function zt(){return`\u26A1 prjct
30
30
 
31
- ---`}o(Xe,"mdHeader");function Ge(){return`---
32
- \u26A1 prjct \xB7 v${Q()}`}o(Ge,"mdFooter");function G(...e){return Ye(Xe(),...e.filter(Boolean),Ge())}o(G,"mdOutput");function N(e,t){let r=`| ${e.join(" | ")} |`,n=`|${e.map(()=>"---").join("|")}|`,i=t.map(a=>`| ${a.join(" | ")} |`);return[r,n,...i].join(`
33
- `)}o(N,"mdTable");function je(e,t=""){return`\`\`\`${t}
34
- ${e}
35
- \`\`\``}o(je,"mdCodeBlock");function g(e,t){return`> ${{success:"\u2705",warn:"\u26A0\uFE0F",error:"\u274C",info:"\u2139\uFE0F"}[e]} **${t}**`}o(g,"mdCallout");function D(e,t,r=3){return`### ${e}
36
- ${t}`}o(D,"mdSection");function Re(e,t=!1){return e.map((r,n)=>t?`${n+1}. ${r}`:`- ${r}`).join(`
37
- `)}o(Re,"mdList");function Ye(...e){return e.filter(Boolean).join(`
31
+ ---`}o(zt,"mdHeader");function Kt(){return`---
32
+ \u26A1 prjct \xB7 v${Z()}`}o(Kt,"mdFooter");function Y(...t){return Zt(zt(),...t.filter(Boolean),Kt())}o(Y,"mdOutput");function F(t,e){let r=`| ${t.join(" | ")} |`,n=`|${t.map(()=>"---").join("|")}|`,i=e.map(a=>`| ${a.join(" | ")} |`);return[r,n,...i].join(`
33
+ `)}o(F,"mdTable");function Ot(t,e=""){return`\`\`\`${e}
34
+ ${t}
35
+ \`\`\``}o(Ot,"mdCodeBlock");function f(t,e){return`> ${{success:"\u2705",warn:"\u26A0\uFE0F",error:"\u274C",info:"\u2139\uFE0F"}[t]} **${e}**`}o(f,"mdCallout");function N(t,e,r=3){return`### ${t}
36
+ ${e}`}o(N,"mdSection");function _t(t,e=!1){return t.map((r,n)=>e?`${n+1}. ${r}`:`- ${r}`).join(`
37
+ `)}o(_t,"mdList");function Zt(...t){return t.filter(Boolean).join(`
38
38
 
39
- `)}o(Ye,"mdJoin");var J=process.argv.slice(2),Me=J.indexOf("--json"),de=Me!==-1;de&&J.splice(Me,1);var Oe=J.indexOf("--md"),Y=Oe!==-1;Y&&J.splice(Oe,1);var[ue,...le]=J;function C(e){if(de){console.log(JSON.stringify(e,null,2));return}if(typeof e=="string"){console.log(e);return}console.log(JSON.stringify(e,null,2))}o(C,"output");function F(e,t=1){console.error(de?JSON.stringify({error:e}):`Error: ${e}`),process.exit(t)}o(F,"error");async function ze(){let e=j(),t=x("node:path").join(x("node:os").homedir(),".mcp-auth",`mcp-remote-${e}`),r=await W("jira"),n=await H(t),i=await Se("jira",se.jira),a=await U(),s=await X("jira");if(k.setMcpHealth("jira",{status:s.ready?"healthy":"unhealthy",tokenVersion:e,configValid:!0,oauthValid:s.ready,lastError:s.ready?null:s.hint}),Y){let u=[];u.push("## Jira MCP Setup"),r.autoFixed&&u.push(g("warn","MCP config was outdated and has been auto-fixed.")),n&&u.push(g("warn","Corrupted token files were cleaned up."));let m=i.map(d=>[d.provider,d.path,d.changed?"updated":"unchanged"]);u.push(D("MCP Config",N(["Provider","Path","Status"],m))),a.migrated&&u.push(g("success",`Tokens migrated from ${x("node:path").basename(a.from)}.`)),s.ready?u.push(g("success","Jira MCP is ready. Restart your AI client to activate.")):(u.push(g("info","OAuth required \u2014 complete the steps below.")),u.push(D("Next Steps",Re([`Open a NEW terminal and run:
40
- ${je(w.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(G(...u));return}C({success:!0,provider:"jira",mode:"mcp",configAutoFixed:r.autoFixed,tokensCleaned:n,tokensMigrated:a.migrated,oauthReady:s.ready,installedIn:i.map(u=>({provider:u.provider,path:u.path,updated:u.changed})),nextSteps:s.ready?["Restart your AI client \u2014 Jira MCP is ready."]:[`STEP 1 (done): MCP config written to ${i.map(u=>u.provider).join(", ")}.`,`STEP 2: Open a NEW terminal and run: ${w.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:w.jira})}o(ze,"setup");async function Ke(){let e=await ke(),t=await W("jira"),r=await R("jira"),n=await U(),i=j(),a=x("node:path").join(x("node:os").homedir(),".mcp-auth",`mcp-remote-${i}`),s=!1,u=e.dirs.find(c=>c.isCurrent);u&&!u.valid&&u.files.length>0&&!n.migrated&&(s=await H(a));let m=await X("jira"),d={installed:!1,verified:!1};try{d=await we.verify()}catch(c){d={installed:!1,verified:!1,message:`check failed: ${c instanceof Error?c.message:"unknown"}`}}if(Y){let c=[];if(c.push("## Jira MCP Verification"),r.configured?t.autoFixed&&c.push(g("warn","MCP config was outdated and has been auto-fixed.")):c.push(g("error","Jira MCP not configured. Run `prjct jira setup` first.")),e.dirs.length===0)c.push(g("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")]);c.push(D("Token Directories",N(["Directory","Current","Status","Token File","Details"],v)))}n.migrated&&c.push(g("success",`Tokens auto-migrated from ${x("node:path").basename(n.from)}.`)),s&&c.push(g("warn","Corrupted token files were cleaned up.")),d.installed?d.verified?c.push(g("success","Context7 MCP is healthy.")):c.push(g("warn",`Context7 MCP configured but not working: ${d.message??"smoke check failed"}. Run \`prjct sync\` to repair.`)):c.push(g("warn","Context7 MCP not configured. Run `prjct sync` to install.")),m.ready?c.push(g("success","READY \u2014 Jira OAuth tokens verified. Restart your AI client to activate.")):c.push(g("error",`NOT READY \u2014 ${m.hint}`)),console.log(G(...c));return}C({provider:"jira",command:"verify",expectedVersion:e.expectedVersion,dirs:e.dirs.map(c=>({version:c.version,isCurrent:c.isCurrent,valid:c.valid,tokenFile:c.tokenFile,reason:c.reason,hasAccessToken:c.hasAccessToken,hasRefreshToken:c.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(Ke,"verify");async function Qe(){let e=await R("jira"),t=await W("jira"),r=e.configured?await X("jira"):null;if(Y){let n=[];n.push("## Jira 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(N(["Check","Result"],i)),n.push(D("Providers",N(["Provider","Configured","Path"],a))),e.configured?r?.ready?n.push(g("success","Jira MCP is healthy. Restart your AI client if tools are not visible.")):n.push(g("warn",r?.hint??"OAuth tokens not found.")):n.push(g("error","Jira MCP not configured. Run `prjct jira setup` to configure.")),t.autoFixed&&n.push(g("info","MCP config was auto-fixed during this check.")),console.log(G(...n));return}C({provider:"jira",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 jira setup` to configure Jira MCP."})}o(Qe,"status");async function Ze(e,t,r){let{configured:n}=await R("jira");n||F("Jira MCP is not configured. Run `prjct jira setup` first.");let i={success:!0,provider:"jira",mode:"mcp",delegated:!0,command:e,args:t,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 "${e}".`]};r?.jql&&(i.jql=r.jql),r?.scope&&(i.scope=r.scope),C(i)}o(Ze,"runMcpOperation");async function et(e){let{configured:t}=await R("jira");t||F("Jira MCP is not configured. Run `prjct jira setup` first."),C({success:!0,provider:"jira",mode:"mcp",delegated:!0,command:"sprint",scope:"active_sprint",args:e,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(et,"sprintOperation");async function tt(e){let{configured:t}=await R("jira");t||F("Jira MCP is not configured. Run `prjct jira setup` first."),C({success:!0,provider:"jira",mode:"mcp",delegated:!0,command:"backlog",scope:"backlog",args:e,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(tt,"backlogOperation");async function rt(){try{switch(ue){case"setup":await ze();break;case"verify":await Ke();break;case"status":await Qe();break;case"help":case"--help":case"-h":case void 0:C({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 et(le);break;case"backlog":await tt(le);break;case"sync":case"start":case"done":case"list":case"get":case"create":case"update":case"transition":case"comment":case"projects":case"boards":await Ze(ue,le);break;default:F(`Unknown command: ${ue}. Use --help to see available commands.`)}}catch(e){F(E(e))}}o(rt,"main");rt();
39
+ `)}o(Zt,"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:$t,mdMode:dt}=At();function S(t){if($t){console.log(JSON.stringify(t,null,2));return}if(typeof t=="string"){console.log(t);return}console.log(JSON.stringify(t,null,2))}o(S,"output");function I(t,e=1){console.error($t?JSON.stringify({error:t}):`Error: ${t}`),process.exit(e)}o(I,"error");async function Qt(){let t=b(),e=w("node:path").join(w("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(k.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(N("MCP Config",F(["Provider","Path","Status"],m))),a.migrated&&c.push(f("success",`Tokens migrated from ${w("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(N("Next Steps",_t([`Open a NEW terminal and run:
40
+ ${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}S({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(Qt,"setup");async function te(){let t=await Rt(),e=await X("jira"),r=await R("jira"),n=await W(),i=b(),a=w("node:path").join(w("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 jt.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 y=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(N("Token Directories",F(["Directory","Current","Status","Token File","Details"],y)))}n.migrated&&u.push(f("success",`Tokens auto-migrated from ${w("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}S({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(te,"verify");async function ee(){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(F(["Check","Result"],i)),n.push(N("Providers",F(["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}S({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(ee,"status");async function re(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),S(i)}o(re,"runMcpOperation");async function ne(t){let{configured:e}=await R("jira");e||I("Jira MCP is not configured. Run `prjct jira setup` first."),S({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(ne,"sprintOperation");async function ie(t){let{configured:e}=await R("jira");e||I("Jira MCP is not configured. Run `prjct jira setup` first."),S({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(ie,"backlogOperation");async function oe(){try{switch(lt){case"setup":await Qt();break;case"verify":await te();break;case"status":await ee();break;case"help":case"--help":case"-h":case void 0:S({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 ne(pt);break;case"backlog":await ie(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 re(lt,pt);break;default:I(`Unknown command: ${lt}. Use --help to see available commands.`)}}catch(t){I(x(t))}}o(oe,"main");oe();
@@ -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 $e=Object.defineProperty;var o=(e,t)=>$e(e,"name",{value:t,configurable:!0}),x=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,n)=>(typeof require<"u"?require:t)[n]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});import{execFile as De}from"node:child_process";import ee from"node:fs/promises";import ve from"node:os";import te from"node:path";import{promisify as Fe}from"node:util";import ge from"node:fs";import me from"node:path";import{z as l}from"zod";var S={create(e,t){class n 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 n(i)}static is(i){return i instanceof n&&i.errorName===e}static create(i){return new n(i)}}return n}},rt=S.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),it=S.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),ot=S.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),st=S.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),at=S.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),ct=S.create("SyncError",l.object({projectId:l.string().optional(),operation:l.enum(["push","pull","auth","connect"]),reason:l.string()}));import Y from"node:fs";import L from"node:path";function Ae(e){return e instanceof Error&&"code"in e}o(Ae,"isNodeError");function de(e){return Ae(e)&&e.code==="ENOENT"}o(de,"isNotFoundError");function E(e){return e instanceof Error?e.message:typeof e=="string"?e:"Unknown error"}o(E,"getErrorMessage");var I=null,_e=null,O=null;function pe(){if(O)return O;let e=__dirname;for(let t=0;t<5;t++){let n=L.join(e,"package.json");if(Y.existsSync(n))try{if(JSON.parse(Y.readFileSync(n,"utf-8")).name==="prjct-cli")return O=e,e}catch{}e=L.dirname(e)}return O=L.join(__dirname,"..","..",".."),O}o(pe,"getPackageRoot");function K(){if(I)return I;try{let e=L.join(pe(),"package.json"),t=JSON.parse(Y.readFileSync(e,"utf-8"));return I=t.version,_e=t,I}catch(e){return console.error("Failed to read version from package.json:",E(e)),"0.0.0"}}o(K,"getVersion");var ht=K(),Z=pe();var Q=null,fe=!1;function Ne(){if(fe)return Q;fe=!0;let e=me.join(Z,"dist","templates.json");try{let t=ge.readFileSync(e,"utf-8");return Q=JSON.parse(t),Q}catch{return null}}o(Ne,"loadBundle");function he(e){let t=Ne();if(t?.[e])return t[e];let n=me.join(Z,"templates",e);try{return ge.readFileSync(n,"utf-8")}catch{return null}}o(he,"getTemplateContent");var Ie=Fe(De),ne={command:"npx",args:["-y","@upstash/context7-mcp@latest"]},Le=300*1e3,T=null;function Ve(){let e=he("mcp-config.json");if(!e)return{mcpServers:{context7:ne}};try{return JSON.parse(e)}catch{return{mcpServers:{context7:ne}}}}o(Ve,"parseTemplateConfig");function Ee(){return Ve().mcpServers?.context7||ne}o(Ee,"getContext7Config");function ye(){return process.env.PRJCT_CONTEXT7_CONFIG?process.env.PRJCT_CONTEXT7_CONFIG:process.env.NODE_ENV==="test"?te.join(ve.tmpdir(),"prjct-context7-test","mcp.json"):te.join(ve.homedir(),".claude","mcp.json")}o(ye,"getConfigPath");async function xe(e){try{let t=await ee.readFile(e,"utf-8");return JSON.parse(t)}catch(t){if(de(t))return{};throw t}}o(xe,"readConfig");async function Je(){if(process.env.PRJCT_SKIP_CONTEXT7_SMOKE==="1"||process.env.NODE_ENV==="test")return;let e=Ee(),t=[...e.args||[],"--help"];await Ie(e.command||"npx",t,{timeout:15e3})}o(Je,"runSmokeCheck");var re=class{static{o(this,"Context7Service")}async install(){let t=ye(),n=te.dirname(t);await ee.mkdir(n,{recursive:!0});let r=await xe(t),i=r.mcpServers||{};return i.context7=Ee(),r.mcpServers=i,await ee.writeFile(t,JSON.stringify(r,null,2),"utf-8"),T=null,{installed:!0,verified:!1,configPath:t,message:"Context7 MCP configured"}}async verify(){if(T&&Date.now()-T.at<Le)return T.status;let t=ye(),i=((await xe(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 Je();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: ${E(a)}`};return T={at:Date.now(),status:s},s}}async ensureReady(){await this.install();let t=await this.verify();if(!t.verified){let n=t.message||"Context7 MCP is required but not ready. Run `prjct start` to repair configuration.";throw new Error(n)}return t}},Pe=new re;import Se from"node:fs";import V from"node:path";function qe(){return typeof globalThis<"u"&&"Bun"in globalThis?"bun":"node"}o(qe,"detectRuntime");function we(){return qe()==="bun"}o(we,"isBun");function Be(e){if(we()){let{Database:i}=x("bun:sqlite");return new i(e,{create:!0})}let t=x("better-sqlite3"),n=new t(e),r=n.exec.bind(n);return n.run=i=>r(i),n}o(Be,"openDatabase");var ie=class{static{o(this,"SystemDatabase")}db=null;dbPath;constructor(){let t=process.env.PRJCT_CLI_HOME?.trim(),n=t?V.resolve(t):V.join(x("node:os").homedir(),".prjct-cli");this.dbPath=V.join(n,"system.db")}getDb(){if(this.db)return this.db;let t=V.dirname(this.dbPath);Se.existsSync(t)||Se.mkdirSync(t,{recursive:!0});let n=Be(this.dbPath);return n.run("PRAGMA journal_mode = WAL"),n.run("PRAGMA synchronous = NORMAL"),n.run("PRAGMA cache_size = -1000"),n.run("PRAGMA temp_store = MEMORY"),this.runMigrations(n),this.db=n,n}runMigrations(t){t.run(`
8
+ var Fe=Object.defineProperty;var o=(e,t)=>Fe(e,"name",{value:t,configurable:!0}),x=(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 xe 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}},st=S.create("FileError",l.object({path:l.string(),operation:l.enum(["read","write","delete","create","copy"]),reason:l.string().optional()})),at=S.create("ValidationError",l.object({field:l.string(),expected:l.string(),received:l.string().optional(),message:l.string().optional()})),ct=S.create("PermissionError",l.object({action:l.string(),resource:l.string(),reason:l.string().optional()})),ut=S.create("TaskError",l.object({taskId:l.string().optional(),operation:l.enum(["create","update","complete","pause","resume","delete"]),reason:l.string()})),lt=S.create("SessionError",l.object({sessionId:l.string().optional(),reason:l.string()})),dt=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 Ne(e){return e instanceof Error&&"code"in e}o(Ne,"isNodeError");function M(e){return Ne(e)&&e.code==="ENOENT"}o(M,"isNotFoundError");function w(e){return e instanceof Error?e.message:typeof e=="string"?e:"Unknown error"}o(w,"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:",w(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 _t=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 we(){return process.env.PRJCT_CONTEXT7_CONFIG?process.env.PRJCT_CONTEXT7_CONFIG:process.env.NODE_ENV==="test"?re.join(xe.tmpdir(),"prjct-context7-test","mcp.json"):re.join(xe.homedir(),".claude","mcp.json")}o(we,"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=we(),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=we(),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: ${w(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}=x("bun:sqlite");return new i(e,{create:!0})}let t=x("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(x("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
9
  CREATE TABLE IF NOT EXISTS _system_migrations (
10
10
  version INTEGER PRIMARY KEY,
11
11
  name TEXT NOT NULL,
12
12
  applied_at TEXT NOT NULL
13
13
  )
14
- `);let n=new Set(t.prepare("SELECT version FROM _system_migrations").all().map(i=>i.version)),r=[{version:1,name:"mcp-health-table",up:o(i=>{i.run(`
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
15
  CREATE TABLE mcp_health (
16
16
  provider TEXT PRIMARY KEY,
17
17
  status TEXT NOT NULL,
@@ -22,19 +22,19 @@ var $e=Object.defineProperty;var o=(e,t)=>$e(e,"name",{value:t,configurable:!0})
22
22
  oauth_valid INTEGER NOT NULL DEFAULT 0,
23
23
  updated_at TEXT NOT NULL
24
24
  )
25
- `)},"up")}];for(let i of r)n.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,n){let r=this.getDb(),i=new Date().toISOString();r.prepare(`
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
26
  INSERT OR REPLACE INTO mcp_health
27
27
  (provider, status, last_checked, last_error, token_version, config_valid, oauth_valid, updated_at)
28
28
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
29
- `).run(t,n.status,i,n.lastError??null,n.tokenVersion??null,n.configValid?1:0,n.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)}},C=new ie;import f from"node:fs/promises";import k from"node:os";import p from"node:path";var j="mcp-remote@0.1.38",oe={linear:{command:"npx",args:["-y",j,"https://mcp.linear.app/mcp"],description:"Linear MCP server (OAuth)"},jira:{command:"npx",args:["-y",j,"https://mcp.atlassian.com/v1/mcp"],description:"Atlassian MCP server for Jira (OAuth)"}},w={linear:`npx -y ${j} https://mcp.linear.app/mcp`,jira:`npx -y ${j} https://mcp.atlassian.com/v1/mcp`};function b(){return j.split("@")[1]}o(b,"getMcpRemoteVersion");function $(){return process.env.PRJCT_TEST_MODE==="1"?p.join(k.tmpdir(),"prjct-context7-test","mcp.json"):p.join(k.homedir(),".claude","mcp.json")}o($,"getClaudeMcpConfigPath");async function se(){if(process.env.PRJCT_TEST_MODE==="1")return[{provider:"claude",configPath:$(),mergeIntoExisting:!1}];let e=k.homedir(),t=[],n=p.join(e,".claude");try{await f.access(n),t.push({provider:"claude",configPath:p.join(n,"mcp.json"),mergeIntoExisting:!1})}catch{}let r=p.join(e,".gemini");try{await f.access(r),t.push({provider:"gemini",configPath:p.join(r,"settings.json"),mergeIntoExisting:!0})}catch{}return t}o(se,"getActiveMcpConfigPaths");async function Te(e,t){let n=await se();return Promise.all(n.map(async r=>{let i=await Ue(e,t,r.configPath);return{provider:r.provider,...i}}))}o(Te,"upsertMcpServerAll");async function q(e){let t=await se(),n=await Promise.all(t.map(async r=>({provider:r.provider,configured:await He(e,r.configPath),path:r.configPath})));return{configured:n.some(r=>r.configured),providers:n}}o(q,"hasMcpServerAny");async function J(e){let t;try{t=await f.readdir(e)}catch{return{valid:!1,reason:"directory not found"}}if(t.length===0)return{valid:!1,reason:"directory empty"};let n=t.filter(r=>r.endsWith("_tokens.json")||r.endsWith(".json"));if(n.length===0)return{valid:!1,reason:"no token files found"};for(let r of n){let i=p.join(e,r);try{let a=await f.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 ${r}`}}}return{valid:!1,reason:"no valid tokens (missing access_token/refresh_token)"}}o(J,"validateTokenFiles");async function B(){let e=b(),t=p.join(k.homedir(),".mcp-auth"),n=p.join(t,`mcp-remote-${e}`);if((await J(n)).valid)return{migrated:!1,from:null,to:n};let i;try{i=await f.readdir(t)}catch{return{migrated:!1,from:null,to:n}}let a=i.filter(s=>s.startsWith("mcp-remote-")&&s!==`mcp-remote-${e}`).sort().reverse();for(let s of a){let u=p.join(t,s);if((await J(u)).valid){await f.mkdir(n,{recursive:!0});let d=await f.readdir(u);for(let c of d)await f.copyFile(p.join(u,c),p.join(n,c));return{migrated:!0,from:u,to:n}}}return{migrated:!1,from:null,to:n}}o(B,"migrateOAuthTokens");async function U(e){if((await J(e)).valid)return!1;try{let n=await f.readdir(e);for(let r of n)await f.unlink(p.join(e,r));return await f.rmdir(e),!0}catch{return!1}}o(U,"cleanCorruptedTokens");async function H(e){let t=[],n=!1,r=await se();for(let i of r){let a=await ae(i.configPath),s=a.mcpServers?.[e];if(!s){t.push(`${i.provider}: no ${e} entry in mcp.json`);continue}let u=oe[e];if(s.command!==u.command||JSON.stringify(s.args)!==JSON.stringify(u.args)){t.push(`${i.provider}: ${e} config doesn't match preset (stale version?)`);let m={...a.mcpServers||{}};m[e]=u,a.mcpServers=m,await ke(a,i.configPath),n=!0}}return{valid:t.length===0,issues:t,autoFixed:n}}o(H,"validateMcpConfig");async function W(e){let t=b(),n=p.join(k.homedir(),".mcp-auth"),r=p.join(n,`mcp-remote-${t}`),i=!1,a=!1,s=await J(r);if(s.valid)return C.setMcpHealth(e,{status:"healthy",tokenVersion:t,oauthValid:!0}),{ready:!0,tokenDir:r,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(r));let u=await B();if(u.migrated)return i=!0,C.setMcpHealth(e,{status:"healthy",tokenVersion:t,oauthValid:!0}),{ready:!0,tokenDir:r,hint:`Tokens migrated from ${p.basename(u.from)} \u2014 restart your AI client.`,validated:!0,migrated:!0,cleaned:a};let m=[];try{m=(await f.readdir(n)).filter(v=>v.startsWith("mcp-remote-")&&v!==`mcp-remote-${t}`)}catch{}let d=a?`Previous tokens were invalid and cleaned. Run in a terminal: ${w[e]}`:m.length>0?`Legacy tokens found (${m.join(", ")}) but invalid. Run: ${w[e]}`:`OAuth not completed. Run in a terminal: ${w[e]}`;return C.setMcpHealth(e,{status:"unhealthy",lastError:d,tokenVersion:t,oauthValid:!1}),{ready:!1,tokenDir:null,hint:d,validated:!1,migrated:!1,cleaned:a}}o(W,"checkOAuthTokens");async function Ce(){let e=b(),t=p.join(k.homedir(),".mcp-auth"),n=[],r;try{r=await f.readdir(t)}catch{return{expectedVersion:e,dirs:n}}let i=r.filter(a=>a.startsWith("mcp-remote-")).sort();for(let a of i){let s=p.join(t,a),u=a.replace("mcp-remote-",""),m=u===e,d=[];try{if(!(await f.stat(s)).isDirectory())continue;d=await f.readdir(s)}catch{continue}let c=d.find(P=>P.endsWith("_tokens.json"))??null,v=!1,h,R=!1,M=!1,z;if(c)try{let P=await f.readFile(p.join(s,c),"utf-8"),y=JSON.parse(P);R=!!y.access_token,M=!!y.refresh_token,y.expires_in&&(z=y.expires_in),v=R||M,v||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${c}`}else{let P=d.filter(y=>y.endsWith(".json"));if(P.length===0)h="no token files found";else{for(let y of P)try{let je=await f.readFile(p.join(s,y),"utf-8"),F=JSON.parse(je);F.access_token&&(R=!0),F.refresh_token&&(M=!0),F.expires_in&&(z=F.expires_in)}catch{h=`corrupt JSON in ${y}`}v=R||M,!v&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}n.push({version:u,path:s,isCurrent:m,files:d,tokenFile:c,valid:v,reason:h,hasAccessToken:R,hasRefreshToken:M,expiresIn:z})}return{expectedVersion:e,dirs:n}}o(Ce,"scanTokenDirectories");async function ae(e=$()){try{let t=await f.readFile(e,"utf-8");return JSON.parse(t)}catch(t){let n=E(t).toLowerCase();if(n.includes("no such file")||n.includes("enoent"))return{};throw new Error(`Failed to read MCP config at ${e}: ${E(t)}`)}}o(ae,"readMcpConfig");async function ke(e,t=$()){await f.mkdir(p.dirname(t),{recursive:!0}),await f.writeFile(t,JSON.stringify(e,null,2),"utf-8")}o(ke,"writeMcpConfig");async function Ue(e,t,n=$()){let r=await ae(n),i={...r.mcpServers||{}},a=i[e];i[e]=t,r.mcpServers=i;let s=JSON.stringify(a)!==JSON.stringify(t);return await ke(r,n),{path:n,changed:s}}o(Ue,"upsertMcpServer");async function He(e,t=$()){return!!(await ae(t)).mcpServers?.[e]}o(He,"hasMcpServer");function We(){return`\u26A1 prjct
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",se={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 b(){return _.split("@")[1]}o(b,"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 be(e,t){let r=await ae();return Promise.all(r.map(async n=>{let i=await Xe(e,t,n.configPath);return{provider:n.provider,...i}}))}o(be,"upsertMcpServerAll");async function B(e){let t=await ae(),r=await Promise.all(t.map(async n=>({provider:n.provider,configured:await Ge(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=b(),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 je(a,i.configPath),r=!0}}return{valid:t.length===0,issues:t,autoFixed:r}}o(H,"validateMcpConfig");async function X(e){let t=b(),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(y=>y.startsWith("mcp-remote-")&&y!==`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 Re(){let e=b(),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,y=!1,h,R=!1,j=!1,z;if(u)try{let E=await g.readFile(p.join(s,u),"utf-8"),v=JSON.parse(E);R=!!v.access_token,j=!!v.refresh_token,v.expires_in&&(z=v.expires_in),y=R||j,y||(h="no valid tokens (missing access_token/refresh_token)")}catch{h=`corrupt JSON in ${u}`}else{let E=d.filter(v=>v.endsWith(".json"));if(E.length===0)h="no token files found";else{for(let v of E)try{let $e=await g.readFile(p.join(s,v),"utf-8"),D=JSON.parse($e);D.access_token&&(R=!0),D.refresh_token&&(j=!0),D.expires_in&&(z=D.expires_in)}catch{h=`corrupt JSON in ${v}`}y=R||j,!y&&!h&&(h="no valid tokens (missing access_token/refresh_token)")}}r.push({version:c,path:s,isCurrent:m,files:d,tokenFile:u,valid:y,reason:h,hasAccessToken:R,hasRefreshToken:j,expiresIn:z})}return{expectedVersion:e,dirs:r}}o(Re,"scanTokenDirectories");async function ce(e=A()){try{let t=await g.readFile(e,"utf-8");return JSON.parse(t)}catch(t){let r=w(t).toLowerCase();if(r.includes("no such file")||r.includes("enoent"))return{};throw new Error(`Failed to read MCP config at ${e}: ${w(t)}`)}}o(ce,"readMcpConfig");async function je(e,t=A()){await V(t,e)}o(je,"writeMcpConfig");async function Xe(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 je(n,r),{path:r,changed:s}}o(Xe,"upsertMcpServer");async function Ge(e,t=A()){return!!(await ce(t)).mcpServers?.[e]}o(Ge,"hasMcpServer");function ze(){return`\u26A1 prjct
30
30
 
31
- ---`}o(We,"mdHeader");function Xe(){return`---
32
- \u26A1 prjct \xB7 v${K()}`}o(Xe,"mdFooter");function X(...e){return Ge(We(),...e.filter(Boolean),Xe())}o(X,"mdOutput");function A(e,t){let n=`| ${e.join(" | ")} |`,r=`|${e.map(()=>"---").join("|")}|`,i=t.map(a=>`| ${a.join(" | ")} |`);return[n,r,...i].join(`
33
- `)}o(A,"mdTable");function be(e,t=""){return`\`\`\`${t}
31
+ ---`}o(ze,"mdHeader");function Ke(){return`---
32
+ \u26A1 prjct \xB7 v${Y()}`}o(Ke,"mdFooter");function G(...e){return Ye(ze(),...e.filter(Boolean),Ke())}o(G,"mdOutput");function $(e,t){let r=`| ${e.join(" | ")} |`,n=`|${e.map(()=>"---").join("|")}|`,i=t.map(a=>`| ${a.join(" | ")} |`);return[r,n,...i].join(`
33
+ `)}o($,"mdTable");function Me(e,t=""){return`\`\`\`${t}
34
34
  ${e}
35
- \`\`\``}o(be,"mdCodeBlock");function g(e,t){return`> ${{success:"\u2705",warn:"\u26A0\uFE0F",error:"\u274C",info:"\u2139\uFE0F"}[e]} **${t}**`}o(g,"mdCallout");function _(e,t,n=3){return`### ${e}
36
- ${t}`}o(_,"mdSection");function Re(e,t=!1){return e.map((n,r)=>t?`${r+1}. ${n}`:`- ${n}`).join(`
37
- `)}o(Re,"mdList");function Ge(...e){return e.filter(Boolean).join(`
35
+ \`\`\``}o(Me,"mdCodeBlock");function f(e,t){return`> ${{success:"\u2705",warn:"\u26A0\uFE0F",error:"\u274C",info:"\u2139\uFE0F"}[e]} **${t}**`}o(f,"mdCallout");function F(e,t,r=3){return`### ${e}
36
+ ${t}`}o(F,"mdSection");function Oe(e,t=!1){return e.map((r,n)=>t?`${n+1}. ${r}`:`- ${r}`).join(`
37
+ `)}o(Oe,"mdList");function Ye(...e){return e.filter(Boolean).join(`
38
38
 
39
- `)}o(Ge,"mdJoin");var N=process.argv.slice(2),Me=N.indexOf("--json"),le=Me!==-1;le&&N.splice(Me,1);var Oe=N.indexOf("--md"),G=Oe!==-1;G&&N.splice(Oe,1);var[ce,...ze]=N;function D(e){if(le){console.log(JSON.stringify(e,null,2));return}if(typeof e=="string"){console.log(e);return}console.log(JSON.stringify(e,null,2))}o(D,"output");function ue(e,t=1){console.error(le?JSON.stringify({error:e}):`Error: ${e}`),process.exit(t)}o(ue,"error");async function Ye(){let e=b(),t=x("node:path").join(x("node:os").homedir(),".mcp-auth",`mcp-remote-${e}`),n=await H("linear"),r=await U(t),i=await Te("linear",oe.linear),a=await B(),s=await W("linear");if(C.setMcpHealth("linear",{status:s.ready?"healthy":"unhealthy",tokenVersion:e,configValid:!0,oauthValid:s.ready,lastError:s.ready?null:s.hint}),G){let u=[];u.push("## Linear MCP Setup"),n.autoFixed&&u.push(g("warn","MCP config was outdated and has been auto-fixed.")),r&&u.push(g("warn","Corrupted token files were cleaned up."));let m=i.map(d=>[d.provider,d.path,d.changed?"updated":"unchanged"]);u.push(_("MCP Config",A(["Provider","Path","Status"],m))),a.migrated&&u.push(g("success",`Tokens migrated from ${x("node:path").basename(a.from)}.`)),s.ready?u.push(g("success","Linear MCP is ready. Restart your AI client to activate.")):(u.push(g("info","OAuth required \u2014 complete the steps below.")),u.push(_("Next Steps",Re([`Open a NEW terminal and run:
40
- ${be(w.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(X(...u));return}D({success:!0,provider:"linear",mode:"mcp",configAutoFixed:n.autoFixed,tokensCleaned:r,tokensMigrated:a.migrated,oauthReady:s.ready,installedIn:i.map(u=>({provider:u.provider,path:u.path,updated:u.changed})),nextSteps:s.ready?["Restart your AI client \u2014 Linear MCP is ready."]:[`STEP 1 (done): MCP config written to ${i.map(u=>u.provider).join(", ")}.`,`STEP 2: Open a NEW terminal and run: ${w.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:w.linear})}o(Ye,"setup");async function Ke(){let e=await Ce(),t=await H("linear"),n=await q("linear"),r=await B(),i=b(),a=x("node:path").join(x("node:os").homedir(),".mcp-auth",`mcp-remote-${i}`),s=!1,u=e.dirs.find(c=>c.isCurrent);u&&!u.valid&&u.files.length>0&&!r.migrated&&(s=await U(a));let m=await W("linear"),d={installed:!1,verified:!1};try{d=await Pe.verify()}catch(c){d={installed:!1,verified:!1,message:`check failed: ${c instanceof Error?c.message:"unknown"}`}}if(G){let c=[];if(c.push("## Linear MCP Verification"),n.configured?t.autoFixed&&c.push(g("warn","MCP config was outdated and has been auto-fixed.")):c.push(g("error","Linear MCP not configured. Run `prjct linear setup` first.")),e.dirs.length===0)c.push(g("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")]);c.push(_("Token Directories",A(["Directory","Current","Status","Token File","Details"],v)))}r.migrated&&c.push(g("success",`Tokens auto-migrated from ${x("node:path").basename(r.from)}.`)),s&&c.push(g("warn","Corrupted token files were cleaned up.")),d.installed?d.verified?c.push(g("success","Context7 MCP is healthy.")):c.push(g("warn",`Context7 MCP configured but not working: ${d.message??"smoke check failed"}. Run \`prjct sync\` to repair.`)):c.push(g("warn","Context7 MCP not configured. Run `prjct sync` to install.")),m.ready?c.push(g("success","READY \u2014 Linear OAuth tokens verified. Restart your AI client to activate.")):c.push(g("error",`NOT READY \u2014 ${m.hint}`)),console.log(X(...c));return}D({provider:"linear",command:"verify",expectedVersion:e.expectedVersion,dirs:e.dirs.map(c=>({version:c.version,isCurrent:c.isCurrent,valid:c.valid,tokenFile:c.tokenFile,reason:c.reason,hasAccessToken:c.hasAccessToken,hasRefreshToken:c.hasRefreshToken})),configValid:t.valid,configAutoFixed:t.autoFixed,migrated:r.migrated,migratedFrom:r.from,cleaned:s,ready:m.ready,hint:m.hint,context7:{installed:d.installed,verified:d.verified,message:d.message}})}o(Ke,"verify");async function Ze(){let e=await q("linear"),t=await H("linear"),n=e.configured?await W("linear"):null;if(G){let r=[];r.push("## Linear MCP Status");let i=[["MCP configured",e.configured?"yes":"no"],["Config valid",t.valid?"yes":`no (${t.issues.join(", ")})`]];n&&(i.push(["OAuth tokens",n.ready?"valid":"missing/invalid"]),n.migrated&&i.push(["Tokens migrated","yes"]),n.cleaned&&i.push(["Corrupted cleaned","yes"]));let a=e.providers.map(s=>[s.provider,s.configured?"yes":"no",s.path]);r.push(A(["Check","Result"],i)),r.push(_("Providers",A(["Provider","Configured","Path"],a))),e.configured?n?.ready?r.push(g("success","Linear MCP is healthy. Restart your AI client if tools are not visible.")):r.push(g("warn",n?.hint??"OAuth tokens not found.")):r.push(g("error","Linear MCP not configured. Run `prjct linear setup` to configure.")),t.autoFixed&&r.push(g("info","MCP config was auto-fixed during this check.")),console.log(X(...r));return}D({provider:"linear",mode:"mcp",configured:e.configured,configValid:t.valid,configAutoFixed:t.autoFixed,oauthReady:n?.ready??!1,oauthValidated:n?.validated??!1,oauthMigrated:n?.migrated??!1,oauthCleaned:n?.cleaned??!1,providers:e.providers,hint:e.configured?n?.hint??"":"Run `prjct linear setup` to configure Linear MCP."})}o(Ze,"status");async function Qe(e,t){let{configured:n}=await q("linear");n||ue("Linear MCP is not configured. Run `prjct linear setup` first."),D({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(Qe,"runMcpOperation");async function et(){try{switch(ce){case"setup":await Ye();break;case"verify":await Ke();break;case"status":await Ze();break;case"help":case"--help":case"-h":case void 0:D({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 Qe(ce,ze);break;default:ue(`Unknown command: ${ce}. Use --help to see available commands.`)}}catch(e){ue(E(e))}}o(et,"main");et();
39
+ `)}o(Ye,"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:Ze,jsonMode:Ae,mdMode:de}=_e();function N(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(N,"output");function le(e,t=1){console.error(Ae?JSON.stringify({error:e}):`Error: ${e}`),process.exit(t)}o(le,"error");async function Qe(){let e=b(),t=x("node:path").join(x("node:os").homedir(),".mcp-auth",`mcp-remote-${e}`),r=await H("linear"),n=await U(t),i=await be("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(F("MCP Config",$(["Provider","Path","Status"],m))),a.migrated&&c.push(f("success",`Tokens migrated from ${x("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(F("Next Steps",Oe([`Open a NEW terminal and run:
40
+ ${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}N({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(Qe,"setup");async function et(){let e=await Re(),t=await H("linear"),r=await B("linear"),n=await W(),i=b(),a=x("node:path").join(x("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 y=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(F("Token Directories",$(["Directory","Current","Status","Token File","Details"],y)))}n.migrated&&u.push(f("success",`Tokens auto-migrated from ${x("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}N({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(et,"verify");async function tt(){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($(["Check","Result"],i)),n.push(F("Providers",$(["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}N({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(tt,"status");async function rt(e,t){let{configured:r}=await B("linear");r||le("Linear MCP is not configured. Run `prjct linear setup` first."),N({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(rt,"runMcpOperation");async function nt(){try{switch(ue){case"setup":await Qe();break;case"verify":await et();break;case"status":await tt();break;case"help":case"--help":case"-h":case void 0:N({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 rt(ue,Ze);break;default:le(`Unknown command: ${ue}. Use --help to see available commands.`)}}catch(e){le(w(e))}}o(nt,"main");nt();