epiq 1.12.2 → 1.12.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.
package/dist/index.js CHANGED
@@ -25,7 +25,7 @@ ${s.message}`);let i=await Dm(e),c=o!==null&&i!==null&&o!==i;return u(c?"Pulled
25
25
  `+t.message);let o=t.value.stdout.trim().split(`
26
26
  `).filter(Boolean).filter(i=>i!==gt);if(o.length===0)return u("State branch is storage-only",!1);let r=await U({args:["rm","-r","--ignore-unmatch","--",...o],cwd:e});if(a(r))return l(`Failed to clean storage branch
27
27
  ${r.message}`);let s=await gr({cwd:e,message:"[epiq:repair-storage-branch]",pathspec:o});return a(s)?l(s.message):u("Cleaned storage branch",!0)},Zt=gc(async(e=process.cwd())=>{let t=await U({args:["rev-parse","--show-toplevel"],cwd:e});return a(t)?l("Not inside a Git repository"):u("Resolved repo root",t.value.stdout.trim())},e=>Et.resolve(e)),vL=gc(async e=>{let t=await U({args:["rev-parse","--git-dir"],cwd:e});if(a(t))return l(t.message);let n=t.value.stdout.trim(),o=Et.isAbsolute(n)?n:Et.join(e,n);return u("Resolved git dir",o)},e=>Et.resolve(e));var CL=process.env.IS_LOCAL==="true",gt=".epiq",Fn="events",wc="media",HI="project.json",Po=e=>gn.join(e,gt),pr=e=>gn.join(Po(e),HI),St=e=>gn.join(Po(e),Fn),gs=e=>gn.join(Po(e),wc),sp=e=>gn.join(e,gt),WI=e=>{let t=gn.join(e,gt);return fs.existsSync(t)&&fs.statSync(t).isDirectory()},hs=e=>{let t=pr(e);return fs.existsSync(t)&&fs.statSync(t).isFile()},Hi=e=>{let t=gn.resolve(e);for(;;){if(WI(t))return u("Resolved closest .epiq root",t);let n=gn.dirname(t);if(n===t)return l("No .epiq directory found in any parent");t=n}},Tc="No .epiq/project.json found in any parent",oe=e=>{let t=gn.resolve(e);for(;;){if(hs(t))return u("Resolved closest epiq project root",t);let n=gn.dirname(t);if(n===t)return l(Tc);t=n}},ip=e=>{let t=St(e);try{return fs.mkdirSync(t,{recursive:!0}),u("Resolved events dir",t)}catch(n){return l(n instanceof Error?`Failed to ensure events dir: ${n.message}`:"Failed to ensure events dir")}},Ie=async()=>{let e=await Zt(process.cwd());if(a(e))return e;let t=me({repoRoot:e.value});return a(t)?t:u("Resolved persist root",t.value)};import{accessSync as GI,copyFileSync as VI,existsSync as zi,mkdirSync as ap,readdirSync as lp,readFileSync as zI,renameSync as KI,rmSync as qI,statSync as cp,unlinkSync as YI,writeFileSync as XI}from"node:fs";import hr from"node:path";var Mc=e=>typeof e=="object"&&e!==null&&"code"in e&&typeof e.code=="string",rt={writeToFile:(e,t)=>{try{let n=hr.dirname(e);zi(n)||ap(n,{recursive:!0});let o=typeof t=="string"?t:JSON.stringify(t,null,2);XI(e,o,"utf-8")}catch(n){logger.error(`Failed to write file at ${e}:`,n)}},readFile:e=>{try{return zI(e,"utf-8")}catch(t){return logger.error(`Failed to read file at ${e}:`,t),null}},readFileJSON(e){try{let t=rt.readFile(e);return t===null?null:JSON.parse(t)}catch(t){return logger.error(`Failed to read JSON at ${e}:`,t),null}},dirExists:e=>{try{return zi(e)&&cp(e).isDirectory()}catch{return!1}},async fileExists(e){try{return await GI(e),!0}catch{return!1}},mkDir:e=>ap(e,{recursive:!0}),locateFolder:e=>{let t=process.cwd(),{root:n}=hr.parse(t);for(;;){let o=hr.join(t,e);try{if(zi(o)&&cp(o).isDirectory())return o}catch{logger.error(`Unable to locate folder ${e}`)}if(t===n)break;t=hr.dirname(t)}return null},readFirstJSON(e){try{if(!rt.dirExists(e))return null;let t=lp(e).filter(o=>o.endsWith(".json")).sort()[0];if(!t)return null;let n=hr.join(e,t);return rt.readFileJSON(n)}catch(t){return logger.error(`Could not read first JSON in folder ${e}`,t),null}},listDir:e=>{try{return rt.dirExists(e)?lp(e):[]}catch(t){return logger.error(`Failed to list dir ${e}`,t),[]}},rmFile(e){try{YI(e)}catch(t){(!Mc(t)||t.code!=="ENOENT")&&logger.error(`Unable to remove file ${e}`)}},rmDir(e){try{qI(e,{recursive:!0,force:!0})}catch(t){(!Mc(t)||t.code!=="ENOENT")&&logger.error(`Unable to remove dir ${e}`)}},moveFile(e,t,n){if(this.mkDir(hr.dirname(t)),!n?.overwrite&&zi(t))throw new Error(`moveFile: destination exists: ${t}`);n?.overwrite&&this.rmFile(t);try{KI(e,t)}catch(o){if(Mc(o)&&o.code==="EXDEV"){VI(e,t),this.rmFile(e);return}throw o}}};var QI={logLevel:"info",userId:"",userName:"",preferredEditor:"",autoSync:!1},up=en.object({logLevel:en.enum(["info","error","debug"]),preferredEditor:en.string().optional(),userName:en.string().optional(),userId:en.string().optional(),autoSync:en.boolean().nullable().optional(),autoSyncDebounceMs:en.number().optional(),attachmentMaxKb:en.number().optional(),viewMode:en.enum(["dense","wide"]).optional(),declinedEmailBoards:en.array(en.string()).optional()}).partial(),ZI="config.json",mp=Bn,Pc=()=>JI.join(mp(),ZI),Lc=()=>{try{return rt.mkDir(mp()),u(`Ensured ~/${Jt} exists`,null)}catch{return l(`Unable to create ~/${Jt}`)}},eE=e=>{let t;try{t=JSON.parse(e)}catch{return l(`Invalid ~/${Jt}/config.json JSON`)}let n=up.safeParse(t??{});return n.success?u("Parsed config",n.data):l(`Invalid ~/${Jt}/config.json shape: ${n.error.issues.map(o=>o.path.join(".")||o.message).join(", ")}`)},hn=()=>{let e=Lc();if(a(e))return l(e.message);let t=Pc(),n=rt.readFile(t);return n==null||n.trim()===""?u("No config found, using empty config",{logLevel:"info",autoSync:null,preferredEditor:"",userId:"",userName:"",autoSyncIntervalMs:1e4}):eE(n)},pp=e=>{let t=Lc();if(a(t))return l(t.message);let n=up.safeParse(e);if(!n.success)return l(`Invalid config: ${n.error.issues.map(r=>r.path.join(".")||r.message).join(", ")}`);let o=Pc();try{return rt.writeToFile(o,JSON.stringify(n.data,null,2)+`
28
- `),u("Config written",null)}catch{return l(`Unable to write ~/${Jt}/config.json`)}},Ut=e=>{let t=hn();if(a(t))return l("Failed to read existing config");let n={...t.value,...e};return pp(n)},ht=()=>{let e=Pc(),t=Lc();if(a(t))return l(`Unable to create ~/${Jt}`);if(!(rt.readFile(e)!==null)){let b=pp(QI);if(a(b))throw new Error(`Unable to create ~/${Jt}/config.json`)}let o=hn();if(a(o))throw new Error(o.message||"Unable to load settings");let{preferredEditor:r,userName:s,userId:i,declinedEmailBoards:c,autoSync:d,autoSyncDebounceMs:p,attachmentMaxKb:m,logLevel:f,viewMode:g}=o.value,h=dr({userId:i,userName:s});if(a(h))return l(h.message);let x=h.value??{userId:i,userName:s};return!x.userName||!x.userId?l(`User name or ID not configured in ~/${Jt}/config.json`):(process.env.EPIQ_LOG_LEVEL=f,u("successfully loaded settings",{gitEmail:null,gitName:null,declinedEmailBoards:c??[],logLevel:f??"debug",preferredEditor:r??"",userName:x.userName,userId:x.userId,autoSync:d??!1,autoSyncIntervalMs:p??1e4,attachmentMaxKb:m??null,viewMode:g??"dense"}))};import{useSyncExternalStore as tE}from"react";var ys={logLevel:"info",autoSyncIntervalMs:null,attachmentMaxKb:null,autoSync:null,preferredEditor:null,userName:null,userId:null,gitEmail:null,gitName:null,declinedEmailBoards:[],viewMode:null},kc=new Set,nE=()=>{for(let e of kc)e()},V=()=>ys,fp=()=>tE(e=>(kc.add(e),()=>{kc.delete(e)}),()=>ys),je=e=>(ys={...ys,...e},nE(),ys);var kt="1.12.2";import aE from"node:os";import lE from"node:path";import vs from"chalk";var Ki=["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557","\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551","\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2580\u2580\u255D "];var it={bg:"#1a1b26",fg:"#c8d3ff",grayDark:"#3a3e54",gray:"#46507a",grayLight:"#969bb5",cyan:"#88d5ee",cyanSoft:"#8fe6fb",blue:"#5b8cff",magenta:"#a78bfa",magentaSoft:"#c4b5fd",green:"#8fdc8c",yellow:"#f1c27d",red:"#ff7a90",white:"#ffffff"},y={accent:it.cyan,accent2:it.magenta,primary:it.white,secondary:it.grayDark,secondary2:it.grayLight,gray:it.gray,green:it.green,yellow:it.yellow,red:it.red};import yr from"chalk";var L={red:it.red,yellow:it.yellow,green:it.green,blue:it.blue,magenta:it.magenta,cyan:it.cyan},qi={urgent:L.red,critical:L.red,important:L.red,blocker:L.red,asap:L.red,immediate:L.red,fail:L.red,failure:L.red,broken:L.red,bug:L.red,error:L.red,incident:L.red,outage:L.red,production:L.red,crash:L.red,security:L.red,warning:L.yellow,warn:L.yellow,risky:L.yellow,risk:L.yellow,attention:L.yellow,pending:L.yellow,review:L.yellow,"needs-review":L.yellow,qa:L.yellow,testing:L.yellow,test:L.yellow,validate:L.yellow,verification:L.yellow,staging:L.yellow,check:L.yellow,"follow-up":L.yellow,followup:L.yellow,waiting:L.yellow,blocked:L.yellow,hold:L.yellow,done:L.green,complete:L.green,completed:L.green,success:L.green,ok:L.green,stable:L.green,resolved:L.green,fixed:L.green,closed:L.green,merged:L.green,released:L.green,deployed:L.green,approved:L.green,verified:L.green,working:L.green,healthy:L.green,pass:L.green,passing:L.green,info:L.blue,information:L.blue,note:L.blue,docs:L.blue,documentation:L.blue,doc:L.blue,guide:L.blue,help:L.blue,explanation:L.blue,detail:L.blue,details:L.blue,context:L.blue,design:L.blue,discussion:L.blue,proposal:L.blue,idea:L.blue,feature:L.magenta,enhancement:L.magenta,improvement:L.magenta,refactor:L.magenta,refactoring:L.magenta,cleanup:L.magenta,optimize:L.magenta,optimization:L.magenta,perf:L.magenta,performance:L.magenta,upgrade:L.magenta,migration:L.magenta,modernize:L.magenta,debt:L.magenta,todo:L.cyan,next:L.cyan,planned:L.cyan,plan:L.cyan,future:L.cyan,backlog:L.cyan,investigate:L.cyan,explore:L.cyan,prototype:L.cyan};var Bc={stringColor:{saturation:50,lightness:60},gradient:{stops:[[174,150,240],[92,138,232],[102,204,226]]}},Oc=(e,t,n)=>Math.max(t,Math.min(n,e)),Dc=(e,t,n)=>e+(t-e)*n,hp=e=>{let t=0;for(let n=0;n<e.length;n++)t=t*31+e.charCodeAt(n)>>>0;return t},oE=e=>e.toLowerCase().trim(),rE=(e,t,n)=>{let o=t/100,r=n/100,s=(1-Math.abs(2*r-1))*o,i=e/60,c=s*(1-Math.abs(i%2-1)),d=0,p=0,m=0;i>=0&&i<1?(d=s,p=c):i>=1&&i<2?(d=c,p=s):i>=2&&i<3?(p=s,m=c):i>=3&&i<4?(p=c,m=s):i>=4&&i<5?(d=c,m=s):(d=s,m=c);let f=r-s/2;return[Math.round((d+f)*255),Math.round((p+f)*255),Math.round((m+f)*255)]},Fc=([e,t,n])=>`#${e.toString(16).padStart(2,"0")}${t.toString(16).padStart(2,"0")}${n.toString(16).padStart(2,"0")}`,gp=e=>{let t=e.replace("#","");return[parseInt(t.slice(0,2),16),parseInt(t.slice(2,4),16),parseInt(t.slice(4,6),16)]},yp=(e,t,n)=>{let o=Oc(n,0,1);return[Math.round(Dc(e[0],t[0],o)),Math.round(Dc(e[1],t[1],o)),Math.round(Dc(e[2],t[2],o))]};var sE=(e,t,n)=>yp(e,t,n),_c=e=>{let t=hp(e)%360,n=rE(t,Bc.stringColor.saturation,Bc.stringColor.lightness);return Fc(n)},ze=(e,t=qi)=>{let n=oE(e??"");return n&&t[n]?t[n]:_c(n)};var Yi=e=>{let t=Bc.gradient.stops,n=Oc(e,0,1);if(t.length===0)return[0,0,0];if(t.length===1)return t[0];let o=t.length-1,r=n*o,s=Math.min(Math.floor(r),o-1),i=r-s;return sE(t[s],t[s+1],i)},vp=(e,t)=>{if(e.length===0)return"#000000";if(e.length===1)return e[0];let n=e.length-1,o=Oc(t,0,1)*n,r=Math.min(Math.floor(o),n-1);return Fc(yp(gp(e[r]),gp(e[r+1]),o-r))},Xi=e=>Fc(Yi(e)),Ji=e=>hp(e.toLowerCase().trim())/4294967295,bp=e=>{let t=Ji(e);return Yi(t)},iE=e=>{let[t,n,o]=bp(e);return{normal:r=>yr.bgRgb(t,n,o).black(r),cursor:r=>yr.bgRgb(t,n,o).white.bold(r)}},jc=e=>{let[t,n,o]=bp(e);return{fg:r=>yr.rgb(t,n,o)(r),fgCursor:r=>yr.rgb(t,n,o).inverse(r),bg:r=>yr.bgRgb(t,n,o).black(r),bgCursor:r=>yr.bgRgb(t,n,o).white.bold(r)}},Qi=e=>iE(e).normal(` ${e} `);var Zi=" ",Ep=vs.hex(y.secondary2),xp=vs.hex(y.gray),cE=()=>{let t=Ki[0].length+Ki.length*2;return Ki.map((n,o)=>Array.from(n).map((r,s)=>{let[i,c,d]=Yi((s+o*2)/t);return vs.rgb(i,c,d)(r)}).join(""))},dE=e=>{let t=aE.homedir();return e===t||e.startsWith(t+lE.sep)?"~"+e.slice(t.length):e},Ip=(e,t)=>`${Zi}${vs.hex(y.accent)("\u279C")} ${Ep(e.padEnd(9))}${t}`,$c=({url:e,repoRoot:t,version:n,reused:o})=>["",...cE().map(r=>Zi+r),"",`${Zi}${Ep("gui")} ${xp(`\xB7 v${n}`)}`,"",Ip("Local",vs.hex(y.accent).bold(e)),Ip("Project",dE(t)),"",Zi+xp(o?"already running for this project \xB7 opened in your browser":"press ctrl+c to stop"),""].join(`
28
+ `),u("Config written",null)}catch{return l(`Unable to write ~/${Jt}/config.json`)}},Ut=e=>{let t=hn();if(a(t))return l("Failed to read existing config");let n={...t.value,...e};return pp(n)},ht=()=>{let e=Pc(),t=Lc();if(a(t))return l(`Unable to create ~/${Jt}`);if(!(rt.readFile(e)!==null)){let b=pp(QI);if(a(b))throw new Error(`Unable to create ~/${Jt}/config.json`)}let o=hn();if(a(o))throw new Error(o.message||"Unable to load settings");let{preferredEditor:r,userName:s,userId:i,declinedEmailBoards:c,autoSync:d,autoSyncDebounceMs:p,attachmentMaxKb:m,logLevel:f,viewMode:g}=o.value,h=dr({userId:i,userName:s});if(a(h))return l(h.message);let x=h.value??{userId:i,userName:s};return!x.userName||!x.userId?l(`User name or ID not configured in ~/${Jt}/config.json`):(process.env.EPIQ_LOG_LEVEL=f,u("successfully loaded settings",{gitEmail:null,gitName:null,declinedEmailBoards:c??[],logLevel:f??"debug",preferredEditor:r??"",userName:x.userName,userId:x.userId,autoSync:d??!1,autoSyncIntervalMs:p??1e4,attachmentMaxKb:m??null,viewMode:g??"dense"}))};import{useSyncExternalStore as tE}from"react";var ys={logLevel:"info",autoSyncIntervalMs:null,attachmentMaxKb:null,autoSync:null,preferredEditor:null,userName:null,userId:null,gitEmail:null,gitName:null,declinedEmailBoards:[],viewMode:null},kc=new Set,nE=()=>{for(let e of kc)e()},V=()=>ys,fp=()=>tE(e=>(kc.add(e),()=>{kc.delete(e)}),()=>ys),je=e=>(ys={...ys,...e},nE(),ys);var kt="1.12.4";import aE from"node:os";import lE from"node:path";import vs from"chalk";var Ki=["\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 ","\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557","\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551","\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551\u2584\u2584 \u2588\u2588\u2551","\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D","\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2580\u2580\u255D "];var it={bg:"#1a1b26",fg:"#c8d3ff",grayDark:"#3a3e54",gray:"#46507a",grayLight:"#969bb5",cyan:"#88d5ee",cyanSoft:"#8fe6fb",blue:"#5b8cff",magenta:"#a78bfa",magentaSoft:"#c4b5fd",green:"#8fdc8c",yellow:"#f1c27d",red:"#ff7a90",white:"#ffffff"},y={accent:it.cyan,accent2:it.magenta,primary:it.white,secondary:it.grayDark,secondary2:it.grayLight,gray:it.gray,green:it.green,yellow:it.yellow,red:it.red};import yr from"chalk";var L={red:it.red,yellow:it.yellow,green:it.green,blue:it.blue,magenta:it.magenta,cyan:it.cyan},qi={urgent:L.red,critical:L.red,important:L.red,blocker:L.red,asap:L.red,immediate:L.red,fail:L.red,failure:L.red,broken:L.red,bug:L.red,error:L.red,incident:L.red,outage:L.red,production:L.red,crash:L.red,security:L.red,warning:L.yellow,warn:L.yellow,risky:L.yellow,risk:L.yellow,attention:L.yellow,pending:L.yellow,review:L.yellow,"needs-review":L.yellow,qa:L.yellow,testing:L.yellow,test:L.yellow,validate:L.yellow,verification:L.yellow,staging:L.yellow,check:L.yellow,"follow-up":L.yellow,followup:L.yellow,waiting:L.yellow,blocked:L.yellow,hold:L.yellow,done:L.green,complete:L.green,completed:L.green,success:L.green,ok:L.green,stable:L.green,resolved:L.green,fixed:L.green,closed:L.green,merged:L.green,released:L.green,deployed:L.green,approved:L.green,verified:L.green,working:L.green,healthy:L.green,pass:L.green,passing:L.green,info:L.blue,information:L.blue,note:L.blue,docs:L.blue,documentation:L.blue,doc:L.blue,guide:L.blue,help:L.blue,explanation:L.blue,detail:L.blue,details:L.blue,context:L.blue,design:L.blue,discussion:L.blue,proposal:L.blue,idea:L.blue,feature:L.magenta,enhancement:L.magenta,improvement:L.magenta,refactor:L.magenta,refactoring:L.magenta,cleanup:L.magenta,optimize:L.magenta,optimization:L.magenta,perf:L.magenta,performance:L.magenta,upgrade:L.magenta,migration:L.magenta,modernize:L.magenta,debt:L.magenta,todo:L.cyan,next:L.cyan,planned:L.cyan,plan:L.cyan,future:L.cyan,backlog:L.cyan,investigate:L.cyan,explore:L.cyan,prototype:L.cyan};var Bc={stringColor:{saturation:50,lightness:60},gradient:{stops:[[174,150,240],[92,138,232],[102,204,226]]}},Oc=(e,t,n)=>Math.max(t,Math.min(n,e)),Dc=(e,t,n)=>e+(t-e)*n,hp=e=>{let t=0;for(let n=0;n<e.length;n++)t=t*31+e.charCodeAt(n)>>>0;return t},oE=e=>e.toLowerCase().trim(),rE=(e,t,n)=>{let o=t/100,r=n/100,s=(1-Math.abs(2*r-1))*o,i=e/60,c=s*(1-Math.abs(i%2-1)),d=0,p=0,m=0;i>=0&&i<1?(d=s,p=c):i>=1&&i<2?(d=c,p=s):i>=2&&i<3?(p=s,m=c):i>=3&&i<4?(p=c,m=s):i>=4&&i<5?(d=c,m=s):(d=s,m=c);let f=r-s/2;return[Math.round((d+f)*255),Math.round((p+f)*255),Math.round((m+f)*255)]},Fc=([e,t,n])=>`#${e.toString(16).padStart(2,"0")}${t.toString(16).padStart(2,"0")}${n.toString(16).padStart(2,"0")}`,gp=e=>{let t=e.replace("#","");return[parseInt(t.slice(0,2),16),parseInt(t.slice(2,4),16),parseInt(t.slice(4,6),16)]},yp=(e,t,n)=>{let o=Oc(n,0,1);return[Math.round(Dc(e[0],t[0],o)),Math.round(Dc(e[1],t[1],o)),Math.round(Dc(e[2],t[2],o))]};var sE=(e,t,n)=>yp(e,t,n),_c=e=>{let t=hp(e)%360,n=rE(t,Bc.stringColor.saturation,Bc.stringColor.lightness);return Fc(n)},ze=(e,t=qi)=>{let n=oE(e??"");return n&&t[n]?t[n]:_c(n)};var Yi=e=>{let t=Bc.gradient.stops,n=Oc(e,0,1);if(t.length===0)return[0,0,0];if(t.length===1)return t[0];let o=t.length-1,r=n*o,s=Math.min(Math.floor(r),o-1),i=r-s;return sE(t[s],t[s+1],i)},vp=(e,t)=>{if(e.length===0)return"#000000";if(e.length===1)return e[0];let n=e.length-1,o=Oc(t,0,1)*n,r=Math.min(Math.floor(o),n-1);return Fc(yp(gp(e[r]),gp(e[r+1]),o-r))},Xi=e=>Fc(Yi(e)),Ji=e=>hp(e.toLowerCase().trim())/4294967295,bp=e=>{let t=Ji(e);return Yi(t)},iE=e=>{let[t,n,o]=bp(e);return{normal:r=>yr.bgRgb(t,n,o).black(r),cursor:r=>yr.bgRgb(t,n,o).white.bold(r)}},jc=e=>{let[t,n,o]=bp(e);return{fg:r=>yr.rgb(t,n,o)(r),fgCursor:r=>yr.rgb(t,n,o).inverse(r),bg:r=>yr.bgRgb(t,n,o).black(r),bgCursor:r=>yr.bgRgb(t,n,o).white.bold(r)}},Qi=e=>iE(e).normal(` ${e} `);var Zi=" ",Ep=vs.hex(y.secondary2),xp=vs.hex(y.gray),cE=()=>{let t=Ki[0].length+Ki.length*2;return Ki.map((n,o)=>Array.from(n).map((r,s)=>{let[i,c,d]=Yi((s+o*2)/t);return vs.rgb(i,c,d)(r)}).join(""))},dE=e=>{let t=aE.homedir();return e===t||e.startsWith(t+lE.sep)?"~"+e.slice(t.length):e},Ip=(e,t)=>`${Zi}${vs.hex(y.accent)("\u279C")} ${Ep(e.padEnd(9))}${t}`,$c=({url:e,repoRoot:t,version:n,reused:o})=>["",...cE().map(r=>Zi+r),"",`${Zi}${Ep("gui")} ${xp(`\xB7 v${n}`)}`,"",Ip("Local",vs.hex(y.accent).bold(e)),Ip("Project",dE(t)),"",Zi+xp(o?"already running for this project \xB7 opened in your browser":"press ctrl+c to stop"),""].join(`
29
29
  `);import{spawn as uE}from"node:child_process";import bs from"node:process";var Sp=(e=bs.platform,t=bs.env)=>e==="darwin"||e==="win32"||!!(t.DISPLAY||t.WAYLAND_DISPLAY||t.BROWSER),Rp=e=>{let t=bs.platform==="darwin"?"open":bs.platform==="win32"?"cmd":"xdg-open",n=bs.platform==="win32"?["/c","start","",e]:[e];try{let o=uE(t,n,{detached:!0,stdio:"ignore"});o.on("error",r=>{logger.info(`[gui] could not open a browser: ${r.message}`)}),o.unref()}catch(o){logger.info(`[gui] could not open a browser: ${String(o)}`)}};import{readFile as px,stat as WT}from"node:fs/promises";import{createHash as GT}from"node:crypto";import Ro from"chalk";import Vv from"string-width";import{decodeTime as Cp}from"ulid";var ea=1440*60*1e3,xs=(e,t=Date.now())=>e>t+ea?t:e,De=e=>xs(Cp(e)),vr=e=>{let t=Date.now()+ea,n=e.find(r=>r!==null&&r<=t)??null;if(n===null)return[...e];let o=null;return e.map(r=>{if(r===null)return null;let s=r<=t?r:o??n;return o=s,s})},br=e=>{try{return u("Decoded date",new Date(De(e)))}catch(t){return l("Decoding failed + "+t.message)}},to=e=>{if(!e?.id)return null;try{return Cp(e.id)}catch{return null}};var mE="Unknown",ta=(e,t)=>t?.length?t:e?.length?e:mE,Ke=(e,t)=>{let n=ta(e,t);return{id:e?.length?e:n,name:n,color:ze(n)}};var xr="removed",yt=(e,t)=>{let n=e.find(o=>o.context===t);return n!==void 0?u("Found node",n):l("Unable to find node in breadcrumb")},Np=["png","jpg","gif","webp"];var Ze=e=>e.trim().toLowerCase(),no=e=>{let t=Ze(e);return t.length>0&&t.length<=254&&/^[^\s@]+@[^\s@]+$/.test(t)},Is=(e,t)=>`${Ze(e)} ${t}`,Uc=e=>!e.tombstoned,Es=(e,t)=>{let n=Ze(t),o=new Set;for(let r of Object.values(e))Uc(r)&&r.email===n&&o.add(r.contributor);return[...o]},yn=(e,t)=>{let n=new Set;for(let o of Object.values(e))Uc(o)&&o.contributor===t&&n.add(o.email);return[...n]},Ap=e=>{let t=new Map;for(let o of Object.values(e)){if(!Uc(o))continue;let r=t.get(o.email)??new Set;r.add(o.contributor),t.set(o.email,r)}let n=new Map;for(let[o,r]of t){let[s]=[...r];r.size===1&&s&&n.set(o,s)}return n};var na=(e,t)=>e===t.authorId||e===t.contributor;var re={WORKSPACE:"WORKSPACE",BOARD:"BOARD",SWIMLANE:"SWIMLANE",TICKET:"TICKET",FIELD:"FIELD",FIELD_LIST:"FIELD_LIST",TEXT:"TEXT",COMMENT:"COMMENT"};function Hc(e){return e.context===re.WORKSPACE}function _(e){return e.context===re.TICKET}function oo(e){return e.context===re.TEXT}function at(e){return e.context===re.FIELD}function Ss(e){return e.context===re.FIELD_LIST}var vn=e=>e.context===re.SWIMLANE,ro=e=>e.context===re.BOARD,Rs=e=>e.context===re.COMMENT;import{useSyncExternalStore as _A}from"react";var I={DEFAULT:"default",MOVE:"move",HELP:"help",COMMAND_LINE:"cmd-line",PALETTE:"palette",IDENTITY:"identity"};var wp=(e,t)=>e.ctrl&&e.name==="w"||e.meta&&e.name==="backspace"||t==="",Tp=(e,t)=>e.meta&&e.name==="b"||t==="\x1Bb",Mp=(e,t)=>e.meta&&e.name==="f"||t==="\x1Bf",Pp=(e,t)=>{if(Tp(e,e.sequence))return E.MoveCursorLeftOfWord;if(Mp(e,e.sequence))return E.MoveCursorRightOfWord;if(wp(e,e.sequence))return E.EraseInputWord;switch(e.name){case"tab":return E.AutoCompleteCommand;case"up":return E.GetLastCommandFromHistory;case"down":return E.GetNextCommandFromHistory;case"left":return E.MoveCursorLeft;case"right":return E.MoveCursorRight;case"return":return E.Confirm;case"backspace":return t?E.EraseInput:E.ExitCommandLine;case"escape":return E.ExitCommandLine;default:return E.CaptureInput}},Lp=(e,t)=>{if(Tp(e,e.sequence))return E.MoveCursorLeftOfWord;if(Mp(e,e.sequence))return E.MoveCursorRightOfWord;if(wp(e,e.sequence))return E.EraseInputWord;switch(e.name){case"tab":return E.AutoCompleteCommand;case"up":return E.NavPreviousItem;case"down":return E.NavNextItem;case"left":return E.MoveCursorLeft;case"right":return E.MoveCursorRight;case"return":return E.Confirm;case"backspace":return t?E.EraseInput:E.ExitCommandLine;case"escape":return E.ExitCommandLine;default:return E.CaptureInput}};import kp from"string-width";function oa(e,t){let n=Math.min(e.length,t.length),o=0;for(;o<n&&e[o]===t[o];)o++;return o}var _n=(e,t)=>t<=0?"":e.length<=t?e:t<=3?"...".slice(0,t):e.slice(0,t-3)+"...",pE=/\u001B\[[0-9;]*m/,Wc="\x1B[0m",fE=e=>[...new Intl.Segmenter(void 0,{granularity:"grapheme"}).segment(e)].map(({segment:t})=>t),jn=(e,t)=>{if(t<=0)return"";if(kp(e)<=t)return e;if(t<=3)return"...".slice(0,t);let o=t-3,r="",s=0,i=!1;for(let c of e.split(/(\u001B\[[0-9;]*m)/))if(c!==""){if(pE.test(c)){r+=c,i=c!==Wc&&c!=="\x1B[m";continue}for(let d of fE(c)){let p=kp(d);if(s+p>o)return`${r}...${i?Wc:""}`;r+=d,s+=p}}return`${r}...${i?Wc:""}`},Ee=e=>typeof e!="string"?"":e.replace(/[\x00-\x08\x0B-\x1F\x7F]/g,"").replace(/[\r\n\t]/g," ").replace(/\s+/g," ").trim(),Dp=e=>e.charAt(0).toUpperCase()+e.slice(1);var Bp=e=>{let t=new Map;for(let n of e){let o=n.toLowerCase();for(let r=1;r<=n.length;r++){let s=o.slice(0,r),i=t.get(s);i?i.push(n):t.set(s,[n])}}return t},Op=(e,t)=>t?e.get(t)??[]:[];var Fp=new WeakMap,gE=e=>{let t=Fp.get(e);return t||(t=Bp(e),Fp.set(e,t)),t};var _p=({wordList:e,inputToMatch:t,overlapThreshold:n=1})=>{let o=t.toLowerCase();return Op(gE(e),o).filter(s=>oa(o,s.toLowerCase())>=n)};var hE={hint:"",hints:[],overlap:0,remainder:""},$p=({inputToMatch:e,lastWord:t,isLastWordCompleted:n,inputString:o},r,s=[])=>{if(n||e===""){let[c]=s;return s.length===1&&c&&!o.trim()?jp("",[c]):hE}let i=_p({wordList:r,inputToMatch:e,overlapThreshold:1});return jp(t,i)},jp=(e,t)=>{let n=t[0]??"",o=oa(e.toLowerCase(),n.toLowerCase()),[r,s]=n.split(":"),i=o<(r??"").length,c=!!s,m=(c&&i?r:n)+(c&&i?":":" "),f=m.slice(o);return{hint:m,hints:t,overlap:o,remainder:f}};import Cs from"node:fs";import Ns from"node:path";import{z as Ir}from"zod";var ra="recent-projects.json",yE=20,vE=Ir.object({projectId:Ir.string().min(1),root:Ir.string().min(1),lastOpenedAt:Ir.number().finite()}),bE=Ir.object({projects:Ir.array(vE)}),Hp=()=>Ns.join(Bn(),ra),Er=e=>Ns.basename(e)||e,Up=e=>{let t=Ns.resolve(e);try{return Cs.realpathSync(t)}catch{return t}},Wp=(e,t)=>t.lastOpenedAt-e.lastOpenedAt,Gp=e=>{if(!hs(e.root))return!1;let t=fn(e.root);return!a(t)&&t.value===e.projectId},Vp=()=>{let e=Hp();if(!Cs.existsSync(e))return u("No recent projects recorded",[]);let t;try{t=JSON.parse(Cs.readFileSync(e,"utf8"))}catch(o){return l(`Invalid ${ra}: ${o instanceof Error?o.message:String(o)}`)}let n=bE.safeParse(t);return n.success?u("Read recent projects",n.data.projects):l(`Invalid ${ra} shape: ${n.error.issues.map(o=>o.path.join(".")||o.message).join(", ")}`)},xE=e=>{let t=Hp();try{Cs.mkdirSync(Ns.dirname(t),{recursive:!0}),Cs.writeFileSync(t,JSON.stringify({projects:e},null,2)+`
30
30
  `,"utf8")}catch(n){return l(`Unable to write ${ra}: ${n instanceof Error?n.message:String(n)}`)}return u("Recorded recent project",e)},$n=({exclude:e}={})=>{let t=Vp();if(a(t))return t;let n=e===void 0?null:Up(e);return u("Listed recent projects",t.value.filter(o=>n===null||Up(o.root)!==n).filter(Gp).sort(Wp))},sa=({root:e,now:t=Date.now()})=>{let n=Ns.resolve(e),o=fn(n);if(a(o))return l(o.message);let r=o.value,s=Vp(),i=a(s)?[]:s.value,c=[{projectId:r,root:n,lastOpenedAt:t},...i.filter(d=>d.projectId!==r&&d.root!==n)].filter(Gp).sort(Wp).slice(0,yE);return xE(c)};var Gc=null,zp=e=>{Gc=e},Kp=e=>Gc?Gc(e):[];var qp=[],Sr=e=>{qp=e},Rr=()=>qp;var Un=()=>{let e=V(),t=!!e.userName?.trim(),n=!!e.preferredEditor?.trim(),o=e.autoSync===!0||e.autoSync===!1,r=Yp(),s=r.length>0?null:Vc(),i=s!==null&&(e.declinedEmailBoards??[]).includes(s),c=r.length>0||i||s===null;return{isSetupDone:n&&t&&o&&c,isSetPreferredEditor:n,isSetUserName:t,userName:e.userName,preferredEditor:e.preferredEditor,autoSync:e.autoSync===void 0?null:e.autoSync,isSetAutoSync:o,isSetEmails:c,claimedEmails:r,emailSetupDeclined:i}},Vc=()=>{let e=oe(process.cwd());if(a(e))return null;let t=fn(e.value);return a(t)?null:t.value||null},Yp=()=>{let{userId:e}=V();return e?Kp(e):[]},Xp=()=>Yp().length>0;var zc=()=>{let e=oe(process.cwd());if(a(e))return!1;let t=Mt(e.value);return ve(t)},Jp=e=>e===!0?"on":e===!1?"off":null,Qp=e=>e==="on"?!0:e==="off"?!1:null,Zp=()=>{let e=Un();if(!e.isSetUserName)return"config username ";if(!e.isSetPreferredEditor)return"config editor ";if(!e.isSetAutoSync)return"config autoSync ";if(!zc())return"init";if(!e.isSetEmails){let{gitEmail:t}=V(),n=Rr()[0]??t;return n&&no(n)?`config emails ${n}`:"config emails "}return null};var IE=["00KM6CZ900T7180RM46K0JAYNF","00JR3R8E00A1Z4X9FGP9DV0SM5"],[he,ia]=IE;var EE=e=>e.props.tags??[],SE=e=>e.props.assignees??[],bn=e=>EE(e).map(t=>N.getTag(t)).filter(t=>!!t),xn=e=>SE(e).map(t=>N.getContributor(t)).filter(t=>!!t),aa=()=>{let{breadCrumb:e,selectedNode:t}=v(),n=[...e,t].find(o=>o?.context==="TICKET");return!n||!_(n)?l("Invalid untag target"):u("Retrieved tags from ticket in breadcrumb",bn(n))},la=()=>{let{breadCrumb:e,selectedNode:t}=v(),n=[...e,t].find(o=>o?.context==="TICKET");return!n||!_(n)?l("Invalid unassign target"):u("Retrieved assignees from ticket in breadcrumb",xn(n))};var C={PALETTE:"?",EXIT:"exit",INIT:"init",OPEN:"open",HELP:"help",NEW:"new",TAG:"tag",UNTAG:"untag",MOVE:"move",PEEK:"peek",REPLAY:"replay",FILTER:"filter",ASSIGN:"assign",UNASSIGN:"unassign",DELETE:"delete",CLOSE_ISSUE:"close",RE_OPEN_ISSUE:"reopen",COMMENT:"comment",CONFIG:"config",EDIT:"edit",YANK:"yank",SYNC:"sync",EXPORT:"export",NONE:""};var RE=/^(\d+)(h|d|w|mo|y)$/,CE=/^(\d{4})-(\d{2})-(\d{2})(?:(?::|\s)(\d{2}):(\d{2}))?$/,NE=({year:e,month:t,day:n,hour:o=0,minute:r=0})=>{let s=new Date(e,t-1,n,o,r);return s.getFullYear()===e&&s.getMonth()===t-1&&s.getDate()===n&&s.getHours()===o&&s.getMinutes()===r},AE=(e,t=new Date)=>{let n=e.match(RE);if(!n)return null;let[,o,r]=n,s=Number(o);if(!Number.isInteger(s)||s<=0)return null;let i=new Date(t);switch(r){case"h":return i.setHours(i.getHours()-s),i;case"d":return i.setDate(i.getDate()-s),i;case"w":return i.setDate(i.getDate()-s*7),i;case"mo":return i.setMonth(i.getMonth()-s),i;case"y":return i.setFullYear(i.getFullYear()-s),i;default:return null}},wE=e=>{let t=e.match(CE);if(!t)return null;let[,n,o,r,s,i]=t,c=Number(n),d=Number(o),p=Number(r),m=s?Number(s):0,f=i?Number(i):0;return NE({year:c,month:d,day:p,hour:m,minute:f})?new Date(c,d-1,p,m,f):null},ko=e=>{let t=e.trim().toLowerCase();return AE(t)??wE(t)};var ef=/^(\d+)(s|m)?$/,ca=e=>{let t=e.trim().toLowerCase().match(ef);if(!t)return null;let n=Number(t[1]);return!Number.isInteger(n)||n<=0?null:t[2]==="m"?n*6e4:n*1e3},da=(e,t)=>{let n=(t??"").trim().split(/\s+/).filter(Boolean),o=n.length>0&&ef.test(n.at(-1))?n.pop():"";return{dateInput:e||n.join(" "),durationInput:o}},tf=({date:e,horizonDate:t})=>t?e.getTime()>=t.getTime():!0,TE=[{unit:"h",from:1,to:24},{unit:"d",from:1,to:7},{unit:"w",from:1,to:52},{unit:"mo",from:1,to:12},{unit:"y",from:1,to:5}],Kc=(e=TE)=>{let t=[];for(let{unit:n,from:o,to:r}of e)for(let s=o;s<=r;s++)t.push(`${s}${n}`);return t};var ME=["BOARD","TICKET","SWIMLANE","COMMENT"],ye={EDITOR:"editor",VIEW:"view",USERNAME:"username",EMAILS:"emails",EMAILS_UNCLAIM:"emails-unclaim",AUTOSYNC:"autoSync",SYNC_DEBOUNCE_MS:"syncDebounceMs",ATTACHMENT_MAX_KB:"attachmentMaxKb",LOG_LEVEL:"logLevel"},Dt={TITLE:"title",DESCRIPTION:"description",COMMENT:"comment"},qe={REF:"ref",TITLE:"title",DESCRIPTION:"description",TAGS:"tags",ASSIGNEES:"assignees"},PE=[ye.EDITOR,ye.VIEW,ye.USERNAME,ye.EMAILS,ye.EMAILS_UNCLAIM,ye.AUTOSYNC,ye.SYNC_DEBOUNCE_MS,ye.ATTACHMENT_MAX_KB,ye.LOG_LEVEL],LE=(e=v().selectedNode?.context)=>{switch(e){case"TICKET":return[Dt.TITLE,Dt.DESCRIPTION];case"BOARD":case"SWIMLANE":return[Dt.TITLE];case"COMMENT":return[Dt.COMMENT];default:return[]}},Yc=[String(3e3),"5000","15000","30000","60000"],Xc=["250","500","1000"],rf=["10s","20s","30s","45s"],Do=[C.EXIT,C.SYNC,C.HELP,C.EXPORT,C.CONFIG,C.YANK],ua=[C.NEW,C.EDIT,C.DELETE,C.MOVE],qc=[C.TAG,C.UNTAG,C.ASSIGN,C.UNASSIGN,C.CLOSE_ISSUE,C.RE_OPEN_ISSUE,C.EDIT,C.COMMENT],nf=[C.FILTER,C.PEEK,C.REPLAY],kE={WORKSPACE:[...Do,...ua],BOARD:[...nf,...Do,...ua],SWIMLANE:[...nf,...Do,...ua],TICKET:[...Do,...ua,...qc],FIELD:[...Do,...qc],FIELD_LIST:[...Do,...qc],TEXT:[...Do],COMMENT:[C.EDIT,C.DELETE,C.YANK]},DE=e=>e==="WORKSPACE"?["board"]:["issue","swimlane","board"],As=({breadCrumb:e,selectedNode:t})=>[...e,t].find(n=>n!=null&&_(n)),of=e=>e.parentNodeId===he,BE=({selectedNode:e,breadCrumb:t})=>{let n=LE(e?.context);return As({breadCrumb:t,selectedNode:e})?n.includes(Dt.DESCRIPTION)?n:[...n,Dt.DESCRIPTION]:n},OE=({selectedNode:e,breadCrumb:t})=>{let n=As({breadCrumb:t,selectedNode:e});return n?[qe.REF,qe.TITLE,...n.props?.description?.trim()?[qe.DESCRIPTION]:[],...bn(n).length>0?[qe.TAGS]:[],...xn(n).length>0?[qe.ASSIGNEES]:[]]:e?[qe.REF,qe.TITLE]:[]},Jc=()=>{let e=$n({exclude:process.cwd()});return a(e)?[]:[...e.value.map((t,n)=>String(n+1)),...e.value.map(t=>t.root)]},FE=({selectedNode:e,readOnly:t,breadCrumb:n})=>{let{isSetupDone:o}=Un();if(!o)return[C.HELP,C.CONFIG];if(!zc())return[C.HELP,C.INIT,C.OPEN];if(t)return[C.HELP,C.PEEK,C.REPLAY,C.EXPORT,C.CONFIG,C.YANK];let r=e?.context,s=r&&ME.includes(r),i=[...new Set([...n,e].map(d=>d?.context).flatMap(d=>d?kE[d]:[]))],c=As({breadCrumb:n,selectedNode:e});return i.filter(d=>d===C.MOVE?!1:d===C.YANK?!!(c??e):d===C.EDIT?s||!!c:d===C.DELETE?s:d===C.UNTAG?!!(c&&bn(c).length>0):d===C.UNASSIGN?!!(c&&xn(c).length>0):d===C.RE_OPEN_ISSUE?!!(c&&of(c)):d===C.CLOSE_ISSUE?!!(c&&!of(c)):!0)},Be=(e,{contextNode:t,selectedNode:n,readOnly:o,breadCrumb:r}=v())=>{let s=t.context??"WORKSPACE";return{[C.NONE]:FE({breadCrumb:r,readOnly:o,selectedNode:n}),[C.EXIT]:["confirm"],[C.EXPORT]:[],[C.SYNC]:[],[C.INIT]:[],[C.OPEN]:e===C.OPEN?Jc():[],[C.HELP]:[],[C.PEEK]:[...Kc(),"now","prev","next"],[C.REPLAY]:[...Kc()],[C.EDIT]:BE({selectedNode:n,breadCrumb:r}),[C.YANK]:OE({selectedNode:n,breadCrumb:r}),[C.COMMENT]:[],[C.DELETE]:["confirm"],[C.RE_OPEN_ISSUE]:["confirm"],[C.CLOSE_ISSUE]:["confirm"],[C.MOVE]:["start","confirm","next","previous","jump-next","jump-previous","to-next","to-previous","cancel"],[C.FILTER]:["tag","assignee","actor","description","title","ref","clear"],[C.TAG]:[...new Set([...Object.keys(qi),...N.getExistingTags()])],[C.UNTAG]:[...aa()?.value?.map(({name:c})=>c)??[]],[C.UNASSIGN]:[...la()?.value?.map(({name:c})=>c)??[]],[C.ASSIGN]:N.getExistingAssignees(),[C.NEW]:DE(s),[C.CONFIG]:[...PE]}[e]??[]};import bf from"chalk";var sf=["vim","nvim","nano","micro","emacs","hx","code","code-insiders","subl","notepad","notepad++","idea","webstorm","default","system","$EDITOR","$VISUAL"];import HE from"zod";import _E from"node:crypto";import ws from"node:fs";import cf from"node:path";var af="/media/",lf=e=>`${af}${e}`,Qc=(e,t)=>`![${e}](${lf(t)})`;var In=500,jE=/^[a-f0-9]{64}\.(png|jpg|gif|webp)$/,Oo=(e,t)=>`${e}.${t}`,$E=e=>jE.test(e),df=e=>e.length>=8&&e.subarray(0,8).equals(Buffer.from([137,80,78,71,13,10,26,10]))?u("Sniffed image type","png"):e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?u("Sniffed image type","jpg"):e.length>=6&&(e.subarray(0,6).equals(Buffer.from("GIF87a","ascii"))||e.subarray(0,6).equals(Buffer.from("GIF89a","ascii")))?u("Sniffed image type","gif"):e.length>=12&&e.subarray(0,4).equals(Buffer.from("RIFF","ascii"))&&e.subarray(8,12).equals(Buffer.from("WEBP","ascii"))?u("Sniffed image type","webp"):l(`Unsupported image format. Allowed: ${Np.join(", ")}`),uf=e=>_E.createHash("sha256").update(e).digest("hex"),UE=(e,t=In)=>{if(e.length===0)return l("Attachment is empty");if(e.length>t*1024)return l(`Attachment exceeds the ${t} KB size cap (${Math.ceil(e.length/1024)} KB)`);let n=df(e);return a(n)?n:u("Validated attachment data",{hash:uf(e),ext:n.value,bytes:e.length})},mf=(e,t,n=In)=>{let o=UE(t,n);if(a(o))return o;let r=gs(e),s=cf.join(r,Oo(o.value.hash,o.value.ext));try{ws.existsSync(s)||(ws.mkdirSync(r,{recursive:!0}),ws.writeFileSync(s,t))}catch(i){return l(`Unable to write attachment blob: ${i instanceof Error?i.message:String(i)}`)}return u("Wrote attachment blob",o.value)},pf=(e,t,n=In)=>{if(!$E(t))return l("Invalid attachment file name");let o=cf.join(gs(e),t);if(!ws.existsSync(o))return l("Attachment blob not found");let r;try{r=ws.readFileSync(o)}catch(d){return l(`Unable to read attachment blob: ${d instanceof Error?d.message:String(d)}`)}if(r.length>n*1024)return l(`Attachment exceeds the ${n} KB size cap and will not be served`);let[s,i]=t.split(".");if(uf(r)!==s)return l("Attachment blob does not match its content hash");let c=df(r);return a(c)?c:c.value!==i?l("Attachment blob content does not match its extension"):u("Resolved attachment blob",{filePath:o,ext:i,bytes:r.length})};var Ts=50,Ms=5e3,ff=()=>{let e=se().commandMeta.inputString,t=HE.coerce.number().int().min(Ts).max(Ms).safeParse(e);if(!t.success)return l(`Attachment size cap must be ${Ts}-${Ms} KB (default ${In})`);let n=Ut({attachmentMaxKb:t.data});return a(n)?n:(je({attachmentMaxKb:t.data}),u(`Attachment size cap set to ${t.data} KB`,null))};var lt=(e,t,n)=>t.length>n?`${e} cannot exceed ${n} characters (got ${t.length})`:null;import{createHash as WE}from"node:crypto";var GE="0123456789ABCDEFGHJKMNPQRSTVWXYZ",VE=e=>{let t=WE("sha256").update(e).digest(),n=0n;for(let r=0;r<16;r++)n=n<<8n|BigInt(t[r]);let o="";for(let r=0;r<26;r++){let s=BigInt((25-r)*5);o+=GE[Number(n>>s&31n)]}return o},gf=new Map,Me=(e,t)=>{let n=`${e}:virtual:${t}`,o=gf.get(n);if(o!==void 0)return o;let r=VE(n);return gf.set(n,r),r};import hf from"chalk";var Se=e=>hf.dim(e),$e=e=>hf.hex(y.primary)(e),Ue=({prefix:e="",wordList:t,postfix:n="",noOfHints:o=100,inputString:r,minLengthForHints:s=1})=>{let i=r.trim();if(i.length<s)return"";let m=[...t.filter(Boolean).filter(f=>f.startsWith(i))].sort((f,g)=>Ji(f)-Ji(g)).slice(0,o).map(f=>Qi(f)).join(" ");return m?`${Se(e)}${m}${Se(n)}`:""};var En={None:"none",Invalid:"invalid",Valid:"valid"};var zE=["BOARD","TICKET","SWIMLANE"],yf=()=>{let e=v().selectedNode;if(!e?.context)return z({message:Se("Missing target context")});if(zE.includes(e.context))return ie();if(e.parentNodeId){let t=v().nodes[e.parentNodeId];if(t?.id===Me(t?.parentNodeId??"","comments"))return ie()}return z({message:Se("Command not available in this context")})},fe="<ENTER> to confirm",KE=()=>{let{userId:e}=V(),t=de();return!e||a(t)?[]:yn(t.value.emailLinks,e)},ie=(e="",t=[],n=!0)=>({message:n?Se(e):e,validity:En.Valid,completionWordList:t}),z=({message:e,completionWordList:t=[]})=>({validity:En.Invalid,message:e,completionWordList:t}),Nr=e=>e.length===0,vf=(e,t)=>{let n=yt(v().breadCrumb,"BOARD");if(a(n))return z({message:$e("Command is not applicable in this context")});let o=br(n.value.id);return a(o)?z({message:$e(`Unable to ${t}: board id is not a valid ULID`)}):tf({date:e,horizonDate:o.value})?null:z({message:$e(`nothing to ${t} before ${o.value.toISOString().slice(0,16).replace("T"," ")}`)})},ma=e=>` ${bf.hex("#000").bgHex(ze(e))(` ${e} `)} `,Zc=({modifier:e})=>{let t="confirm";return e===t?ie(fe):z({message:Nr(e)?Se("if you are certain, enter ")+Qi(t):"",completionWordList:[t]})},qE=({list:e,hint:t,onValue:n})=>({modifier:o,inputString:r})=>e.includes(o)?r.trim().length<1?z({message:Se(n)}):ie():z({message:Nr(o)?t:"",completionWordList:[...e]}),Cr=({hint:e,onOk:t})=>({modifier:n,inputString:o})=>Nr(n)&&Nr(o)?z({message:e,completionWordList:[]}):ie(t??fe),YE=({modifier:e,inputString:t})=>{let n=Jc();return!Nr(e)||!Nr(t)?ie(fe):z({message:n.length?Se("number from the list, or a path"):Se("path to an epiq project"),completionWordList:n})},XE=({modifier:e,inputString:t})=>{let n=Be(C.CONFIG);if(!n.includes(e))return z({message:Ue({prefix:"... ",wordList:n,inputString:e,minLengthForHints:0}),completionWordList:n});switch(e){case ye.EDITOR:{let o=[...sf];return t.trim()?o.includes(t.trim())?ie(fe):z({message:Ue({prefix:"editors: ",wordList:o,inputString:t,minLengthForHints:0}),completionWordList:o}):z({message:Ue({prefix:"editors: ",wordList:o,inputString:t,minLengthForHints:0}),completionWordList:o})}case ye.VIEW:{let o=["dense","wide"];return o.includes(t.trim())?ie(fe):z({message:Ue({prefix:"view... ",wordList:o,inputString:t,minLengthForHints:0}),completionWordList:o})}case ye.USERNAME:{let o=V().gitName,r=o?[o]:[],s=t.trim(),i=r.filter(p=>p.startsWith(s)),d=i.length===1&&i[0]===s?"":Ue({prefix:"name: ",wordList:r,inputString:s,minLengthForHints:0});return s?d?ie(`${d} ${Se(fe)}`,r,!1):ie(fe,r):z({message:d||$e("Enter a user name. Saved in ")+bf.bgBlack("~/.epiq-global/config.json"),completionWordList:r})}case ye.EMAILS:{let o=V().gitEmail,r=Rr(),s=r.length>0||!o?r:[o],i=[...s,"none"],c=t.trim(),d=(x,b)=>z({message:Ue({prefix:x,wordList:i,noOfHints:3,inputString:b,minLengthForHints:0}),completionWordList:i});if(!c)return ie(`${fe} to see your addresses, or name one`,i);let p=c.split(/[,\s]+/).filter(Boolean),m=p[p.length-1]??"",f=x=>x==="none"||s.includes(x.toLowerCase()),g=x=>i.some(b=>b.startsWith(x.toLowerCase())),h=p.filter(x=>!f(x)&&!g(x));return h.length>0?z({message:$e(`no address here matches ${h.join(", ")} \u2014 pick one from the list, or its number`),completionWordList:i}):f(m)?ie(fe):d("",m)}case ye.EMAILS_UNCLAIM:{let o=KE(),r=t.trim();return o.length===0?z({message:$e("you have not claimed any addresses"),completionWordList:[]}):r&&o.includes(r.toLowerCase())?ie(fe):z({message:Ue({prefix:"give an address back ",wordList:o,noOfHints:3,inputString:r,minLengthForHints:0}),completionWordList:o})}case ye.LOG_LEVEL:{let o=["debug","error","info"],r=t.trim();return o.includes(r)?ie(fe):z({message:Ue({prefix:"one of: ",wordList:[...o],inputString:r,postfix:" persisted in ~/.epiq-global/config.json",minLengthForHints:0}),completionWordList:[...o]})}case ye.AUTOSYNC:{let o=["on","off"],r=V().autoSync;if(!o.includes(t.trim())){let s=Jp(r);return z({message:Ue({prefix:`should auto-sync (recommended)${s!==null?", currently: "+s:""} `,wordList:o,noOfHints:3,inputString:t,minLengthForHints:0}),completionWordList:o})}return ie(fe)}case ye.ATTACHMENT_MAX_KB:{let o=V().attachmentMaxKb,r=Number.parseInt(t.trim(),10);if(!t.trim()||Number.isNaN(r)||r<Ts||r>Ms){let s=Ue({prefix:" examples: ",wordList:Xc,minLengthForHints:0,inputString:t});return z({message:$e(`provide a size cap in KB (${Ts}-${Ms}). current: ${o??In} KB.`)+s,completionWordList:Xc})}return ie(fe)}case ye.SYNC_DEBOUNCE_MS:{let o=V().autoSyncIntervalMs,r=ur(t);if(!t.trim()||r===null){let s=Ue({prefix:" examples: ",wordList:Yc,minLengthForHints:0,inputString:t});return z({message:$e(`provide a duration between ${3e3}ms and ${864e5}ms. current duration: ${o}ms.`)+s,completionWordList:Yc})}return ie(fe)}default:return z({message:$e("Unknown config option"),completionWordList:n})}},JE=({modifier:e,inputString:t})=>{let n=Be(C.EDIT);if(!n.length)return z({message:$e("Command not available in this context")});if(!n.includes(e)){let o=Ue({prefix:"edit... ",wordList:n,inputString:e,minLengthForHints:0});return z({message:o||$e("Unknown edit option"),completionWordList:n})}switch(e){case Dt.COMMENT:return t.trim()?ie(fe):z({message:Se("write a comment...")});case Dt.TITLE:return ie(fe);case Dt.DESCRIPTION:{let{preferredEditor:o}=V();return o?ie(Se("<ENTER> to edit in ")+o):z({message:"No editor selected"})}default:return z({message:$e("Unknown edit option"),completionWordList:n})}},QE=({modifier:e})=>{let t=Be(C.YANK);return t.length?t.includes(e)?ie(fe+Se(" and copy to clipboard")):z({message:Ue({prefix:"yank... ",wordList:t,inputString:e,minLengthForHints:0}),completionWordList:t}):z({message:$e("Nothing selected to copy from")})},ZE={[C.EXPORT]:()=>ie(fe+Se(", and create export markdown file")),[C.PEEK]:e=>{let t=e.modifier;if(t==="now"||t==="prev"||t==="next")return ie(fe);let n={message:Se("historical state from: '1h', '2d', '23h', '1mo', '2y', 'prev', 'next' or full date as YYYY-MM-DD")},o=t||e.inputString.trim(),r=ko(o);if(!o||!r)return z(n);let s=vf(r,"peek");return s||ie(fe)},[C.REPLAY]:e=>{let{dateInput:t,durationInput:n}=da(e.modifier,e.inputString),o={message:Se("replay forward from: '1h', '2d', '1mo', '2y' or full date as YYYY-MM-DD, with optional duration (e.g. '2y 30s')")},r=ko(t);if(!t||!r)return z(o);let s=vf(r,"replay");return s||(n&&ca(n)===null?z({message:$e("duration must be positive (e.g. 30s, 2m, or a number of seconds)")}):ie("<ENTER> to replay board history",n?rf:[]))},[C.EXIT]:()=>ie(fe+Se(" and exit the application")),[C.INIT]:()=>ie(fe),[C.OPEN]:YE,[C.PALETTE]:()=>ie(fe),[C.FILTER]:e=>{if(e.modifier==="clear")return ie(fe);let t=s=>Be(C.FILTER).includes(s);if(!e.modifier||!t(e.modifier))return z({message:Ue({wordList:Be(C.FILTER),inputString:e.inputString,minLengthForHints:0}),completionWordList:Be(C.FILTER)});let n=Object.values(v().tags).map(s=>s.name),o=Object.values(v().contributors).map(s=>s.name),r=e.modifier==="tag"?n:e.modifier==="assignee"?o:[];return e.inputString?r.length&&!r.includes(e.inputString.trim())?z({message:Ue({prefix:`existing ${e.modifier}s... `,wordList:r,noOfHints:10,inputString:e.inputString,minLengthForHints:0}),completionWordList:r}):ie():z({message:Ue({prefix:"one of... ",wordList:r,noOfHints:10,inputString:e.inputString,minLengthForHints:0}),completionWordList:r})},[C.NONE]:e=>{let t=Be(C.NONE);return z({message:Ue({prefix:"... ",wordList:t,inputString:e.inputString,minLengthForHints:0}),completionWordList:t})},[C.NEW]:e=>qE({list:Be(C.NEW),hint:Ue({wordList:Be(C.NEW),noOfHints:3,inputString:e.inputString,minLengthForHints:0}),onValue:"provide a name..."})(e),[C.HELP]:()=>ie(fe),[C.EDIT]:JE,[C.COMMENT]:e=>{let t=Cr({hint:Se(`write a comment (max ${4e3} char)...`),onOk:Se(`(${e.inputString.length}/${4e3})`)})(e);return t.validity===En.Invalid?t:e.inputString.length>4e3?ie($e("max input exceeded")):t},[C.CONFIG]:XE,[C.YANK]:QE,[C.DELETE]:e=>{let t=yf();return t.validity==="invalid"?t:Zc(e)},[C.CLOSE_ISSUE]:e=>Zc(e),[C.RE_OPEN_ISSUE]:e=>Zc(e),[C.MOVE]:e=>{let t=yf();return t.validity==="invalid"?t:Cr({hint:Ue({prefix:"hey hacker! These commands are blocked for you... ",wordList:Be(C.MOVE),noOfHints:10,inputString:e.inputString})})(e)},[C.TAG]:e=>{let n=N.getExistingTags().slice(0,10).map(ma).join("");return Cr({hint:n.length?Se("create tag or reuse:")+n+Se(""):Se("create tag ...")})(e)},[C.UNTAG]:e=>{let t=aa();if(a(t))return z({message:$e("Invalid untag target"),completionWordList:[]});let n=t.value.map(({name:o})=>o).map(ma).slice(0,10);return n.length?Cr({hint:Se(" ... ")+n.join("")})(e):z({message:$e("Issue has no tags"),completionWordList:[]})},[C.ASSIGN]:e=>{let t=N.getExistingAssignees().map(ma).slice(0,10);return Cr({hint:Se("assignees... ")+t.join("")})(e)},[C.UNASSIGN]:e=>{let t=la();if(a(t))return z({message:$e("Invalid unassign target"),completionWordList:[]});let n=t.value.map(({name:o})=>o).map(ma).slice(0,10);return n.length?Cr({hint:Se("remove assignee... ")+n.join("")})(e):z({message:$e("Issue has no assignees"),completionWordList:[]})},[C.SYNC]:()=>ie(fe)},xf=Object.fromEntries(Object.entries(ZE).map(([e,t])=>[e,{validate:(n,o,r)=>t({modifier:o,command:n,inputString:r})}]));var pa=["add","fix","bug","log","run","api","cli","ui","ux","test","mock","stub","sync","hash","sign","fork","push","pull","lock","warn","leak","hang","node","seed","lint","edit","save","load","read","send","drop","swap","wrap","port","host","role","user","auth","flag","diff","perf","docs","todo","task","team","epic","spec","remove","update","change","improve","enhance","refactor","rewrite","redesign","implement","build","create","delete","rename","migrate","upgrade","downgrade","revert","rollback","restore","replace","deprecate","cleanup","simplify","optimize","stabilize","harden","document","clarify","investigate","debug","reproduce","triage","mitigate","remediate","resolve","escalate","verify","validate","benchmark","profile","audit","monitor","instrument","configure","provision","deploy","release","publish","integrate","automate","support","enable","disable","prevent","handle","ensure","prioritize","estimate","schedule","track","install","uninstall","enforce","expose","extract","inject","override","extend","customize","localize","translate","redirect","forward","dispatch","broadcast","subscribe","unsubscribe","register","allocate","reserve","persist","retrieve","archive","expire","refresh","reload","reset","recover","replay","retry","scaffold","bootstrap","finalize","terminate","suspend","resume","cancel","abort","notify","alert","trigger","debounce","frontend","backend","fullstack","infrastructure","architecture","integration","application","environment","framework","platform","service","component","module","gateway","pipeline","container","orchestrator","middleware","endpoint","interface","database","datastore","cache","queue","scheduler","worker","daemon","runtime","library","package","plugin","extension","webhook","microservice","monolith","repository","namespace","cluster","sandbox","tenant","dashboard","console","portal","client","server","browser","mobile","desktop","kernel","driver","protocol","schema","migration","fixture","template","snippet","config","manifest","bundle","exception","incident","defect","regression","degradation","malfunction","instability","intermittent","workaround","failure","outage","crash","freeze","corruption","inconsistency","severity","criticality","diagnostics","analysis","blocker","flaky","timeout","mismatch","misconfiguration","boundary","overflow","underflow","panic","stacktrace","breakage","breaking","oversight","ambiguity","discrepancy","anomaly","authorize","authenticate","confidentiality","availability","accessibility","reliability","compliance","governance","encrypt","decrypt","integrity","traceability","accountability","protection","privileges","permissions","sanitize","escape","vulnerability","exposure","secrets","credentials","certificate","session","cookie","identity","tokenization","rotation","scanning","hardening","threat","exploit","payload","injection","phishing","breach","dependency","orchestrate","synchronize","compatibility","incompatibility","interoperability","observability","telemetry","discovery","registration","coordination","distribution","isolation","virtualization","networking","routing","proxy","firewall","balancer","failover","topology","replica","shard","region","capacity","quota","metrics","logging","tracing","alerting","monitoring","heartbeat","liveness","rollover","serialize","deserialize","initialize","instantiate","propagate","aggregate","consolidate","normalize","standardize","transform","reconcile","correlate","index","partition","enrich","filter","stream","batch","parse","encode","decode","compress","decompress","deduplicate","paginate","query","ingest","export","import","backup","snapshot","mapping","record","dataset","metadata","checksum","rollup","lookup","cursor","truncate","concurrency","parallelism","contention","deadlock","throttle","backpressure","fragmentation","saturation","exhaustion","replicate","redundancy","obsolescence","starvation","overload","latency","throughput","scalability","bottleneck","memoize","prefetch","warmup","autoscale","horizontal","vertical","elasticity","recursion","allocation","leakage","garbage","collection","pooling","buffering","caching","eviction","staleness","modularize","encapsulate","abstraction","extensibility","configurability","maintainability","recoverability","readability","testability","debuggability","reusability","simplicity","consistency","linting","formatting","typecheck","coverage","tooling","scaffolding","boilerplate","technical","cleanliness","naming","comments","docstring","testing","unittest","mocking","stubbing","assertion","smoke","sanity","fuzzing","flakiness","harness","scenario","baseline","performance","functionality","requirement","recommendation","improvement","enhancement","description","acceptance","criteria","deliverable","milestone","iteration","backlog","roadmap","followup","hotfix","patch","changelog","rollout","feature","spike","proposal","specification","priority","sprint","story","subtask","assignee","reviewer","reproduction","context","expected","actual","impact","workflow","version","tracking","discussion","decision","tradeoff","feedback","approval","planning","breakdown","scoping"];var eS=3,tS=new Set(["the","and","for","are","but","not","you","all","any","can","was","one","our","out","use","this","that","with","have","from","will","your","they","them","then","than","when","what","were","been","into","should","would","could","about"]),nS=e=>{let t=[];for(let n of Object.values(e.nodes)){n.title&&t.push(n.title);let o=n.props;typeof o.description=="string"&&t.push(o.description),typeof o.value=="string"&&t.push(o.value)}for(let n of Object.values(e.tags))t.push(n.name);for(let n of Object.values(e.contributors))t.push(n.name);for(let n of Object.values(e.comments))t.push(n.md);return t},oS=e=>e.toLowerCase().split(/[^a-z0-9]+/).filter(t=>t.length>=eS&&!tS.has(t)&&!/^\d+$/.test(t)),rS=e=>{let t=new Map;for(let s of nS(e))for(let i of oS(s))t.set(i,(t.get(i)??0)+1);let n=[...t.entries()].sort((s,i)=>i[1]-s[1]||s[0].localeCompare(i[0])).map(([s])=>s),o=new Set(n),r=pa.filter(s=>!o.has(s));return[...n,...r]},If=pa,Ef=-1,Sf=()=>{let e=de();if(a(e))return pa;let t=e.value,n=t.eventLog.length;return n!==Ef&&(If=rS(t),Ef=n),If};var Rf=e=>Object.values(C).includes(e),Cf=(e,t)=>{let n=e.command??"",{modifier:o,target:r,inputString:s}=e,{message:i,validity:c,completionWordList:d}=xf[n].validate(n,o,s),p=n!==C.PEEK&&n!==C.REPLAY,m=r==="command"||r==="modifier"?Be(n):p?Sf():[],{mode:f}=v(),g=f===I.COMMAND_LINE?i??"":"",h=[...d,...m];return{validity:c,command:e.command,modifier:e.modifier,inputString:e.inputString,infoMessage:g,autoCompletion:t?$p(e,h,d):{hint:"",hints:[],remainder:"",overlap:0}}};var Nf=e=>{let t=e.trimStart(),n=iS(t),o=n[0]??"",r=n[1]??"",s=/\s$/.test(e),i=aS(e),c=Rf(o)?o:null,d=c!==null,p=o!=="",m=c?Be(c)??[]:[],f=c&&m.includes(r)?r:"",g="word";n.length===0||n.length===1&&!s?g="command":(n.length===1&&s||n.length===2&&!s)&&(g="modifier");let h=s?"":i,x=sS(t,c,f);return{raw:e,trimmedStart:t,words:n,firstWord:o,lastWord:i,hasCommand:p,command:c,isCommandKeyword:d,isLastWordCompleted:s,modifier:f,target:g,inputToMatch:h,inputString:x}},sS=(e,t,n)=>{let o=e;return t&&o.startsWith(t)&&(o=o.slice(t.length)),o=o.replace(/^\s+/,""),n&&o.startsWith(n)&&(o=o.slice(n.length),o=o.replace(/^\s+/,"")),o},iS=e=>e.trim()?e.trim().split(/\s+/):[],aS=e=>e.trimEnd().split(/\s+/).at(-1)??"";import{useSyncExternalStore as lS}from"react";var Ar=e=>e===ed||e===":",ed=" ",Ls=40,ct={commandHistory:[],value:"",commandHistoryIndex:-1,cursorPosition:0,commandIsPending:!1,commandMeta:{command:null,modifier:"",infoMessage:"",inputString:"",validity:En.None,autoCompletion:{hint:"",hints:[],remainder:"",overlap:0}}},td=new Set,Af=()=>{for(let e of td)e()},nd=e=>(td.add(e),()=>td.delete(e)),Wt=e=>{let n=e(ct),o=Nf(n.value),r=n.cursorPosition===n.value.length;ct={...n,commandMeta:Cf(o,r)},Af()},ks=({message:e,status:t})=>{let n=structuredClone(ct);return n.commandMeta={...n.commandMeta,infoMessage:e??"",validity:t==="fail"?"invalid":"valid"},n.commandIsPending=!0,ct=n,Af(),u(e,null)},od=e=>{Wt(t=>({...t,cursorPosition:Math.max(0,Math.min(t.value.length,t.cursorPosition+e))}))},rd=e=>{Wt(t=>{let{value:n,cursorPosition:o}=t,r=o;if(e==="left"){for(;r>0&&Ar(n[r-1]);)r--;for(;r>0&&!Ar(n[r-1]);)r--}else{for(;r<n.length&&!Ar(n[r]);)r++;for(;r<n.length&&Ar(n[r]);)r++}return{...t,cursorPosition:r}})},wf=()=>{Wt(e=>{let t=e.value.slice(e.cursorPosition),n=Math.max(0,e.cursorPosition-1);return{...e,value:e.value.slice(0,n)+t,cursorPosition:n,commandIsPending:!1}})},Tf=()=>{Wt(e=>{let{value:t,cursorPosition:n}=e,o=n;for(;o>0&&Ar(t[o-1]);)o--;for(;o>0&&!Ar(t[o-1]);)o--;let r=t.slice(n);return{...e,value:t.slice(0,o)+r,cursorPosition:o,commandIsPending:!1}})},fa=e=>{Wt(t=>{let n=Math.max(0,Math.min(t.cursorPosition,t.value.length)),o=t.value.slice(0,n),r=t.value.slice(n),s=e(o,t.commandMeta.autoCompletion),i=s+r,c=Math.max(0,Math.min(s.length,i.length));return{...t,value:i,cursorPosition:c,commandIsPending:!1}})},Mf=()=>{Wt(e=>({...e,commandIsPending:!0}))},J=e=>{Wt(t=>({...t,value:e,cursorPosition:e.length,commandIsPending:!1}))},Pf=({addToHistory:e=!0,line:t})=>{Wt(n=>{let o=t??n.value;return{...n,commandHistory:e&&o.trim()?[o,...n.commandHistory].slice(0,Ls):n.commandHistory,commandHistoryIndex:-1,commandIsPending:!1,value:"",cursorPosition:0}})},Lf=e=>{Wt(t=>({...t,commandHistory:e.slice(0,Ls),commandHistoryIndex:-1}))},kf=()=>{Wt(e=>e.commandHistoryIndex===-1?e:{...e,commandHistoryIndex:-1})},Df=()=>{Wt(e=>{let t=Math.min(e.commandHistoryIndex+1,e.commandHistory.length-1),n=e.commandHistory[t]??"";return{...e,commandHistoryIndex:t,value:n,cursorPosition:n.length}})},Bf=()=>{Wt(e=>{let t=Math.max(e.commandHistoryIndex-1,-1),n=t===-1?"":e.commandHistory[t]??"";return{...e,commandHistoryIndex:t,value:n,cursorPosition:n.length}})},se=()=>ct,Of=()=>lS(nd,se,se),ga=()=>{let[e,...t]=ct.value.split(ed);return t.join(ed).trim()};var E={NavPreviousItem:"navPreviousItem",NavNextItem:"navNextItem",NavPreviousItemJump:"navPreviousItemJump",NavNextItemJump:"navNextItemJump",NavToPreviousContainer:"navToPreviousContainer",NavToNextContainer:"navToNextContainer",MovePreviousItem:"movePreviousItem",MoveNextItem:"moveNextItem",MovePreviousItemJump:"movePreviousItemJump",MoveNextItemJump:"moveNextItemJump",MoveToPreviousContainer:"moveToPreviousContainer",MoveToNextContainer:"moveToNextContainer",Confirm:"confirm",Exit:"exit",ViewHelp:"viewHelp",HideHelp:"hideHelp",InitMove:"initMove",ConfirmMove:"confirmMove",Delete:"Delete",InitCommandPalette:"initCommandPalette",InitCommandLine:"initCommandLine",ExitCommandLine:"exitCommandLine",CaptureInput:"captureInput",EraseInput:"eraseInput",AddItem:"addItem",GetLastCommandFromHistory:"getLastCommandFromHistory",GetNextCommandFromHistory:"getNextCommandFromHistory",AutoCompleteCommand:"autoCompleteCommand",MoveCursorLeft:"MoveCursorLeft",MoveCursorRight:"MoveCursorRight",MoveCursorLeftOfWord:"MoveCursorLeftOfWord",MoveCursorRightOfWord:"MoveCursorRightOfWord",EraseInputWord:"EraseInputWord",None:"None",Edit:"edit",EditTitle:"editTitle",EditDescription:"editDescription",Yank:"yank",OpenInEditor:"openInEditor",MarkDiffLine:"markDiffLine",CommentOnDiffLine:"commentOnDiffLine",SetViewDense:"SetViewDense",SetViewWide:"SetViewWide"},cS=e=>e.shift===!0,dS={[E.NavPreviousItem]:E.NavPreviousItemJump,[E.NavNextItem]:E.NavNextItemJump,[E.MovePreviousItem]:E.MovePreviousItemJump,[E.MoveNextItem]:E.MoveNextItemJump};function uS(e){switch(e.name){case"up":case"down":case"left":case"right":return e.name;default:return null}}function mS(e){switch(e.name){case"k":return"up";case"j":return"down";case"h":return"left";case"l":return"right";default:return null}}function pS(e,t,n){let o=v().contextNode.childNavigationAcrossParents;switch(t){case"up":return e==="vertical"?n.prevItem:o?n.prevContainer:null;case"down":return e==="vertical"?n.nextItem:o?n.nextContainer:null;case"left":return e==="horizontal"?n.prevItem:o?n.prevContainer:null;case"right":return e==="horizontal"?n.nextItem:o?n.nextContainer:null}}function Ff(e,t){let n=se();if(e.sequence==="?"&&t!==I.PALETTE)return E.InitCommandPalette;if(e.sequence===":"&&t!==I.COMMAND_LINE)return E.InitCommandLine;if(t===I.MOVE)switch(e.name){case"m":case"return":return E.ConfirmMove}if(t===I.COMMAND_LINE)return Pp(e,n.value);if(t===I.PALETTE)return Lp(e,n.value);let o=uS(e)||mS(e);if(o)return fS(o,t,cS(e));if(e.ctrl&&e.name==="c")return E.Exit;switch(e.name){case"r":return E.EditTitle;case"e":return E.EditDescription;case"n":return E.AddItem;case"m":return E.InitMove;case"d":return E.Delete;case"y":return E.Yank;case"o":return E.OpenInEditor;case"s":return E.MarkDiffLine;case"c":return E.CommentOnDiffLine;case"return":return E.Confirm;case"space":return E.Confirm;case"v":return V().viewMode==="wide"?E.SetViewDense:E.SetViewWide;case"q":case"escape":return E.Exit;default:return null}}function fS(e,t,n=!1){let o=t===I.MOVE?{prevItem:E.MovePreviousItem,nextItem:E.MoveNextItem,prevContainer:E.MoveToPreviousContainer,nextContainer:E.MoveToNextContainer}:{prevItem:E.NavPreviousItem,nextItem:E.NavNextItem,prevContainer:E.NavToPreviousContainer,nextContainer:E.NavToNextContainer},r=pS(v().contextNode.childRenderAxis,e,o);return!r||!n?r:dS[r]??r}import{ulid as yS}from"ulid";var Ds=24n,gS=Ds*4n,tn=(1n<<gS)-1n,hS=/^[0-9a-f]+$/;function _f(e){return!e||!hS.test(e)?l(`Invalid hex rank: ${e}`):u("Converted rank to bigint",BigInt("0x"+e))}function Bt(e,t=Ds){if(e<0n)return l("Negative rank not allowed");let n=e.toString(16);return u("Converted bigint to hex rank",n.padStart(Number(t),"0"))}function vt(e,t){if(!e&&!t)return Bt(tn/2n,Ds);let n=e?_f(e):u("Resolved lower bound",0n);if(a(n))return n;let o=t?_f(t):u("Resolved upper bound",tn);if(a(o))return o;let r=n.value,s=o.value;if(s<=r)return l("Neighbouring ranks leave no space between them");let i=(r+s)/2n;return i===r||i===s?l("No rank space available between neighbors"):Bt(i,Ds)}function jf(e){if(e<=0)return u("Resolved empty rank list",[]);let t=BigInt(e),n=[];for(let o=0;o<e;o++){let r=tn*BigInt(o+1)/(t+1n),s=Bt(r,Ds);if(a(s))return s;n.push(s.value)}return u("Resolved evenly spaced ranks",n)}var D=({userId:e})=>({userId:e}),$f=e=>({action:e.action,payload:e.payload});var sd=["init.workspace","add.workspace","add.board","add.swimlane","add.issue","add.field","edit.title","delete.node","create.tag","tombstone.tag","restore.tag","create.contributor","rename.contributor","tombstone.contributor","restore.contributor","add.issue.assignee","remove.issue.assignee","add.issue.tag","remove.issue.tag","move.node","edit.description","add.issue.comment","edit.issue.comment","delete.issue.comment","add.issue.attachment","delete.issue.attachment","close.issue","reopen.issue","lock.node","rebalance.children","link.contributor.user","link.contributor.email","unlink.contributor.email"];var dB=new Set(sd);var id=(e,t)=>{let n=be(e),o=jf(n.length);if(a(o))return o;let r={};for(let s=0;s<n.length;s++){let i=n[s],c=o.value[s];if(!i||!c)return l("Unable to assign rebalance rank");r[i.id]=c}return u("Created rebalance event",{id:yS(),action:"rebalance.children",payload:{parent:e,ranks:r},...D(t)})};import{z as Fo}from"zod";var Uf=1,Hf=Fo.tuple([Fo.string().min(1),Fo.string().min(1).nullable()]),vS=Fo.looseObject({v:Fo.literal(Uf),id:Hf}),RB=Fo.looseObject({v:Fo.number().int().positive(),id:Hf}),bS=e=>Object.prototype.hasOwnProperty.call(e,"__proto__"),xS=e=>{let t={};for(let n of Object.keys(e))n!=="__proto__"&&(t[n]=e[n]);return t},Wf=e=>{if(typeof e!="object"||e===null||Array.isArray(e))return l("Invalid persisted event envelope: expected an object");let{v:t,id:n}=e;if(typeof t!="number"||!Number.isSafeInteger(t)||t<=0)return l("Invalid persisted event envelope: v");if(!Array.isArray(n)||n.length!==2)return l("Invalid persisted event envelope: id");let[o,r]=n;return typeof o!="string"||o.length===0?l("Invalid persisted event envelope: id.0"):r!==null&&(typeof r!="string"||r.length===0)?l("Invalid persisted event envelope: id.1"):u("Parsed persisted event envelope",bS(e)?xS(e):e)};var IS=[1];var ES=new Set(IS),ad=e=>ES.has(e),Gf=e=>{let t=vS.safeParse(e);return t.success?u("Parsed persisted event",t.data):l(`Invalid persisted event: ${t.error.issues.map(n=>n.path.join(".")||n.message).join(", ")}`)},ld=(e,t)=>{let n={[e.action]:e.payload,v:Uf,id:t};return Gf(n)};import _s from"node:fs";import Ea from"node:path";import{decodeTime as PS}from"ulid";import{z as gd}from"zod";import cd from"node:fs";import SS from"node:path";var Bs=e=>e?.code==="ENOENT",dd=3,ud=e=>cd.readdirSync(e).filter(t=>t.endsWith(".jsonl")).sort(),et=e=>{let t=St(e);for(let n=1;;n++){if(!cd.existsSync(t))return"none";let o=[],r=!1;for(let s of ud(t))try{let{size:i,mtimeMs:c}=cd.statSync(SS.join(t,s));o.push(`${s}:${i}:${c}`)}catch(i){if(!Bs(i))throw i;if(n<dd){r=!0;break}}if(!r)return o.join("|")}},Vf=e=>new Map(e.split("|").filter(Boolean).map(t=>{let n=t.indexOf(":");return[t.slice(0,n),t.slice(n+1)]})),md=(e,t,n)=>{let o=Vf(t),r=et(e),s=Vf(r);for(let[i,c]of s)if(i!==n&&o.get(i)!==c)return null;for(let i of o.keys())if(i!==n&&!s.has(i))return null;return r},so=null,ha=e=>so&&so.root===e?so.signature:null,wr=(e,t)=>{so={root:e,signature:t}},zf=(e,t)=>{if(!so||so.root!==e)return;let n=md(e,so.signature,t);so=n===null?null:{root:e,signature:n}};import He from"node:fs";import _o from"node:path";import{ulid as RS}from"ulid";var va="~pending",pd=/~pending(-[0-9a-z]+)*$/i,qf=/-f(\d+)$/,Yf=e=>{let t=e.indexOf(".");return t===-1?`${e}${va}`:e.slice(0,t)+va+e.slice(t)},ba=e=>{let t=e.indexOf(".");return t===-1?[e,""]:[e.slice(0,t),e.slice(t)]},CS=e=>{let[t,n]=ba(e);return pd.test(t)?t.replace(pd,"")+n:null},fd=e=>e.replace(pd,""),jo=e=>e.endsWith(".jsonl")&&CS(e)!==null,Os=e=>fd(ba(e)[0]),Xf=e=>{let[t]=ba(e),n=qf.exec(t);return n&&jo(e)?Number(n[1]):null},NS=e=>Yf(e).replace(va,`${va}-${RS().toLowerCase()}`),AS=(e,t)=>{let[n,o]=ba(e);return`${n.replace(qf,"")}-f${t}${o}`},Jf=(e,t)=>_o.join(St(e),Yf(t)),wS=(e,t)=>Math.max(0,He.statSync(e).size-(Xf(t)??0)),Qf=e=>{let t=St(e);try{return He.existsSync(t)?He.readdirSync(t).filter(jo).some(n=>wS(_o.join(t,n),n)>0):!1}catch{return!0}},TS=3,Zf=(e,t)=>{for(let n=1;;n++){let o=He.openSync(e,"a"),r;try{He.writeSync(o,t),r=He.fstatSync(o).ino}finally{He.closeSync(o)}let s;try{s=He.statSync(e).ino}catch{s=null}if(s===r||n>=TS)return}},MS=e=>{let t;try{t=He.openSync(e,"r")}catch{return!0}try{let{size:n}=He.fstatSync(t);if(n===0)return!0;let o=Buffer.alloc(1);return He.readSync(t,o,0,1,n-1),o[0]===10}finally{He.closeSync(t)}},ya=10,Kf=(e,t,n=!1)=>{let o=n?t.length:t.lastIndexOf(ya)+1;if(o===0)return{bytes:0,lines:0};let r=t.subarray(0,o);if(r.toString("utf8").trim().length===0)return{bytes:o,lines:0};He.appendFileSync(e,Buffer.concat([Buffer.from(MS(e)?"":`
31
31
  `),r,Buffer.from(r[r.length-1]===ya?"":`
package/dist/mcp.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- var gI=Object.defineProperty;var g=(e,t)=>()=>(e&&(t=e(e=0)),t);var ss=(e,t)=>{for(var n in t)gI(e,n,{get:t[n],enumerable:!0})};var bm={};ss(bm,{failed:()=>a,isFail:()=>l,isSuccess:()=>_t,resultStatuses:()=>Tn,succeeded:()=>d});var Tn,a,d,l,_t,N=g(()=>{"use strict";Tn={Success:"success",Fail:"fail"},a=e=>({status:Tn.Fail,message:e,value:null}),d=(e,t)=>({status:Tn.Success,message:e,value:t}),l=e=>e.status==="fail",_t=e=>e.status==="success"});var Em={};ss(Em,{ACTOR_ID_ENV:()=>is,ACTOR_NAME_ENV:()=>Ft,applyActorNameArgument:()=>Ml,deriveActorId:()=>Im,isValidUserId:()=>Ai,isValidUserName:()=>as,resolveEnvActor:()=>Tl});import hI from"node:crypto";var Ft,is,xm,vI,wl,Ai,as,ro,Im,Tl,Ml,xr=g(()=>{"use strict";N();Ft="EPIQ_USER_NAME",is="EPIQ_USER_ID",xm="0123456789ABCDEFGHJKMNPQRSTVWXYZ",vI=26,wl=80,Ai=e=>/^[0-9A-HJKMNP-TV-Z]{26}$/.test(e),as=e=>e.trim().length>0&&e.length<=wl,ro=e=>e.trim().toLowerCase(),Im=e=>{let t=hI.createHash("sha256").update(`epiq:actor:${ro(e)}`).digest(),n="";for(let r=0;r<vI;r++)n+=xm[(t[r]??0)%xm.length];return n},Tl=(e,t=process.env)=>{let n=(t[Ft]??"").trim(),r=(t[is]??"").trim();return n?as(n)?!r&&e.userId&&e.userName&&ro(e.userName)===ro(n)?d("Actor override names the configured user",{userId:e.userId,userName:e.userName}):r&&!Ai(r)?a(`${is} must be 26 characters of Crockford base32`):r&&e.userId&&r===e.userId?a(`${is} is the configured user's own id; using it under a different name would rename them on the board`):d("Resolved actor from environment",{userId:r||Im(n),userName:r?n:ro(n)}):a(`${Ft} must be 1-${wl} characters of text`):r?a(`${is} is set without ${Ft}`):d("No actor override",null)},Ml=(e,t,n=process.env)=>{let r=e.trim();if(!as(r))return a(`${t} must be 1-${wl} characters of text`);let o=(n[Ft]??"").trim();return o&&ro(o)!==ro(r)?a(`${t} names ${r}, but ${Ft} names ${o}`):(o||(n[Ft]=r),d("Applied actor name argument",o||r))}});var kl,Sm=g(()=>{"use strict";kl="1.12.2"});var Rm={};ss(Rm,{parseMcpArgs:()=>bI});var yI,bI,Nm=g(()=>{"use strict";Sm();yI=`epiq-mcp ${kl}
2
+ var gI=Object.defineProperty;var g=(e,t)=>()=>(e&&(t=e(e=0)),t);var ss=(e,t)=>{for(var n in t)gI(e,n,{get:t[n],enumerable:!0})};var bm={};ss(bm,{failed:()=>a,isFail:()=>l,isSuccess:()=>_t,resultStatuses:()=>Tn,succeeded:()=>d});var Tn,a,d,l,_t,N=g(()=>{"use strict";Tn={Success:"success",Fail:"fail"},a=e=>({status:Tn.Fail,message:e,value:null}),d=(e,t)=>({status:Tn.Success,message:e,value:t}),l=e=>e.status==="fail",_t=e=>e.status==="success"});var Em={};ss(Em,{ACTOR_ID_ENV:()=>is,ACTOR_NAME_ENV:()=>Ft,applyActorNameArgument:()=>Ml,deriveActorId:()=>Im,isValidUserId:()=>Ai,isValidUserName:()=>as,resolveEnvActor:()=>Tl});import hI from"node:crypto";var Ft,is,xm,vI,wl,Ai,as,ro,Im,Tl,Ml,xr=g(()=>{"use strict";N();Ft="EPIQ_USER_NAME",is="EPIQ_USER_ID",xm="0123456789ABCDEFGHJKMNPQRSTVWXYZ",vI=26,wl=80,Ai=e=>/^[0-9A-HJKMNP-TV-Z]{26}$/.test(e),as=e=>e.trim().length>0&&e.length<=wl,ro=e=>e.trim().toLowerCase(),Im=e=>{let t=hI.createHash("sha256").update(`epiq:actor:${ro(e)}`).digest(),n="";for(let r=0;r<vI;r++)n+=xm[(t[r]??0)%xm.length];return n},Tl=(e,t=process.env)=>{let n=(t[Ft]??"").trim(),r=(t[is]??"").trim();return n?as(n)?!r&&e.userId&&e.userName&&ro(e.userName)===ro(n)?d("Actor override names the configured user",{userId:e.userId,userName:e.userName}):r&&!Ai(r)?a(`${is} must be 26 characters of Crockford base32`):r&&e.userId&&r===e.userId?a(`${is} is the configured user's own id; using it under a different name would rename them on the board`):d("Resolved actor from environment",{userId:r||Im(n),userName:r?n:ro(n)}):a(`${Ft} must be 1-${wl} characters of text`):r?a(`${is} is set without ${Ft}`):d("No actor override",null)},Ml=(e,t,n=process.env)=>{let r=e.trim();if(!as(r))return a(`${t} must be 1-${wl} characters of text`);let o=(n[Ft]??"").trim();return o&&ro(o)!==ro(r)?a(`${t} names ${r}, but ${Ft} names ${o}`):(o||(n[Ft]=r),d("Applied actor name argument",o||r))}});var kl,Sm=g(()=>{"use strict";kl="1.12.4"});var Rm={};ss(Rm,{parseMcpArgs:()=>bI});var yI,bI,Nm=g(()=>{"use strict";Sm();yI=`epiq-mcp ${kl}
3
3
 
4
4
  Usage: epiq-mcp [name]
5
5
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epiq",
3
- "version": "1.12.2",
3
+ "version": "1.12.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "EPIQ - ergonomic, distributed CLI-first issue tracker TUI ready for the agentic era",
@@ -51,8 +51,8 @@
51
51
  "test:e2e:ci": "export IS_CI=true EPIQ_E2E_TIMEOUT_SCALE=${EPIQ_E2E_TIMEOUT_SCALE:-2} && ([ -n \"${EPIQ_SKIP_BUILD:-}\" ] || npm run build:npm) && vitest run --maxWorkers=4 source/test/e2e/",
52
52
  "test:e2e": "docker run --rm -e EPIQ_SKIP_BUILD -v \"$PWD\":/app -v /app/node_modules -w /app epiq-e2e npm run test:e2e:ci",
53
53
  "test:gui": "playwright test",
54
- "test:gui:warnings": "export IS_CI=true EPIQ_GUI_DEV_BUILD=1 && npm run build:npm && playwright install --with-deps chromium && playwright test",
55
- "test:gui:ci": "export IS_CI=true && npm run build:npm && playwright install --with-deps chromium && playwright test",
54
+ "test:gui:warnings": "export IS_CI=true EPIQ_GUI_DEV_BUILD=1 && npm run build:npm && playwright install chromium && playwright test",
55
+ "test:gui:ci": "export IS_CI=true && npm run build:npm && playwright install chromium && playwright test",
56
56
  "build:e2e:image": "docker build -f source/test/e2e/Dockerfile -t epiq-e2e .",
57
57
  "prepack": "npm run build:publish",
58
58
  "pack:check": "rm -f epiq-*.tgz && npm pack && FILE=$(ls -t epiq-*.tgz | head -n 1) && echo \"$FILE\" && tar -tf \"$FILE\"",
@@ -69,7 +69,7 @@
69
69
  "dist"
70
70
  ],
71
71
  "dependencies": {
72
- "@modelcontextprotocol/sdk": "^1.29.0",
72
+ "@modelcontextprotocol/sdk": "^1.32.1",
73
73
  "@pierre/diffs": "^1.3.6",
74
74
  "@xterm/headless": "^6.0.0",
75
75
  "ink": "^6.8.0",
@@ -77,7 +77,7 @@
77
77
  "react": "^19.2.4",
78
78
  "react-dom": "^19.2.6",
79
79
  "react-markdown": "^10.1.0",
80
- "react-router-dom": "^7.17.0",
80
+ "react-router-dom": "^7.18.4",
81
81
  "remark-breaks": "^4.0.0",
82
82
  "remark-gfm": "^4.0.1",
83
83
  "string-width": "^8.2.0",
@@ -97,9 +97,9 @@
97
97
  "@typescript-eslint/eslint-plugin": "^8.46.0",
98
98
  "@typescript-eslint/parser": "^8.46.0",
99
99
  "@vdemedes/prettier-config": "^2.0.1",
100
- "@vitest/coverage-v8": "4.1.2",
100
+ "@vitest/coverage-v8": "4.1.11",
101
101
  "chalk": "^5.2.0",
102
- "esbuild": "^0.25.0",
102
+ "esbuild": "^0.28.2",
103
103
  "eslint": "^9.39.1",
104
104
  "eslint-plugin-react": "^7.37.5",
105
105
  "eslint-plugin-react-hooks": "^7.0.1",
@@ -110,7 +110,7 @@
110
110
  "tsx": "^4.20.3",
111
111
  "typescript": "^5.0.3",
112
112
  "typescript-eslint": "^8.46.0",
113
- "vitest": "4.1.2"
113
+ "vitest": "4.1.11"
114
114
  },
115
115
  "prettier": "@vdemedes/prettier-config"
116
116
  }
package/readme.md CHANGED
@@ -1,20 +1,18 @@
1
1
  # Epiq
2
2
 
3
- _Issue tracking as code. Open source, distributed, local-first, and code-native._
3
+ Epiq is a self-hosted issue tracker that allows you to review workflows in real time or after the fact via replay. It persists state as an immutable event log, versioned and synchronized via Git.
4
4
 
5
- **[See docs →](https://ljtn.github.io/epiq/docs.html)**
5
+ Most issue trackers live outside your workflow. Instead of a centralized, managed service, Epiq offers issue tracking as an integrated part of the development environment offering workflow replay and inline code-diffs, tackling the review bottleneck with time-travel, filtering, and a tight code integration.
6
6
 
7
- Epiq provides issue tracking as a portable, integrated part of the development environment, with access to all the powerful tooling developers are used to.
7
+ **[Site →](https://ljtn.github.io/epiq/)**
8
8
 
9
- > Kanban to review workflows in your terminal or in your browser - while keeping all state local, Git-backed, and versioned.
10
-
11
- With great attention to user ergonomics and developer experience, epiq strives to make project management painless and friction free.
9
+ > All state is kept local, Git-backed, and versioned.
12
10
 
13
11
  ![The Epiq GUI: the event log, the board and a ticket's code diff, under the time travel timeline](https://raw.githubusercontent.com/ljtn/epiq/main/source/assets/time-travel.jpeg)
14
12
 
15
13
  ## Audit the workflow
16
14
 
17
- Agents now run whole sprints unattended. Because state is a full event log, you can replay the board to find out what moved when, who moved it, and what changed along the way.
15
+ Agents now run whole sprints unattended. Because state is an event log, you can replay the board to find out what moved when, who moved it, and what changed along the way.
18
16
 
19
17
  ## Code, linked to tickets
20
18
 
@@ -39,14 +37,9 @@ Epiq originated from the command line and offers a first-class terminal experien
39
37
 
40
38
  ![The Epiq terminal UI: the same board rendered in a terminal, with the command palette along the bottom](https://raw.githubusercontent.com/ljtn/epiq/main/source/assets/tui.jpeg)
41
39
 
42
- ## What is epiq?
43
-
44
- Epiq is a self hosted issue tracker that allows you to review workflows in real time or after the fact via replay. It persists state as an immutable event log, versioned and synchronized via Git.
45
-
46
- Most issue trackers live outside your workflow. Instead of a centralized, managed service, Epiq keeps project state alongside your repository, where it travels with your code.
47
-
48
- These design choices result in a system that offers:
40
+ ## How it is different
49
41
 
42
+ Fundamental design choices gives a system with:
50
43
  - **Workflow replay**, - inspect what happened while you were away, as if it happens now
51
44
  - **Simple setup** — no accounts, SaaS, or external services required
52
45
  - **Repo-native** — your issues can live where your code lives