prjct-cli 1.23.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +84 -1
- package/dist/bin/prjct-core.mjs +1748 -0
- package/dist/bin/prjct.mjs +17 -1744
- package/dist/cli/linear.mjs +3 -5
- package/dist/daemon/entry.mjs +1429 -0
- package/package.json +1 -1
- package/dist/bin/prjct.mjs.map +0 -7
- package/dist/cli/linear.mjs.map +0 -7
package/dist/cli/linear.mjs
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
1
|
#!/usr/bin/env node
|
|
3
2
|
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
4
3
|
import { dirname as __pathDirname } from 'path';
|
|
5
4
|
const __filename = __fileURLToPath(import.meta.url);
|
|
6
5
|
const __dirname = __pathDirname(__filename);
|
|
7
|
-
var ae=Object.defineProperty;var o=(r,e)=>ae(r,"name",{value:e,configurable:!0});var ce=(r,e)=>()=>(r&&(e=r(r=0)),e);var je=(r,e)=>{for(var t in e)ae(r,t,{get:e[t],enumerable:!0})};function Oe(r){return r instanceof Error&&"code"in r}function Z(r){return Oe(r)&&r.code==="ENOENT"}function y(r){return r instanceof Error?r.message:typeof r=="string"?r:"Unknown error"}var x=ce(()=>{"use strict";o(Oe,"isNodeError");o(Z,"isNotFoundError");o(y,"getErrorMessage")});var ue={};je(ue,{deleteCredential:()=>$e,getCredential:()=>N,getCredentialWithSource:()=>_e,hasCredential:()=>De,setCredential:()=>Le});import{exec as Ne}from"node:child_process";import{promisify as Re}from"node:util";async function Le(r,e){if(process.platform!=="darwin")return console.warn("[keychain] macOS Keychain only available on macOS"),!1;try{return await D(`security delete-generic-password -s "${_}" -a "${r}" 2>/dev/null || true`),await D(`security add-generic-password -s "${_}" -a "${r}" -w "${e}"`),!0}catch(t){return console.error("[keychain] Failed to store credential:",y(t)),!1}}async function N(r){if(process.platform!=="darwin")return Q(r);try{let{stdout:e}=await D(`security find-generic-password -s "${_}" -a "${r}" -w 2>/dev/null`);return e.trim()||null}catch{return Q(r)}}async function $e(r){if(process.platform!=="darwin")return!1;try{return await D(`security delete-generic-password -s "${_}" -a "${r}" 2>/dev/null`),!0}catch{return!1}}async function De(r){let e=await N(r);return e!==null&&e.length>0}function Q(r){let t={"linear-api-key":"LINEAR_API_KEY","jira-api-token":"JIRA_API_TOKEN"}[r];return process.env[t]||null}async function _e(r){if(process.platform==="darwin")try{let{stdout:t}=await D(`security find-generic-password -s "${_}" -a "${r}" -w 2>/dev/null`),s=t.trim();if(s)return{value:s,source:"keychain"}}catch{}let e=Q(r);return e?{value:e,source:"env"}:{value:null,source:"none"}}var D,_,z=ce(()=>{"use strict";x();D=Re(Ne),_="prjct-cli";o(Le,"setCredential");o(N,"getCredential");o($e,"deleteCredential");o(De,"hasCredential");o(Q,"getEnvFallback");o(_e,"getCredentialWithSource")});var b=class{static{o(this,"TTLCache")}cache=new Map;ttl;maxSize;constructor(e={}){this.ttl=e.ttl??5e3,this.maxSize=e.maxSize??50}isValid(e){let t=this.cache.get(e);return t?Date.now()-t.timestamp<this.ttl:!1}get(e){let t=this.cache.get(e);return t?this.isValid(e)?t.data:(this.cache.delete(e),null):null}set(e,t){this.cache.set(e,{data:t,timestamp:Date.now()}),this.evictOldEntries()}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}has(e){return this.cache.has(e)}get size(){return this.cache.size}evictOldEntries(){if(this.cache.size<=this.maxSize)return;let t=Array.from(this.cache.entries()).sort((s,i)=>s[1].timestamp-i[1].timestamp).slice(0,this.cache.size-this.maxSize);for(let[s]of t)this.cache.delete(s)}stats(){return{size:this.cache.size,maxSize:this.maxSize,ttl:this.ttl}}prune(){let e=0;for(let t of this.cache.keys())this.isValid(t)||(this.cache.delete(t),e++);return e}};var G=300*1e3,f=new b({ttl:G,maxSize:100}),w=new b({ttl:G,maxSize:10}),j=new b({ttl:G,maxSize:5}),O=new b({ttl:G,maxSize:5});function B(){f.clear(),w.clear(),j.clear(),O.clear()}o(B,"clearLinearCache");function X(){return{issues:f.stats(),assignedIssues:w.stats(),teams:j.stats(),projects:O.stats()}}o(X,"getLinearCacheStats");x();z();var Me={backlog:"backlog",unstarted:"todo",started:"in_progress",completed:"done",canceled:"cancelled",cancelled:"cancelled"},Fe={0:"none",1:"urgent",2:"high",3:"medium",4:"low"},le={none:0,urgent:1,high:2,medium:3,low:4},K=class{static{o(this,"LinearProvider")}name="linear";displayName="Linear";sdk=null;config=null;isConfigured(){return this.sdk!==null&&this.config?.enabled===!0}async initialize(e){this.config=e;let t=e.apiKey||await N("linear-api-key");if(!t)throw new Error("LINEAR_API_KEY not configured. Run `p. linear setup` to configure.");let{LinearClient:s}=await import("@linear/sdk");this.sdk=new s({apiKey:t});try{await this.sdk.viewer}catch(i){throw this.sdk=null,new Error(`Linear connection failed: ${y(i)}`)}}async fetchAssignedIssues(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.sdk.viewer,s={};e?.includeCompleted||(s.state={type:{nin:["completed","canceled"]}}),this.config?.defaultTeamId&&(s.team={id:{eq:this.config.defaultTeamId}});let i=await t.assignedIssues({first:e?.limit||50,filter:Object.keys(s).length>0?s:void 0});return Promise.all(i.nodes.map(n=>this.mapIssue(n)))}async fetchTeamIssues(e,t){if(!this.sdk)throw new Error("Linear not initialized");let i=await(await this.sdk.team(e)).issues({first:t?.limit||50,filter:t?.includeCompleted?void 0:{state:{type:{nin:["completed","canceled"]}}}});return Promise.all(i.nodes.map(n=>this.mapIssue(n)))}async fetchIssue(e){if(!this.sdk)throw new Error("Linear not initialized");try{if(e.includes("-")&&/^[A-Z]+-\d+$/.test(e)){let s=e.match(/^([A-Z]+)-(\d+)$/);if(!s)return null;let[,i,n]=s,c=parseInt(n,10),$=(await this.sdk.teams({first:50})).nodes.find(Y=>Y.key===i);if(!$)return null;let A=await $.issues({first:1,filter:{number:{eq:c}}});return A.nodes.length>0?this.mapIssue(A.nodes[0]):null}let t=await this.sdk.issue(e);return this.mapIssue(t)}catch{return null}}async createIssue(e){if(!this.sdk)throw new Error("Linear not initialized");let t=e.teamId||this.config?.defaultTeamId;if(!t)throw new Error("Team ID required for creating issues");let i=await(await this.sdk.createIssue({teamId:t,title:e.title,description:e.description,priority:e.priority?le[e.priority]:void 0,projectId:e.projectId||this.config?.defaultProjectId,assigneeId:e.assigneeId,labelIds:e.labels?await this.resolveLabelIds(t,e.labels):void 0})).issue;if(!i)throw new Error("Failed to create issue");return this.mapIssue(i)}async updateIssue(e,t){if(!this.sdk)throw new Error("Linear not initialized");let s=await this.fetchIssue(e);if(!s)throw new Error(`Issue ${e} not found`);let i={};t.title!==void 0&&(i.title=t.title),t.description!==void 0&&(i.description=t.description),t.priority!==void 0&&(i.priority=le[t.priority]),t.assigneeId!==void 0&&(i.assigneeId=t.assigneeId),t.stateId!==void 0&&(i.stateId=t.stateId),t.projectId!==void 0&&(i.projectId=t.projectId),t.labels!==void 0&&s.team&&(i.labelIds=await this.resolveLabelIds(s.team.id,t.labels)),await this.sdk.updateIssue(s.id,i);let n=await this.fetchIssue(s.id);if(!n)throw new Error("Failed to fetch updated issue");return n}async markInProgress(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.fetchIssue(e);if(!t)throw new Error(`Issue ${e} not found`);let i=await(await this.sdk.issue(t.id)).team;if(!i)throw new Error("Issue has no team");let c=(await i.states()).nodes.find(d=>d.type==="started");c&&await this.sdk.updateIssue(t.id,{stateId:c.id})}async markDone(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.fetchIssue(e);if(!t)throw new Error(`Issue ${e} not found`);let i=await(await this.sdk.issue(t.id)).team;if(!i)throw new Error("Issue has no team");let c=(await i.states()).nodes.find(d=>d.type==="completed");c&&await this.sdk.updateIssue(t.id,{stateId:c.id})}async addComment(e,t){if(!this.sdk)throw new Error("Linear not initialized");let s=await this.fetchIssue(e);if(!s)throw new Error(`Issue ${e} not found`);await this.sdk.createComment({issueId:s.id,body:t})}async getTeams(){if(!this.sdk)throw new Error("Linear not initialized");return(await this.sdk.teams({first:50})).nodes.map(t=>({id:t.id,name:t.name,key:t.key}))}async getProjects(){if(!this.sdk)throw new Error("Linear not initialized");return(await this.sdk.projects({first:50})).nodes.map(t=>({id:t.id,name:t.name}))}async mapIssue(e){let t=await e.state,s=await e.assignee,i=await e.team,n=await e.project,c=await e.labels();return{id:e.id,externalId:e.identifier,provider:"linear",title:e.title,description:e.description||void 0,status:Me[t?.type||"backlog"]||"backlog",priority:Fe[e.priority]||"none",type:this.inferType(e.title,c.nodes.map(d=>d.name)),assignee:s?{id:s.id,name:s.name,email:s.email}:void 0,labels:c.nodes.map(d=>d.name),team:i?{id:i.id,name:i.name,key:i.key}:void 0,project:n?{id:n.id,name:n.name}:void 0,url:e.url,createdAt:e.createdAt.toISOString(),updatedAt:e.updatedAt.toISOString(),raw:e}}inferType(e,t){let s=e.toLowerCase(),i=t.map(n=>n.toLowerCase());return i.includes("bug")||s.includes("fix")||s.includes("bug")?"bug":i.includes("feature")||s.includes("add")||s.includes("implement")?"feature":i.includes("improvement")||s.includes("improve")||s.includes("enhance")?"improvement":i.includes("chore")||s.includes("chore")||s.includes("deps")?"chore":"task"}async resolveLabelIds(e,t){return this.sdk?(await(await this.sdk.team(e)).labels()).nodes.filter(n=>t.includes(n.name)).map(n=>n.id):[]}},h=new K;var J=class{static{o(this,"LinearService")}initialized=!1;userId=null;isReady(){return this.initialized&&h.isConfigured()}async initialize(e){this.initialized||(await h.initialize(e),this.initialized=!0)}async initializeFromApiKey(e,t){let s={enabled:!0,provider:"linear",apiKey:e,defaultTeamId:t,syncOn:{task:!0,done:!0,ship:!0},enrichment:{enabled:!0,updateProvider:!0}};await this.initialize(s)}async fetchAssignedIssues(e){this.ensureInitialized();let t=`assigned:${this.userId||"me"}`,s=w.get(t);if(s)return s;let i=await h.fetchAssignedIssues(e);w.set(t,i);for(let n of i)f.set(`issue:${n.id}`,n),f.set(`issue:${n.externalId}`,n);return i}async fetchTeamIssues(e,t){this.ensureInitialized();let s=`team:${e}`,i=w.get(s);if(i)return i;let n=await h.fetchTeamIssues(e,t);w.set(s,n);for(let c of n)f.set(`issue:${c.id}`,c),f.set(`issue:${c.externalId}`,c);return n}async fetchIssue(e){this.ensureInitialized();let t=`issue:${e}`,s=f.get(t);if(s)return s;let i=await h.fetchIssue(e);return i&&(f.set(`issue:${i.id}`,i),f.set(`issue:${i.externalId}`,i)),i}async createIssue(e){this.ensureInitialized();let t=await h.createIssue(e);return f.set(`issue:${t.id}`,t),f.set(`issue:${t.externalId}`,t),w.clear(),t}async updateIssue(e,t){this.ensureInitialized();let s=await h.updateIssue(e,t);return f.set(`issue:${s.id}`,s),f.set(`issue:${s.externalId}`,s),s}async markInProgress(e){this.ensureInitialized(),await h.markInProgress(e),f.delete(`issue:${e}`),w.clear()}async markDone(e){this.ensureInitialized(),await h.markDone(e),f.delete(`issue:${e}`),w.clear()}async addComment(e,t){this.ensureInitialized(),await h.addComment(e,t)}async getTeams(){this.ensureInitialized();let e=j.get("teams");if(e)return e;let t=await h.getTeams();return j.set("teams",t),t}async getProjects(){this.ensureInitialized();let e=O.get("projects");if(e)return e;let t=await h.getProjects();return O.set("projects",t),t}clearCache(){B()}getCacheStats(){return X()}ensureInitialized(){if(!this.initialized)throw new Error("Linear service not initialized. Call linearService.initialize() first or run `p. linear setup`.")}},l=new J;import{mkdir as ge,readFile as qe,writeFile as he}from"node:fs/promises";import{join as M}from"node:path";import{z as a}from"zod";var de=a.enum(["linear","jira","github","monday","asana","none"]),Ue=a.enum(["backlog","todo","in_progress","in_review","done","cancelled"]),Ge=a.enum(["none","urgent","high","medium","low"]),ze=a.enum(["feature","bug","improvement","task","chore","epic"]),Ke=a.object({id:a.string(),identifier:a.string(),title:a.string(),description:a.string().optional(),status:Ue,priority:Ge,type:ze.optional(),assignee:a.object({id:a.string(),name:a.string(),email:a.string().optional()}).optional(),labels:a.array(a.string()).default([]),team:a.object({id:a.string(),name:a.string(),key:a.string().optional()}).optional(),project:a.object({id:a.string(),name:a.string()}).optional(),url:a.string(),createdAt:a.string(),updatedAt:a.string(),fetchedAt:a.string()}),Je=a.object({provider:de,lastSync:a.string(),staleAfter:a.number().default(18e5),issues:a.record(a.string(),Ke)}),bt=a.object({provider:de,fetched:a.number(),updated:a.number(),errors:a.array(a.object({issueId:a.string(),error:a.string()})),timestamp:a.string()}),pe=o(r=>Je.parse(r),"parseIssues");function me(r){return{provider:r,lastSync:"",staleAfter:18e5,issues:{}}}o(me,"createEmptyIssues");import{homedir as We}from"node:os";import{join as fe}from"node:path";var Ve=fe(We(),".prjct-cli","projects");function W(r){return fe(Ve,r)}o(W,"getProjectPath");x();import He from"node:fs/promises";x();x();async function E(r){try{return await He.access(r),!0}catch(e){if(Z(e))return!1;throw e}}o(E,"fileExists");var ye=1800*1e3,V=class{static{o(this,"LinearSync")}async pullAll(e){let t=M(W(e),"storage"),s=M(t,"issues.json");await E(t)||await ge(t,{recursive:!0});let i=new Date().toISOString(),n=[];try{let c=await l.fetchAssignedIssues({limit:100}),d={};for(let A of c)try{d[A.externalId]=this.toCachedIssue(A,i)}catch(Y){n.push({issueId:A.externalId||A.id,error:y(Y)})}return await he(s,JSON.stringify({provider:"linear",lastSync:i,staleAfter:ye,issues:d},null,2)),{provider:"linear",fetched:c.length,updated:Object.keys(d).length,errors:n,timestamp:i}}catch(c){return n.push({issueId:"all",error:y(c)}),{provider:"linear",fetched:0,updated:0,errors:n,timestamp:i}}}async getIssue(e,t){let s=await this.loadIssues(e);if(s?.issues[t]){let i=s.issues[t],n=new Date(i.fetchedAt).getTime(),c=Date.now(),d=600*1e3;if(c-n<d)return i}try{let i=await l.fetchIssue(t);if(!i)return null;let n=new Date().toISOString(),c=this.toCachedIssue(i,n);return await this.updateIssueInCache(e,t,c),c}catch{return s?.issues[t]?s.issues[t]:null}}async getIssueLocal(e,t){return(await this.loadIssues(e))?.issues[t]||null}async pushStatus(e,t,s){s==="in_progress"?await l.markInProgress(t):s==="done"&&await l.markDone(t);let i=await this.loadIssues(e);if(i?.issues[t]){let n=s==="done"?"done":"in_progress";i.issues[t].status=n,i.issues[t].fetchedAt=new Date().toISOString(),await this.saveIssues(e,i)}}async isStale(e){let t=await this.loadIssues(e);if(!t||!t.lastSync)return!0;let s=new Date(t.lastSync).getTime(),i=Date.now(),n=t.staleAfter||ye;return i-s>n}async getSyncStatus(e){let t=await this.loadIssues(e);return t?{hasCache:!0,lastSync:t.lastSync||null,issueCount:Object.keys(t.issues).length,isStale:await this.isStale(e)}:{hasCache:!1,lastSync:null,issueCount:0,isStale:!0}}async listCachedIssues(e){let t=await this.loadIssues(e);return t?Object.values(t.issues):[]}async loadIssues(e){let t=M(W(e),"storage","issues.json");if(!await E(t))return null;try{let s=await qe(t,"utf-8");return pe(JSON.parse(s))}catch{return null}}async saveIssues(e,t){let s=M(W(e),"storage"),i=M(s,"issues.json");await E(s)||await ge(s,{recursive:!0}),await he(i,JSON.stringify(t,null,2))}async updateIssueInCache(e,t,s){let i=await this.loadIssues(e);i||(i=me("linear")),i.issues[t]=s,await this.saveIssues(e,i)}toCachedIssue(e,t){return{id:e.id,identifier:e.externalId,title:e.title,description:e.description,status:e.status,priority:e.priority,type:e.type,assignee:e.assignee,labels:e.labels,team:e.team,project:e.project,url:e.url,createdAt:e.createdAt,updatedAt:e.updatedAt,fetchedAt:t}}},F=new V;x();import I from"chalk";import k from"chalk";import{exec as Ze}from"node:child_process";import R from"node:os";import L from"node:path";import{promisify as Qe}from"node:util";import{z as S}from"zod";var nr=S.enum(["opus","sonnet","haiku"]),or=S.enum(["2.5-pro","2.5-flash","2.0-flash"]),ar=S.string().min(1);var Ye=S.object({provider:S.string(),model:S.string(),cliVersion:S.string().optional(),recordedAt:S.string()}),cr=S.object({preferredModel:S.string().optional(),lastAnalysisModel:Ye.optional()});import Be from"node:os";import Ie from"node:path";var Xe=Ie.join(Be.homedir(),".prjct-cli","cache"),mr=Ie.join(Xe,"providers.json"),fr=600*1e3;var Ar=Qe(Ze);var br={name:"claude",displayName:"Claude Code",cliCommand:"claude",configDir:L.join(R.homedir(),".claude"),contextFile:"CLAUDE.md",skillsDir:L.join(R.homedir(),".claude","skills"),commandsDir:".claude/commands",commandFormat:"md",settingsFile:"settings.json",projectSettingsFile:"settings.local.json",ignoreFile:".claudeignore",websiteUrl:"https://www.anthropic.com/claude",docsUrl:"https://docs.anthropic.com/claude-code",defaultModel:"sonnet",supportedModels:["opus","sonnet","haiku"],minCliVersion:"1.0.0"},kr={name:"gemini",displayName:"Gemini CLI",cliCommand:"gemini",configDir:L.join(R.homedir(),".gemini"),contextFile:"GEMINI.md",skillsDir:L.join(R.homedir(),".gemini","skills"),commandsDir:".gemini/commands",commandFormat:"toml",settingsFile:"settings.json",projectSettingsFile:"settings.json",ignoreFile:".geminiignore",websiteUrl:"https://geminicli.com",docsUrl:"https://geminicli.com/docs",defaultModel:"2.5-flash",supportedModels:["2.5-pro","2.5-flash","2.0-flash"],minCliVersion:"1.0.0"},jr={name:"antigravity",displayName:"Google Antigravity",cliCommand:null,configDir:L.join(R.homedir(),".gemini","antigravity"),contextFile:"ANTIGRAVITY.md",skillsDir:L.join(R.homedir(),".gemini","antigravity","global_skills"),commandsDir:".agent/skills",commandFormat:"md",settingsFile:"mcp_config.json",projectSettingsFile:null,ignoreFile:".agentignore",websiteUrl:"https://gemini.google.com/app/antigravity",docsUrl:"https://gemini.google.com/app/antigravity",defaultModel:null,supportedModels:[],minCliVersion:null};function ee(r){return{commitFooter:"Generated with [p/](https://www.prjct.app/)",signature:{claude:"\u26A1 prjct + Claude",gemini:"\u26A1 prjct + Gemini",cursor:"\u26A1 prjct + Cursor",antigravity:"\u26A1 prjct + Antigravity",windsurf:"\u26A1 prjct + Windsurf"}[r]||"\u26A1 prjct"}}o(ee,"getProviderBranding");var we=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],et=80,tt={name:"prjct",icon:"\u26A1",signature:"\u26A1 prjct",spinner:{frames:we,speed:et},cli:{header:o(()=>`${k.cyan.bold("\u26A1")} ${k.cyan("prjct")}`,"header"),footer:o(()=>k.dim("\u26A1 prjct"),"footer"),spin:o((r,e)=>`${k.cyan("\u26A1")} ${k.cyan("prjct")} ${k.cyan(we[r%10])} ${k.dim(e||"")}`,"spin")},template:{header:"\u26A1 prjct",footer:"\u26A1 prjct"},commitFooter:"Generated with [p/](https://www.prjct.app/)",urls:{website:"https://prjct.app",docs:"https://prjct.app/docs"},getCommitFooter:o((r="claude")=>ee(r).commitFooter,"getCommitFooter"),getSignature:o((r="claude")=>ee(r).signature,"getSignature")},te=tt;var re={SPINNER_MSG:45,DONE_MSG:50,FAIL_MSG:65,WARN_MSG:65,STEP_MSG:35,PROGRESS_TEXT:25,ISSUE_TITLE:50,FALLBACK_TRUNCATE:50,CLEAR_WIDTH:80};var Yr=te.spinner.frames,Br=te.spinner.speed,st={silent:{maxLines:0,maxCharsPerLine:0,showMetrics:!1},minimal:{maxLines:1,maxCharsPerLine:65,showMetrics:!1},compact:{maxLines:4,maxCharsPerLine:80,showMetrics:!0},verbose:{maxLines:1/0,maxCharsPerLine:1/0,showMetrics:!0}},U="compact";function Se(r){U=r}o(Se,"setOutputTier");function ie(){return st[U]}o(ie,"getTierConfig");var Xr={success:I.green("\u2713"),fail:I.red("\u2717"),warn:I.yellow("\u26A0"),info:I.blue("\u2139"),debug:I.dim("\u{1F527}"),bullet:I.dim("\u2022"),arrow:I.dim("\u2192"),check:I.green("\u2713"),cross:I.red("\u2717"),spinner:I.cyan("\u25D0")};var H=o((r,e)=>{let t=e??(ie().maxCharsPerLine||re.FALLBACK_TRUNCATE);return r&&r.length>t?`${r.slice(0,t-1)}\u2026`:r||""},"truncate");function se(r,e){let t=e??ie().maxLines;if(t===1/0||t===0)return r;let s=r.split(`
|
|
6
|
+
var ae=Object.defineProperty;var o=(r,e)=>ae(r,"name",{value:e,configurable:!0});var ce=(r,e)=>()=>(r&&(e=r(r=0)),e);var je=(r,e)=>{for(var t in e)ae(r,t,{get:e[t],enumerable:!0})};function Oe(r){return r instanceof Error&&"code"in r}function Z(r){return Oe(r)&&r.code==="ENOENT"}function y(r){return r instanceof Error?r.message:typeof r=="string"?r:"Unknown error"}var E=ce(()=>{"use strict";o(Oe,"isNodeError");o(Z,"isNotFoundError");o(y,"getErrorMessage")});var ue={};je(ue,{deleteCredential:()=>$e,getCredential:()=>N,getCredentialWithSource:()=>_e,hasCredential:()=>De,setCredential:()=>Le});import{exec as Ne}from"node:child_process";import{promisify as Re}from"node:util";async function Le(r,e){if(process.platform!=="darwin")return console.warn("[keychain] macOS Keychain only available on macOS"),!1;try{return await D(`security delete-generic-password -s "${_}" -a "${r}" 2>/dev/null || true`),await D(`security add-generic-password -s "${_}" -a "${r}" -w "${e}"`),!0}catch(t){return console.error("[keychain] Failed to store credential:",y(t)),!1}}async function N(r){if(process.platform!=="darwin")return Q(r);try{let{stdout:e}=await D(`security find-generic-password -s "${_}" -a "${r}" -w 2>/dev/null`);return e.trim()||null}catch{return Q(r)}}async function $e(r){if(process.platform!=="darwin")return!1;try{return await D(`security delete-generic-password -s "${_}" -a "${r}" 2>/dev/null`),!0}catch{return!1}}async function De(r){let e=await N(r);return e!==null&&e.length>0}function Q(r){let t={"linear-api-key":"LINEAR_API_KEY","jira-api-token":"JIRA_API_TOKEN"}[r];return process.env[t]||null}async function _e(r){if(process.platform==="darwin")try{let{stdout:t}=await D(`security find-generic-password -s "${_}" -a "${r}" -w 2>/dev/null`),s=t.trim();if(s)return{value:s,source:"keychain"}}catch{}let e=Q(r);return e?{value:e,source:"env"}:{value:null,source:"none"}}var D,_,z=ce(()=>{"use strict";E();D=Re(Ne),_="prjct-cli";o(Le,"setCredential");o(N,"getCredential");o($e,"deleteCredential");o(De,"hasCredential");o(Q,"getEnvFallback");o(_e,"getCredentialWithSource")});var k=class{static{o(this,"TTLCache")}cache=new Map;ttl;maxSize;constructor(e={}){this.ttl=e.ttl??5e3,this.maxSize=e.maxSize??50}isValid(e){let t=this.cache.get(e);return t?Date.now()-t.timestamp<this.ttl:!1}get(e){let t=this.cache.get(e);return t?this.isValid(e)?t.data:(this.cache.delete(e),null):null}set(e,t){this.cache.set(e,{data:t,timestamp:Date.now()}),this.evictOldEntries()}delete(e){this.cache.delete(e)}clear(){this.cache.clear()}has(e){return this.cache.has(e)}get size(){return this.cache.size}evictOldEntries(){if(this.cache.size<=this.maxSize)return;let t=Array.from(this.cache.entries()).sort((s,i)=>s[1].timestamp-i[1].timestamp).slice(0,this.cache.size-this.maxSize);for(let[s]of t)this.cache.delete(s)}stats(){return{size:this.cache.size,maxSize:this.maxSize,ttl:this.ttl}}prune(){let e=0;for(let t of this.cache.keys())this.isValid(t)||(this.cache.delete(t),e++);return e}};var G=300*1e3,f=new k({ttl:G,maxSize:100}),w=new k({ttl:G,maxSize:10}),j=new k({ttl:G,maxSize:5}),O=new k({ttl:G,maxSize:5});function B(){f.clear(),w.clear(),j.clear(),O.clear()}o(B,"clearLinearCache");function X(){return{issues:f.stats(),assignedIssues:w.stats(),teams:j.stats(),projects:O.stats()}}o(X,"getLinearCacheStats");E();z();var Me={backlog:"backlog",unstarted:"todo",started:"in_progress",completed:"done",canceled:"cancelled",cancelled:"cancelled"},Fe={0:"none",1:"urgent",2:"high",3:"medium",4:"low"},le={none:0,urgent:1,high:2,medium:3,low:4},K=class{static{o(this,"LinearProvider")}name="linear";displayName="Linear";sdk=null;config=null;isConfigured(){return this.sdk!==null&&this.config?.enabled===!0}async initialize(e){this.config=e;let t=e.apiKey||await N("linear-api-key");if(!t)throw new Error("LINEAR_API_KEY not configured. Run `p. linear setup` to configure.");let{LinearClient:s}=await import("@linear/sdk");this.sdk=new s({apiKey:t});try{await this.sdk.viewer}catch(i){throw this.sdk=null,new Error(`Linear connection failed: ${y(i)}`)}}async fetchAssignedIssues(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.sdk.viewer,s={};e?.includeCompleted||(s.state={type:{nin:["completed","canceled"]}}),this.config?.defaultTeamId&&(s.team={id:{eq:this.config.defaultTeamId}});let i=await t.assignedIssues({first:e?.limit||50,filter:Object.keys(s).length>0?s:void 0});return Promise.all(i.nodes.map(n=>this.mapIssue(n)))}async fetchTeamIssues(e,t){if(!this.sdk)throw new Error("Linear not initialized");let i=await(await this.sdk.team(e)).issues({first:t?.limit||50,filter:t?.includeCompleted?void 0:{state:{type:{nin:["completed","canceled"]}}}});return Promise.all(i.nodes.map(n=>this.mapIssue(n)))}async fetchIssue(e){if(!this.sdk)throw new Error("Linear not initialized");try{if(e.includes("-")&&/^[A-Z]+-\d+$/.test(e)){let s=e.match(/^([A-Z]+)-(\d+)$/);if(!s)return null;let[,i,n]=s,c=parseInt(n,10),$=(await this.sdk.teams({first:50})).nodes.find(Y=>Y.key===i);if(!$)return null;let A=await $.issues({first:1,filter:{number:{eq:c}}});return A.nodes.length>0?this.mapIssue(A.nodes[0]):null}let t=await this.sdk.issue(e);return this.mapIssue(t)}catch{return null}}async createIssue(e){if(!this.sdk)throw new Error("Linear not initialized");let t=e.teamId||this.config?.defaultTeamId;if(!t)throw new Error("Team ID required for creating issues");let i=await(await this.sdk.createIssue({teamId:t,title:e.title,description:e.description,priority:e.priority?le[e.priority]:void 0,projectId:e.projectId||this.config?.defaultProjectId,assigneeId:e.assigneeId,labelIds:e.labels?await this.resolveLabelIds(t,e.labels):void 0})).issue;if(!i)throw new Error("Failed to create issue");return this.mapIssue(i)}async updateIssue(e,t){if(!this.sdk)throw new Error("Linear not initialized");let s=await this.fetchIssue(e);if(!s)throw new Error(`Issue ${e} not found`);let i={};t.title!==void 0&&(i.title=t.title),t.description!==void 0&&(i.description=t.description),t.priority!==void 0&&(i.priority=le[t.priority]),t.assigneeId!==void 0&&(i.assigneeId=t.assigneeId),t.stateId!==void 0&&(i.stateId=t.stateId),t.projectId!==void 0&&(i.projectId=t.projectId),t.labels!==void 0&&s.team&&(i.labelIds=await this.resolveLabelIds(s.team.id,t.labels)),await this.sdk.updateIssue(s.id,i);let n=await this.fetchIssue(s.id);if(!n)throw new Error("Failed to fetch updated issue");return n}async markInProgress(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.fetchIssue(e);if(!t)throw new Error(`Issue ${e} not found`);let i=await(await this.sdk.issue(t.id)).team;if(!i)throw new Error("Issue has no team");let c=(await i.states()).nodes.find(d=>d.type==="started");c&&await this.sdk.updateIssue(t.id,{stateId:c.id})}async markDone(e){if(!this.sdk)throw new Error("Linear not initialized");let t=await this.fetchIssue(e);if(!t)throw new Error(`Issue ${e} not found`);let i=await(await this.sdk.issue(t.id)).team;if(!i)throw new Error("Issue has no team");let c=(await i.states()).nodes.find(d=>d.type==="completed");c&&await this.sdk.updateIssue(t.id,{stateId:c.id})}async addComment(e,t){if(!this.sdk)throw new Error("Linear not initialized");let s=await this.fetchIssue(e);if(!s)throw new Error(`Issue ${e} not found`);await this.sdk.createComment({issueId:s.id,body:t})}async getTeams(){if(!this.sdk)throw new Error("Linear not initialized");return(await this.sdk.teams({first:50})).nodes.map(t=>({id:t.id,name:t.name,key:t.key}))}async getProjects(){if(!this.sdk)throw new Error("Linear not initialized");return(await this.sdk.projects({first:50})).nodes.map(t=>({id:t.id,name:t.name}))}async mapIssue(e){let t=await e.state,s=await e.assignee,i=await e.team,n=await e.project,c=await e.labels();return{id:e.id,externalId:e.identifier,provider:"linear",title:e.title,description:e.description||void 0,status:Me[t?.type||"backlog"]||"backlog",priority:Fe[e.priority]||"none",type:this.inferType(e.title,c.nodes.map(d=>d.name)),assignee:s?{id:s.id,name:s.name,email:s.email}:void 0,labels:c.nodes.map(d=>d.name),team:i?{id:i.id,name:i.name,key:i.key}:void 0,project:n?{id:n.id,name:n.name}:void 0,url:e.url,createdAt:e.createdAt.toISOString(),updatedAt:e.updatedAt.toISOString(),raw:e}}inferType(e,t){let s=e.toLowerCase(),i=t.map(n=>n.toLowerCase());return i.includes("bug")||s.includes("fix")||s.includes("bug")?"bug":i.includes("feature")||s.includes("add")||s.includes("implement")?"feature":i.includes("improvement")||s.includes("improve")||s.includes("enhance")?"improvement":i.includes("chore")||s.includes("chore")||s.includes("deps")?"chore":"task"}async resolveLabelIds(e,t){return this.sdk?(await(await this.sdk.team(e)).labels()).nodes.filter(n=>t.includes(n.name)).map(n=>n.id):[]}},h=new K;var J=class{static{o(this,"LinearService")}initialized=!1;userId=null;isReady(){return this.initialized&&h.isConfigured()}async initialize(e){this.initialized||(await h.initialize(e),this.initialized=!0)}async initializeFromApiKey(e,t){let s={enabled:!0,provider:"linear",apiKey:e,defaultTeamId:t,syncOn:{task:!0,done:!0,ship:!0},enrichment:{enabled:!0,updateProvider:!0}};await this.initialize(s)}async fetchAssignedIssues(e){this.ensureInitialized();let t=`assigned:${this.userId||"me"}`,s=w.get(t);if(s)return s;let i=await h.fetchAssignedIssues(e);w.set(t,i);for(let n of i)f.set(`issue:${n.id}`,n),f.set(`issue:${n.externalId}`,n);return i}async fetchTeamIssues(e,t){this.ensureInitialized();let s=`team:${e}`,i=w.get(s);if(i)return i;let n=await h.fetchTeamIssues(e,t);w.set(s,n);for(let c of n)f.set(`issue:${c.id}`,c),f.set(`issue:${c.externalId}`,c);return n}async fetchIssue(e){this.ensureInitialized();let t=`issue:${e}`,s=f.get(t);if(s)return s;let i=await h.fetchIssue(e);return i&&(f.set(`issue:${i.id}`,i),f.set(`issue:${i.externalId}`,i)),i}async createIssue(e){this.ensureInitialized();let t=await h.createIssue(e);return f.set(`issue:${t.id}`,t),f.set(`issue:${t.externalId}`,t),w.clear(),t}async updateIssue(e,t){this.ensureInitialized();let s=await h.updateIssue(e,t);return f.set(`issue:${s.id}`,s),f.set(`issue:${s.externalId}`,s),s}async markInProgress(e){this.ensureInitialized(),await h.markInProgress(e),f.delete(`issue:${e}`),w.clear()}async markDone(e){this.ensureInitialized(),await h.markDone(e),f.delete(`issue:${e}`),w.clear()}async addComment(e,t){this.ensureInitialized(),await h.addComment(e,t)}async getTeams(){this.ensureInitialized();let e=j.get("teams");if(e)return e;let t=await h.getTeams();return j.set("teams",t),t}async getProjects(){this.ensureInitialized();let e=O.get("projects");if(e)return e;let t=await h.getProjects();return O.set("projects",t),t}clearCache(){B()}getCacheStats(){return X()}ensureInitialized(){if(!this.initialized)throw new Error("Linear service not initialized. Call linearService.initialize() first or run `p. linear setup`.")}},l=new J;import{mkdir as ge,readFile as qe,writeFile as he}from"node:fs/promises";import{join as M}from"node:path";import{z as a}from"zod";var de=a.enum(["linear","jira","github","monday","asana","none"]),Ue=a.enum(["backlog","todo","in_progress","in_review","done","cancelled"]),Ge=a.enum(["none","urgent","high","medium","low"]),ze=a.enum(["feature","bug","improvement","task","chore","epic"]),Ke=a.object({id:a.string(),identifier:a.string(),title:a.string(),description:a.string().optional(),status:Ue,priority:Ge,type:ze.optional(),assignee:a.object({id:a.string(),name:a.string(),email:a.string().optional()}).optional(),labels:a.array(a.string()).default([]),team:a.object({id:a.string(),name:a.string(),key:a.string().optional()}).optional(),project:a.object({id:a.string(),name:a.string()}).optional(),url:a.string(),createdAt:a.string(),updatedAt:a.string(),fetchedAt:a.string()}),Je=a.object({provider:de,lastSync:a.string(),staleAfter:a.number().default(18e5),issues:a.record(a.string(),Ke)}),kt=a.object({provider:de,fetched:a.number(),updated:a.number(),errors:a.array(a.object({issueId:a.string(),error:a.string()})),timestamp:a.string()}),pe=o(r=>Je.parse(r),"parseIssues");function me(r){return{provider:r,lastSync:"",staleAfter:18e5,issues:{}}}o(me,"createEmptyIssues");import{homedir as We}from"node:os";import{join as fe}from"node:path";var Ve=fe(We(),".prjct-cli","projects");function W(r){return fe(Ve,r)}o(W,"getProjectPath");E();import He from"node:fs/promises";E();E();async function v(r){try{return await He.access(r),!0}catch(e){if(Z(e))return!1;throw e}}o(v,"fileExists");var ye=1800*1e3,V=class{static{o(this,"LinearSync")}async pullAll(e){let t=M(W(e),"storage"),s=M(t,"issues.json");await v(t)||await ge(t,{recursive:!0});let i=new Date().toISOString(),n=[];try{let c=await l.fetchAssignedIssues({limit:100}),d={};for(let A of c)try{d[A.externalId]=this.toCachedIssue(A,i)}catch(Y){n.push({issueId:A.externalId||A.id,error:y(Y)})}return await he(s,JSON.stringify({provider:"linear",lastSync:i,staleAfter:ye,issues:d},null,2)),{provider:"linear",fetched:c.length,updated:Object.keys(d).length,errors:n,timestamp:i}}catch(c){return n.push({issueId:"all",error:y(c)}),{provider:"linear",fetched:0,updated:0,errors:n,timestamp:i}}}async getIssue(e,t){let s=await this.loadIssues(e);if(s?.issues[t]){let i=s.issues[t],n=new Date(i.fetchedAt).getTime(),c=Date.now(),d=600*1e3;if(c-n<d)return i}try{let i=await l.fetchIssue(t);if(!i)return null;let n=new Date().toISOString(),c=this.toCachedIssue(i,n);return await this.updateIssueInCache(e,t,c),c}catch{return s?.issues[t]?s.issues[t]:null}}async getIssueLocal(e,t){return(await this.loadIssues(e))?.issues[t]||null}async pushStatus(e,t,s){s==="in_progress"?await l.markInProgress(t):s==="done"&&await l.markDone(t);let i=await this.loadIssues(e);if(i?.issues[t]){let n=s==="done"?"done":"in_progress";i.issues[t].status=n,i.issues[t].fetchedAt=new Date().toISOString(),await this.saveIssues(e,i)}}async isStale(e){let t=await this.loadIssues(e);if(!t||!t.lastSync)return!0;let s=new Date(t.lastSync).getTime(),i=Date.now(),n=t.staleAfter||ye;return i-s>n}async getSyncStatus(e){let t=await this.loadIssues(e);return t?{hasCache:!0,lastSync:t.lastSync||null,issueCount:Object.keys(t.issues).length,isStale:await this.isStale(e)}:{hasCache:!1,lastSync:null,issueCount:0,isStale:!0}}async listCachedIssues(e){let t=await this.loadIssues(e);return t?Object.values(t.issues):[]}async loadIssues(e){let t=M(W(e),"storage","issues.json");if(!await v(t))return null;try{let s=await qe(t,"utf-8");return pe(JSON.parse(s))}catch{return null}}async saveIssues(e,t){let s=M(W(e),"storage"),i=M(s,"issues.json");await v(s)||await ge(s,{recursive:!0}),await he(i,JSON.stringify(t,null,2))}async updateIssueInCache(e,t,s){let i=await this.loadIssues(e);i||(i=me("linear")),i.issues[t]=s,await this.saveIssues(e,i)}toCachedIssue(e,t){return{id:e.id,identifier:e.externalId,title:e.title,description:e.description,status:e.status,priority:e.priority,type:e.type,assignee:e.assignee,labels:e.labels,team:e.team,project:e.project,url:e.url,createdAt:e.createdAt,updatedAt:e.updatedAt,fetchedAt:t}}},F=new V;E();import I from"chalk";import b from"chalk";import{exec as Ze}from"node:child_process";import R from"node:os";import L from"node:path";import{promisify as Qe}from"node:util";import{z as S}from"zod";var nr=S.enum(["opus","sonnet","haiku"]),or=S.enum(["2.5-pro","2.5-flash","2.0-flash"]),ar=S.string().min(1);var Ye=S.object({provider:S.string(),model:S.string(),cliVersion:S.string().optional(),recordedAt:S.string()}),cr=S.object({preferredModel:S.string().optional(),lastAnalysisModel:Ye.optional()});import Be from"node:os";import Ie from"node:path";var Xe=Ie.join(Be.homedir(),".prjct-cli","cache"),mr=Ie.join(Xe,"providers.json"),fr=600*1e3;var Ar=Qe(Ze);var kr={name:"claude",displayName:"Claude Code",cliCommand:"claude",configDir:L.join(R.homedir(),".claude"),contextFile:"CLAUDE.md",skillsDir:L.join(R.homedir(),".claude","skills"),commandsDir:".claude/commands",commandFormat:"md",settingsFile:"settings.json",projectSettingsFile:"settings.local.json",ignoreFile:".claudeignore",websiteUrl:"https://www.anthropic.com/claude",docsUrl:"https://docs.anthropic.com/claude-code",defaultModel:"sonnet",supportedModels:["opus","sonnet","haiku"],minCliVersion:"1.0.0"},br={name:"gemini",displayName:"Gemini CLI",cliCommand:"gemini",configDir:L.join(R.homedir(),".gemini"),contextFile:"GEMINI.md",skillsDir:L.join(R.homedir(),".gemini","skills"),commandsDir:".gemini/commands",commandFormat:"toml",settingsFile:"settings.json",projectSettingsFile:"settings.json",ignoreFile:".geminiignore",websiteUrl:"https://geminicli.com",docsUrl:"https://geminicli.com/docs",defaultModel:"2.5-flash",supportedModels:["2.5-pro","2.5-flash","2.0-flash"],minCliVersion:"1.0.0"},jr={name:"antigravity",displayName:"Google Antigravity",cliCommand:null,configDir:L.join(R.homedir(),".gemini","antigravity"),contextFile:"ANTIGRAVITY.md",skillsDir:L.join(R.homedir(),".gemini","antigravity","global_skills"),commandsDir:".agent/skills",commandFormat:"md",settingsFile:"mcp_config.json",projectSettingsFile:null,ignoreFile:".agentignore",websiteUrl:"https://gemini.google.com/app/antigravity",docsUrl:"https://gemini.google.com/app/antigravity",defaultModel:null,supportedModels:[],minCliVersion:null};function ee(r){return{commitFooter:"Generated with [p/](https://www.prjct.app/)",signature:{claude:"\u26A1 prjct + Claude",gemini:"\u26A1 prjct + Gemini",cursor:"\u26A1 prjct + Cursor",antigravity:"\u26A1 prjct + Antigravity",windsurf:"\u26A1 prjct + Windsurf"}[r]||"\u26A1 prjct"}}o(ee,"getProviderBranding");var we=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],et=80,tt={name:"prjct",icon:"\u26A1",signature:"\u26A1 prjct",spinner:{frames:we,speed:et},cli:{header:o(()=>`${b.cyan.bold("\u26A1")} ${b.cyan("prjct")}`,"header"),footer:o(()=>b.dim("\u26A1 prjct"),"footer"),spin:o((r,e)=>`${b.cyan("\u26A1")} ${b.cyan("prjct")} ${b.cyan(we[r%10])} ${b.dim(e||"")}`,"spin")},template:{header:"\u26A1 prjct",footer:"\u26A1 prjct"},commitFooter:"Generated with [p/](https://www.prjct.app/)",urls:{website:"https://prjct.app",docs:"https://prjct.app/docs"},getCommitFooter:o((r="claude")=>ee(r).commitFooter,"getCommitFooter"),getSignature:o((r="claude")=>ee(r).signature,"getSignature")},te=tt;var re={SPINNER_MSG:45,DONE_MSG:50,FAIL_MSG:65,WARN_MSG:65,STEP_MSG:35,PROGRESS_TEXT:25,ISSUE_TITLE:50,FALLBACK_TRUNCATE:50,CLEAR_WIDTH:80};var Yr=te.spinner.frames,Br=te.spinner.speed,st={silent:{maxLines:0,maxCharsPerLine:0,showMetrics:!1},minimal:{maxLines:1,maxCharsPerLine:65,showMetrics:!1},compact:{maxLines:4,maxCharsPerLine:80,showMetrics:!0},verbose:{maxLines:1/0,maxCharsPerLine:1/0,showMetrics:!0}},U="compact";function Se(r){U=r}o(Se,"setOutputTier");function ie(){return st[U]}o(ie,"getTierConfig");var Xr={success:I.green("\u2713"),fail:I.red("\u2717"),warn:I.yellow("\u26A0"),info:I.blue("\u2139"),debug:I.dim("\u{1F527}"),bullet:I.dim("\u2022"),arrow:I.dim("\u2192"),check:I.green("\u2713"),cross:I.red("\u2717"),spinner:I.cyan("\u25D0")};var H=o((r,e)=>{let t=e??(ie().maxCharsPerLine||re.FALLBACK_TRUNCATE);return r&&r.length>t?`${r.slice(0,t-1)}\u2026`:r||""},"truncate");function se(r,e){let t=e??ie().maxLines;if(t===1/0||t===0)return r;let s=r.split(`
|
|
8
7
|
`);if(s.length<=t)return r;let i=s.slice(0,t),n=s.length-t;return`${i.join(`
|
|
9
8
|
`)}
|
|
10
|
-
${I.dim(`...${n} more lines`)}`}o(se,"limitLines");function
|
|
9
|
+
${I.dim(`...${n} more lines`)}`}o(se,"limitLines");function xe(r){let e=ie();if(U==="silent")return"";if(U==="verbose")return JSON.stringify(r,null,2);if(typeof r!="object"||r===null)return H(String(r),e.maxCharsPerLine);let t=r;if("identifier"in t&&"title"in t){let n=[];return n.push(`${t.identifier}: ${H(String(t.title),e.maxCharsPerLine-10)}`),t.status&&n.push(`Status: ${t.status}`),t.priority&&t.priority!=="none"&&n.push(`Priority: ${t.priority}`),t.url&&U==="compact"&&n.push(I.dim(String(t.url))),se(n.join(`
|
|
11
10
|
`),e.maxLines)}if("issues"in t&&Array.isArray(t.issues)){let n=t.issues,c=n.slice(0,e.maxLines).map(d=>{let $=d.priority&&d.priority!=="none"?` [${d.priority}]`:"";return`${d.identifier} ${H(String(d.title),re.ISSUE_TITLE)}${$}`});return n.length>e.maxLines&&c.push(I.dim(`...${n.length-e.maxLines} more`)),c.join(`
|
|
12
11
|
`)}let i=["id","name","title","status","message","success","error"].filter(n=>n in t);return i.length>0?se(i.map(n=>`${n}: ${H(String(t[n]),e.maxCharsPerLine-n.length-2)}`).join(`
|
|
13
|
-
`),e.maxLines):se(JSON.stringify(r,null,2),e.maxLines)}o(
|
|
12
|
+
`),e.maxLines):se(JSON.stringify(r,null,2),e.maxLines)}o(xe,"formatForHuman");E();import ne from"node:fs/promises";import it from"node:os";import Ee from"node:path";z();function ve(r){return Ee.join(it.homedir(),".prjct-cli","projects",r,"config","credentials.json")}o(ve,"getCredentialsPath");async function C(r){let e=ve(r);if(!await v(e))return{};try{return JSON.parse(await ne.readFile(e,"utf-8"))}catch(t){return console.error("[project-credentials] Failed to read credentials:",y(t)),{}}}o(C,"getProjectCredentials");async function Ce(r,e){let t=ve(r),s=Ee.dirname(t);await v(s)||await ne.mkdir(s,{recursive:!0});let i=await C(r);i.linear=e,await ne.writeFile(t,JSON.stringify(i,null,2))}o(Ce,"setLinearCredentials");async function oe(r){let e=await C(r);return e.linear?.apiKey?e.linear.apiKey:N("linear-api-key")}o(oe,"getLinearApiKey");async function Te(r){if((await C(r)).linear?.apiKey)return"project";let{getCredentialWithSource:t}=await Promise.resolve().then(()=>(z(),ue)),s=await t("linear-api-key");return s.value?s.source==="keychain"?"keychain":"env":"none"}o(Te,"getCredentialSource");var x=process.argv.slice(2),q=x.indexOf("--project"),m=null;q!==-1&&x[q+1]&&(m=x[q+1],x.splice(q,2));var ke=x.indexOf("--json"),T=ke!==-1;T&&x.splice(ke,1);var be=x.indexOf("--verbose"),nt=be!==-1;nt&&(x.splice(be,1),Se("verbose"));var[Ae,...g]=x;function p(r){console.log(T?JSON.stringify(r,null,2):xe(r))}o(p,"output");function u(r,e=1){console.error(T?JSON.stringify({error:r}):`Error: ${r}`),process.exit(e)}o(u,"error");async function P(){m||u("No --project specified. Usage: linear.ts --project <projectId> <command>");let r=await oe(m);r||u("Linear not configured. Run: p. linear setup");let e=await C(m);await l.initializeFromApiKey(r,e.linear?.teamId)}o(P,"initFromProject");async function ot(){try{switch(Ae){case"setup":{m||u("--project required for setup");let r=g[0],e=g[1];r||u("API key required. Usage: setup <apiKey> [teamId]"),await l.initializeFromApiKey(r,e);let t=await l.getTeams();t.length===0&&u("No teams found. Check your API key permissions.");let s=e,i;if(!s&&t.length===1)s=t[0].id,i=t[0].key;else if(s){let n=t.find(c=>c.id===s||c.key===s);n&&(s=n.id,i=n.key)}await Ce(m,{apiKey:r,teamId:s,teamKey:i,setupAt:new Date().toISOString()}),p({success:!0,teams:t,defaultTeam:s?{id:s,key:i}:null});break}case"list":{await P();let r=g[0]?parseInt(g[0],10):20,e=await C(m),t;e.linear?.teamId?t=await l.fetchTeamIssues(e.linear.teamId,{limit:r}):t=await l.fetchAssignedIssues({limit:r});let s=t.map(i=>({id:i.id,identifier:i.externalId,title:i.title,status:i.status,priority:i.priority,url:i.url}));if(T)p({count:t.length,issues:s});else{console.log(`Your issues (${t.length}):`);for(let i of s.slice(0,10)){let n=i.priority&&i.priority!=="none"?` [${i.priority}]`:"";console.log(` ${i.identifier} ${i.title.slice(0,50)}${n}`)}t.length>10&&console.log(` ...${t.length-10} more`)}break}case"list-team":{await P();let r=g[0],e=g[1]?parseInt(g[1],10):20;r||u("Team ID required. Usage: list-team <teamId> [limit]");let t=await l.fetchTeamIssues(r,{limit:e});p({count:t.length,issues:t.map(s=>({id:s.id,identifier:s.externalId,title:s.title,status:s.status,priority:s.priority,url:s.url}))});break}case"get":{await P();let r=g[0];r||u("Issue ID required. Usage: get <id>");let e=await l.fetchIssue(r);if(e||u(`Issue not found: ${r}`),T)p(e);else{if(console.log(`${e.externalId}: ${e.title}`),console.log(`Status: ${e.status} | Priority: ${e.priority||"none"}`),e.description){let t=e.description.slice(0,200);console.log(`
|
|
14
13
|
${t}${e.description.length>200?"...":""}`)}console.log(`
|
|
15
14
|
${e.url}`)}break}case"get-local":{m||u("--project required for get-local");let r=g[0];r||u("Issue ID required. Usage: get-local <id>");let e=await F.getIssueLocal(m,r);e||u(`Issue not in local cache: ${r}. Run 'sync' first.`),p(e);break}case"sync":{m||u("--project required for sync"),await P();let r=await F.pullAll(m);p({success:r.errors.length===0,...r});break}case"sync-status":{m||u("--project required for sync-status");let r=await F.getSyncStatus(m);p(r);break}case"create":{await P();let r=g[0];r||u(`JSON input required. Usage: create '{"title":"...", "teamId":"..."}'`);let e;try{e=JSON.parse(r)}catch{u(`Invalid JSON: ${r}`)}if(e.title||u("title is required"),!e.teamId){let s=await C(m);s.linear?.teamId?e.teamId=s.linear.teamId:u("teamId is required (no default team configured)")}let t=await l.createIssue(e);p(t);break}case"update":{await P();let r=g[0],e=g[1];r||u(`Issue ID required. Usage: update <id> '{"description":"..."}'`),e||u(`JSON input required. Usage: update <id> '{"description":"..."}'`);let t;try{t=JSON.parse(e)}catch{u(`Invalid JSON: ${e}`)}let s=await l.updateIssue(r,t);p(s);break}case"start":{await P();let r=g[0];r||u("Issue ID required. Usage: start <id>"),await l.markInProgress(r),p({success:!0,id:r,status:"in_progress"});break}case"done":{await P();let r=g[0];r||u("Issue ID required. Usage: done <id>"),await l.markDone(r),p({success:!0,id:r,status:"done"});break}case"comment":{await P();let r=g[0],e=g.slice(1).join(" ");r||u("Issue ID required. Usage: comment <id> <text>"),e||u("Comment text required. Usage: comment <id> <text>"),await l.addComment(r,e),p({success:!0,id:r});break}case"teams":{await P();let r=await l.getTeams();p({count:r.length,teams:r});break}case"projects":{await P();let r=await l.getProjects();p({count:r.length,projects:r});break}case"status":{m||u("--project required for status");let r=await Te(m),e=await oe(m),t=await C(m);if(!e){T?p({configured:!1,source:"none",message:"Linear not configured"}):(console.log("Linear: Not configured"),console.log("Run: p. linear setup"));break}try{await l.initializeFromApiKey(e,t.linear?.teamId);let s=await l.getTeams();T?p({configured:!0,source:r,teamId:t.linear?.teamId,teamKey:t.linear?.teamKey,teamsAvailable:s.length}):(console.log("Linear: Connected"),t.linear?.teamKey&&console.log(`Team: ${t.linear.teamKey}`),console.log(`Teams: ${s.length} available`))}catch(s){T?p({configured:!0,source:r,connectionError:y(s)}):(console.log("Linear: Connection error"),console.log(`Error: ${y(s)}`))}break}case"help":case"--help":case"-h":case void 0:{p({usage:"linear.ts --project <projectId> <command> [args...]",commands:{setup:"setup <apiKey> [teamId] - Store API key",list:"list [limit] - List my assigned issues","list-team":"list-team <teamId> [limit] - List team issues",get:"get <id> - Get issue by ID or identifier","get-local":"get-local <id> - Get from local cache (no API)",sync:"sync - Pull all assigned issues to local storage","sync-status":"sync-status - Check local cache status",create:"create <json> - Create issue",update:"update <id> <json> - Update issue",start:"start <id> - Mark as in progress",done:"done <id> - Mark as done",comment:"comment <id> <text> - Add comment",teams:"teams - List available teams",projects:"projects - List available projects",status:"status - Check connection"}});break}default:u(`Unknown command: ${Ae}. Use --help to see available commands.`)}}catch(r){u(y(r))}}o(ot,"main");ot();
|
|
16
|
-
//# sourceMappingURL=linear.mjs.map
|