epiq 1.15.0 → 1.15.2
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-G4CUKBA2.js +16 -0
- package/dist/{args-SB26WNBZ.js → args-7BQCBFSS.js} +1 -1
- package/dist/chunk-FDSMDDGG.js +2 -0
- package/dist/{chunk-C4V7IKIG.js → chunk-VRDQK5QD.js} +75 -74
- package/dist/{chunk-FLZ5VLKV.js → chunk-ZPUSANPS.js} +3 -3
- package/dist/gui/inter-OFL.txt +92 -0
- package/dist/gui/inter.woff2 +0 -0
- package/dist/gui/main.js +197 -169
- package/dist/index.js +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{server-ZFM45XFD.js → server-CMCAPC5E.js} +15 -16
- package/dist/{virtual-nodes-QB7VWWF2.js → virtual-nodes-5IGKV5PO.js} +1 -1
- package/package.json +1 -1
- package/dist/Index-S6LJGU7V.js +0 -16
- package/dist/chunk-6VBRR7QM.js +0 -2
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.NODE_ENV||="production";await import("./Index-
|
|
2
|
+
process.env.NODE_ENV||="production";await import("./Index-G4CUKBA2.js");
|
package/dist/mcp.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
process.env.EPIQ_MCP="true";process.env.NODE_ENV||="production";console.log=console.error;console.info=console.error;console.debug=console.error;console.warn=console.error;var{applyActorNameArgument:r}=await import("./actor-env-F6R6NBSD.js"),{isFail:s}=await import("./result-types-RM3ASLV3.js"),{parseMcpArgs:t}=await import("./args-
|
|
2
|
+
process.env.EPIQ_MCP="true";process.env.NODE_ENV||="production";console.log=console.error;console.info=console.error;console.debug=console.error;console.warn=console.error;var{applyActorNameArgument:r}=await import("./actor-env-F6R6NBSD.js"),{isFail:s}=await import("./result-types-RM3ASLV3.js"),{parseMcpArgs:t}=await import("./args-7BQCBFSS.js"),e=t(process.argv.slice(2));e.kind==="error"&&(console.error(e.message),process.exit(1));e.kind==="print"&&(process.stdout.write(e.text),process.exit(0));if(e.kind==="name"){let o=r(e.name,"The name argument");s(o)&&(console.error(o.message),process.exit(1))}var{setVirtualNodesEnabled:n}=await import("./virtual-nodes-5IGKV5PO.js");n(!1);var{startMcpServer:a}=await import("./server-CMCAPC5E.js");await a();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{$ as Ie,B as Y,C as W,D as V,E as Z,F as ee,G as te,H as ie,I as oe,J as ne,K as se,L as re,M as ae,N as ce,O as le,P as de,Q as
|
|
2
|
+
import{$ as Ie,B as Y,C as W,D as V,E as Z,F as ee,G as te,H as ie,I as oe,J as ne,K as se,L as re,M as ae,N as ce,O as le,P as de,Q as pe,R as me,S as he,T as ue,U as ge,V as fe,W as we,X as be,Y as ye,Z as _e,_ as ve,b as R,ba as qe,ca as ke,da as Se,fa as Re,i as O,k as D,ka as Te,l as G,m as $,p as B,t as F,u as H,v as z,w as K,x as X,y as J,z as Q}from"./chunk-ZPUSANPS.js";import{Kb as U,ab as S,b as N,ca as M,h as A,l as C,m as P,x as L}from"./chunk-VRDQK5QD.js";import{a as x}from"./chunk-WUCQWBQE.js";import{b as r,c as w,d as a}from"./chunk-5RIQL7P4.js";import{McpServer as Be}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as Fe}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as e}from"zod";import{ulid as Oe}from"ulid";var Ee=[{name:"userName",question:"the name they want to appear under on the board"},{name:"preferredEditor",question:'the command that opens a file for editing, e.g. "vim", "nano" or "code --wait"'},{name:"autoSync",question:"whether the TUI and GUI should sync with the git remote on their own (true or false)"}],je=t=>t.trim().toLowerCase(),xe=async(t={})=>{let o=C();if(a(o))return r(o.message);let n=o.value,c=t.userName?.trim(),E=(process.env[x]??"").trim();if(c&&E&&je(c)===je(E))return r(`userName "${c}" is this agent's own identity. Pass the user's name, the one they want the TUI and GUI to write as.`);let p={userName:c||void 0,preferredEditor:t.preferredEditor?.trim()||void 0,autoSync:t.autoSync},g={userName:n.userName?.trim()||void 0,preferredEditor:n.preferredEditor?.trim()||void 0,autoSync:typeof n.autoSync=="boolean"?n.autoSync:void 0};for(let s of Ee){let d=p[s.name],f=g[s.name];if(!(d===void 0||f===void 0||d===f))return r(`This machine is already set up with ${s.name} ${JSON.stringify(f)}; epiq_project_init does not change it. Call again without ${s.name}, or let the user change it in the TUI with :config.`)}let l={};if(p.userName&&!g.userName&&(l.userName=p.userName),p.preferredEditor&&!g.preferredEditor&&(l.preferredEditor=p.preferredEditor),p.autoSync!==void 0&&g.autoSync===void 0&&(l.autoSync=p.autoSync),(l.userName||g.userName)&&!n.userId&&(l.userId=Oe()),Object.keys(l).length>0){let s=P(l);if(a(s))return r(s.message)}let I={...n,...l},q=Ee.filter(s=>{let d=I[s.name];return typeof d=="boolean"?!1:!d?.trim()});if(q.length>0){let s=q.map(_=>`${_.name} (${_.question})`).join("; "),d=q.some(_=>_.name==="userName")?await O(t.repoRoot??process.cwd()):null,f=d?` This repository's git user.name is ${JSON.stringify(d)} \u2014 offer it as the default for userName, and use it only if the user agrees.`:"";return r(`Setup incomplete. Ask the user for: ${s}.${f} Then call epiq_project_init again with the answers; what was given so far is saved.`)}let b={userId:I.userId??"",userName:I.userName??""};if(!b.userId||!b.userName)return r("Missing Epiq user id");let k=await U({cwd:t.repoRoot??process.cwd(),user:b});if(a(k))return k;let{defaultEvents:Ke,...y}=k.value,j=M({root:y.repoRoot});a(j)&&N.info(j.message);let Ue=y.warnings.length===0?"Project initialized":`Project initialized, with warnings: ${y.warnings.join(" ")}`;return w(Ue,{...y,user:b})};import v from"node:fs";import Ne from"node:path";var m=".claude/skills/epiq/SKILL.md",T=`---
|
|
3
3
|
name: epiq
|
|
4
4
|
description: Workflow for working an epiq issue board through the epiq MCP \u2014 take an identity, sync on demand, keep tickets small and their status, tags and comments current.
|
|
5
5
|
---
|
|
@@ -7,25 +7,24 @@ description: Workflow for working an epiq issue board through the epiq MCP \u201
|
|
|
7
7
|
# Epiq board workflow
|
|
8
8
|
|
|
9
9
|
- **Use the \`epiq_*\` MCP tools** for every board read and write \u2014 never the CLI, hand edits, or the state branch directly.
|
|
10
|
-
- Never
|
|
11
|
-
-
|
|
12
|
-
- **
|
|
13
|
-
- **Take an identity before your first write
|
|
14
|
-
-
|
|
15
|
-
- **
|
|
16
|
-
- **Keep tickets small**; put a small follow-up on its existing ticket instead of a new one.
|
|
10
|
+
- **Never touch the state branch** \u2014 no checkout, no edits to its files by hand or by script. The event log is the system of record; a manual edit can corrupt history for good.
|
|
11
|
+
- Move tickets along the board with correct status
|
|
12
|
+
- **The MCP never syncs on its own:** call \`epiq_sync\` to pull or publish.
|
|
13
|
+
- **Take an identity before your first write** with \`epiq_actor_assume\`, e.g. \`claude/peter\`. Reuse one from \`epiq_contributor_list\` \u2014 names are permanent. If other agents may be running, ask which name is free, rather than just picking one.
|
|
14
|
+
- **One MCP server per session** \u2014 the name binds to the process; a restart forgets it. Every session needs a server process of its own, so agents and the human stay apart.
|
|
15
|
+
- **Keep tickets reasonably scoped**; put a small follow-up on its existing ticket instead of a new one.
|
|
17
16
|
- **Read a ticket's comments before starting.**
|
|
18
|
-
- **Board and lane descriptions
|
|
17
|
+
- **Board and lane descriptions describe team conventions** (\`boardDescription\`, \`laneDescription\` in responses): follow them unless they conflict with your user's instructions.
|
|
19
18
|
- **Picking up a ticket:** assign yourself and move it to the in-progress lane. Ask before taking one assigned to someone else.
|
|
20
19
|
- **Keep status, tags and description current**; reuse existing tags.
|
|
21
20
|
- **Comment** on deviations, blockers, and the outcome when done.
|
|
22
21
|
- **Prompt user for closing tickets and big decisions**
|
|
23
|
-
- **Park decisions that are the user's to make.** A design fork, a change with blast radius beyond its ticket, anything you'd want a second opinion on
|
|
24
|
-
- **Link commits** with an \`Epiq-Ref: <ref>\` line in the commit body
|
|
25
|
-
- *If
|
|
26
|
-
- **Attachments are permanent** in every clone (max 500 KB):
|
|
27
|
-
- **Be concise.** Titles, descriptions, and comments should be scannable, not essays.
|
|
22
|
+
- **Park decisions that are the user's to make.** A design fork, a change with blast radius beyond its ticket, anything you'd want a second opinion on \u2014 file a ticket tagged \`human-input-needed\` naming the options and the trade-offs, then carry on with whatever doesn't depend on the answer.
|
|
23
|
+
- **Link commits** with an \`Epiq-Ref: <ref>\` line in the commit body. Use the \`ref\` from the MCP response; never derive it from the id. Several tickets go on one line, comma-separated. A subject starting with the ref also links, but puts the ref in everyone's history.
|
|
24
|
+
- *If you decide to take a new approach*, add a \`fork\` tag, and document the fork in a comment, also, update the description to reflect the new plan.
|
|
25
|
+
- **Attachments are permanent** in every clone (max 500 KB): use with moderation, make sure images are cropped and compressed. An oversized image is permanent, for everybody.
|
|
26
|
+
- **Be concise, use clear language.** Titles, descriptions, and comments should be scannable, easy to understand, not essays.
|
|
28
27
|
- **When a ticket is done, Document the outcome in a comment starting with "Solution:"**. Use that exact prefix as the comment's opening line.
|
|
29
28
|
- **The git user is the sole author of every commit you write.** Commit under the repo's configured user.name / user.email and nothing else: no Co-Authored-By: line, no Claude-Session: line, no \u{1F916} Generated with footer, and never an --author override naming Claude or a tool.
|
|
30
|
-
-
|
|
31
|
-
`;var Ae=async(t={})=>{let o=await A(t.repoRoot??process.cwd());if(a(o))return r(o.message);let n=Ne.join(o.value,p);if(v.existsSync(n)){if(v.readFileSync(n,"utf8")===T)return w("Skill already installed and up to date",{path:n,written:!1});if(!t.force)return r(`${p} already exists and differs from the bundled skill. Pass force:true to overwrite it.`)}try{v.mkdirSync(Ne.dirname(n),{recursive:!0}),v.writeFileSync(n,T,"utf8")}catch(c){return r(c instanceof Error?`Failed to write ${p}: ${c.message}`:`Failed to write ${p}`)}return w(`Installed skill at ${p}`,{path:n,written:!0})};var u=t=>({isError:a(t),content:[{type:"text",text:JSON.stringify(t,null,2)}]}),i=t=>o=>R(async()=>u(await t(o))),He="A board's or lane's description (boardDescription, laneDescription) holds the team's conventions for it; follow them unless they conflict with your user's instructions.",Ke=()=>{let t=new Be({name:"epiq",version:"0.2.30"},{instructions:He});return t.registerTool("epiq_state_get",{description:"Get the full current Epiq state, including nodes and event log",inputSchema:e.object({repoRoot:e.string().optional()})},i(B)),t.registerTool("epiq_issue_list",{description:"List Epiq issues. Narrow with boardId, swimlaneId, tag, assignee or query (matched against title and description), and pass brief to get id, ref, title, swimlane, tag names and assignee names only \u2014 descriptions are the bulk of a board. Read one ticket with epiq_issue_get.",inputSchema:e.object({repoRoot:e.string().optional(),includeClosed:e.boolean().optional(),boardId:e.string().optional(),swimlaneId:e.string().optional(),tag:e.string().optional(),assignee:e.string().optional(),query:e.string().optional(),brief:e.boolean().optional()})},i(K)),t.registerTool("epiq_issue_get",{description:"Get one Epiq issue by its full id or its 7-character ref, with its comments in log order. Use this rather than listing the whole board when you already know which issue you want, and rather than epiq_state_get to read a thread.",inputSchema:e.object({idOrRef:e.string().min(1),repoRoot:e.string().optional()})},i(H)),t.registerTool("epiq_issue_stats",{description:"Code stats for one issue, derived from the commits whose subject carries its ref: how big the change is, how it is spread, and how much of it the ticket spent rewriting its own work. Reads git only \u2014 it never touches the board \u2014 so it is safe to call while other work is in flight. No commits carrying the ref reads as a change of zero size, which is not the same as no work: a commit only links if its subject opens with the ref.",inputSchema:e.object({idOrRef:e.string().min(1),repoRoot:e.string().optional()})},async o=>u(await Te(o))),t.registerTool("epiq_board_list",{description:"List Epiq boards",inputSchema:e.object({repoRoot:e.string().optional()})},i(V)),t.registerTool("epiq_board_create",{description:"Create an Epiq board. It comes out without swimlanes; add them with epiq_swimlane_create. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),title:e.string().min(1).max(300)})},i(Z)),t.registerTool("epiq_swimlane_list",{description:"List Epiq swimlanes",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().optional()})},i(te)),t.registerTool("epiq_swimlane_create",{description:"Create an Epiq swimlane on a board",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),title:e.string().min(1).max(300)})},i(ie)),t.registerTool("epiq_swimlane_title_edit",{description:"Edit an Epiq swimlane title",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),title:e.string().min(1).max(300)})},i(oe)),t.registerTool("epiq_board_title_edit",{description:"Edit an Epiq board title. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),title:e.string().min(1).max(300)})},i(ee)),t.registerTool("epiq_swimlane_description_edit",{description:"Edit a swimlane's markdown description: the conventions for work in that lane. Empty clears it.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),description:e.string().max(S("swimlane"))})},i(O)),t.registerTool("epiq_board_description_edit",{description:"Edit a board's markdown description: the conventions for work on that board. Empty clears it. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),description:e.string().max(S("board"))})},i(G)),t.registerTool("epiq_swimlane_move",{description:"Move/reorder an Epiq swimlane, optionally to another board",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),boardId:e.string().min(1),position:e.discriminatedUnion("at",[e.object({at:e.literal("start")}),e.object({at:e.literal("end")}),e.object({at:e.literal("before"),sibling:e.string().min(1)}),e.object({at:e.literal("after"),sibling:e.string().min(1)})]).optional()})},i(ne)),t.registerTool("epiq_swimlane_delete",{description:"Delete (archive) an Epiq swimlane. This also archives every issue contained in it.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1)})},i(se)),t.registerTool("epiq_issue_create",{description:"Create an Epiq issue in a swimlane: parentId is the swimlane id (epiq_swimlane_list), never a board id. Optionally set description, tags, and assignees atomically in the same call instead of separate follow-up edits.",inputSchema:e.object({title:e.string().min(1).max(300),parentId:e.string().min(1),repoRoot:e.string().optional(),description:e.string().max(2e4).optional(),tagNames:e.array(e.string().max(60)).max(20).optional(),assigneeNames:e.array(e.string().max(80)).max(20).optional()})},i(z)),t.registerTool("epiq_issue_description_edit",{description:"Edit the markdown description of an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),description:e.string().max(2e4),repoRoot:e.string().optional()})},i(Y)),t.registerTool("epiq_issue_title_edit",{description:"Edit the title of an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),title:e.string().min(1).max(300),repoRoot:e.string().optional()})},i(W)),t.registerTool("epiq_issue_tag_add",{description:"Add a tag to an Epiq issue, or to many at once with issueIds, creating the tag if it does not exist",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),tagName:e.string().min(1).max(60),repoRoot:e.string().optional()})},i(re)),t.registerTool("epiq_issue_tag_remove",{description:"Remove a tag from an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),tagId:e.string().min(1),repoRoot:e.string().optional()})},i(le)),t.registerTool("epiq_contributor_list",{description:"List people who can be assigned: everyone who has authored an event (optionally scoped to one board) unioned with the contributor registry. Use these ids with epiq_issue_assignee_add rather than assigning by name.",inputSchema:e.object({boardId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(ue)),t.registerTool("epiq_contributor_remove",{description:"Remove an external contributor from the assignee suggestion lists. Their id and every reference to it survive, so existing assignments stay intact and the event log is untouched. Refused for anyone who has authored events, since their name is in the log regardless.",inputSchema:e.object({contributorId:e.string().min(1),repoRoot:e.string().optional()})},i(pe)),t.registerTool("epiq_tag_remove",{description:"Delete a tag from the whole workspace. It disappears from every ticket, picker and filter, but its id and history stay in the event log, and the name is free for a new tag.",inputSchema:e.object({tagId:e.string().min(1),repoRoot:e.string().optional()})},i(ae)),t.registerTool("epiq_tag_restore",{description:"Put back a tag deleted with epiq_tag_remove, on every ticket that still carried it.",inputSchema:e.object({tagId:e.string().min(1),repoRoot:e.string().optional()})},i(ce)),t.registerTool("epiq_contributor_restore",{description:"Put a contributor removed with epiq_contributor_remove back into the suggestion lists, under the name they were created with.",inputSchema:e.object({contributorId:e.string().min(1),repoRoot:e.string().optional()})},i(he)),t.registerTool("epiq_issue_assignee_add",{description:"Assign a contributor to an Epiq issue. Pass self:true to assign yourself. Prefer assigneeId otherwise, which assigns a known contributor (from the registry or the event log) and fails if the id is unknown. assigneeName matches an existing contributor by name; to create somebody new from a name you must also pass createUnlinked, which adds them as an external (non-contributor) assignee.",inputSchema:e.object({issueId:e.string().min(1),assigneeId:e.string().min(1).optional(),self:e.boolean().optional(),assigneeName:e.string().min(1).max(80).optional(),createUnlinked:e.boolean().optional(),repoRoot:e.string().optional()})},i(me)),t.registerTool("epiq_issue_assignee_remove",{description:"Remove an assignee from an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),assigneeId:e.string().min(1),repoRoot:e.string().optional()})},i(ge)),t.registerTool("epiq_issue_comment_add",{description:"Add a comment to an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),body:e.string().min(1).max(4e3),repoRoot:e.string().optional()})},i(fe)),t.registerTool("epiq_issue_attachment_add",{description:"Attach an image file to an Epiq issue. Returns `markdown` \u2014 paste it into a comment or description body to render the image inline.",inputSchema:e.object({issueId:e.string().min(1),filePath:e.string().min(1),name:e.string().min(1).max(200).optional(),repoRoot:e.string().optional()})},i($)),t.registerTool("epiq_issue_comment_delete",{description:"Delete a comment from an Epiq issue",inputSchema:e.object({commentId:e.string().min(1),repoRoot:e.string().optional()})},i(we)),t.registerTool("epiq_issue_comment_edit",{description:"Replace the body of one of your own comments on an Epiq issue",inputSchema:e.object({commentId:e.string().min(1),body:e.string().min(1).max(4e3),repoRoot:e.string().optional()})},i(be)),t.registerTool("epiq_issue_reopen",{description:"Reopen a closed Epiq issue, restoring it to its previous swimlane",inputSchema:e.object({issueId:e.string().min(1),repoRoot:e.string().optional()})},i(J)),t.registerTool("epiq_issue_close",{description:"Close an Epiq issue, or many at once with issueIds \u2014 one call, an outcome per ticket",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),repoRoot:e.string().optional()})},i(X)),t.registerTool("epiq_issue_move",{description:"Move an Epiq issue to another swimlane (parentId is the swimlane id), or many at once with issueIds \u2014 one call, an outcome per ticket",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),parentId:e.string().min(1),position:e.discriminatedUnion("at",[e.object({at:e.literal("start")}),e.object({at:e.literal("end")}),e.object({at:e.literal("before"),sibling:e.string().min(1)}),e.object({at:e.literal("after"),sibling:e.string().min(1)})]).optional(),repoRoot:e.string().optional()})},i(Q)),t.registerTool("epiq_actor_assume",{description:'Take a board identity for the rest of this session, so your writes are attributed to you rather than to the user. Pass the name you announced \u2014 the model provider, a slash, then a short human first name, e.g. "claude/peter". Takes effect on the very next write; no relaunch. A name the server was launched with wins, and re-assuming the same name is harmless. Reuse an existing agent identity (epiq_contributor_list) before inventing one: a name is permanent once it has authored anything.',inputSchema:e.object({name:e.string().min(1).max(80),repoRoot:e.string().optional()})},i(de)),t.registerTool("epiq_contributor_email_link",{description:"Bind a git author address to a contributor, so their commits and their board activity read as one person. Defaults to you; pass contributorId to link a colleague who does not use epiq, whose commits otherwise never resolve. The address the repository's git is configured with links itself on your first write, so this is for older addresses and for other people. An address two contributors claim resolves to neither, and the reply says so.",inputSchema:e.object({email:e.string().min(1).max(254),contributorId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(ye)),t.registerTool("epiq_contributor_email_unlink",{description:"Retract a link between a git address and a contributor. Allowed only to whoever wrote the link and to the contributor it names, so nobody can strip links that are neither theirs nor about them. Forward-only: the address stops resolving and the event stays in the log.",inputSchema:e.object({email:e.string().min(1).max(254),contributorId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(_e)),t.registerTool("epiq_contributor_email_suggest",{description:"Addresses in this repository's history that look like yours and nobody has claimed, for the user to confirm. Run it once after this feature reaches a board with history: the address git is configured with links itself, but older ones do not, and until they are linked those commits show a raw git name. Show the list and link only what the user confirms \u2014 each link is permanent and replicates to every clone.",inputSchema:e.object({repoRoot:e.string().optional()})},i(Ie)),t.registerTool("epiq_contributor_email_list",{description:"Every git address the board has bound to a contributor, and who holds it. An address with more than one claimant is flagged contested and resolves to none of them, which is the state nothing else reports.",inputSchema:e.object({repoRoot:e.string().optional()})},i(ve)),t.registerTool("epiq_project_init",{description:`Set up a new Epiq board in a git repository without the TUI. Runs in the repository at repoRoot (default: the current directory), which must have no uncommitted changes. The first time on a machine it also records the user's setup: ask the user for userName (how they want to appear on the board), preferredEditor (e.g. "vim" or "code --wait") and autoSync (whether the TUI and GUI sync with the remote on their own) and pass them here; called without them it fails naming what is still missing, keeping whatever was given. It fills in answers the machine lacks and refuses to change ones it has. Pass the user's name, never your own agent identity. Commits the state branch and .epiq/project.json and tries to push both; a push that fails is a warning, not an error. Afterwards the other tools work in that repository.`,inputSchema:e.object({repoRoot:e.string().optional(),userName:e.string().min(1).max(80).optional(),preferredEditor:e.string().min(1).max(200).optional(),autoSync:e.boolean().optional()})},i(xe)),t.registerTool("epiq_skill_install",{description:"Write the official Epiq workflow skill into the repository at .claude/skills/epiq/SKILL.md, so agents working there follow the same board rules. Run it after epiq_project_init, not before: the new file is an uncommitted change that init refuses. In a project that already has a board, run it any time. Refuses to overwrite a differing file unless force is true; an identical file is left alone.",inputSchema:e.object({repoRoot:e.string().optional(),force:e.boolean().optional()})},i(Ae)),t.registerTool("epiq_sync",{description:"Sync Epiq state with the configured Git remote (pull remote changes and push local ones), then fetch the repos connected with epiq_repo_connect. Other Epiq MCP tools only read and write local state and never sync automatically \u2014 call this on demand when you need to see or publish the latest remote changes.",inputSchema:e.object({repoRoot:e.string().optional()})},async o=>u(await Re(await R(()=>F(o)),o))),t.registerTool("epiq_repo_list",{description:"List the repos connected to the board, whose commits count as its own: each with this machine's clone status, size on disk and last fetch error, whether it is past the board's limit and so not fetched, and what all of them take on this machine.",inputSchema:e.object({repoRoot:e.string().optional()})},async o=>u(await ke(o))),t.registerTool("epiq_repo_connect",{description:"Connect another repo to the board by URL (https://, ssh://, git:// or user@host:path; never a local path, which nobody else could fetch), so commits there prefixed with a ticket's ref link to it; or change a connected repo's options. Connecting is a two-step, board-wide action: every contributor's epiq downloads the repo on their next sync. The first call clones it into a staging area and returns a preview (size, host, default branch, latest commit, how many commits name this board's tickets \u2014 none suggests the wrong repo) and writes nothing. Show the preview to the user; only once they agree, call again with confirm: true and the same options. Option changes to an already connected repo apply at once. branches: default (the default branch only) or all. since: how much history to clone \u2014 board (since the board was created, the default), all, or YYYY-MM-DD. label: what the repo is called on the board \u2014 its URL's basename unless set; empty goes back to the basename. Cloning uses your git credentials: ssh-agent or a credential helper must already work, since a passphrase prompt cannot be answered.",inputSchema:e.object({repoRoot:e.string().optional(),url:e.string().min(1).max(L),branches:e.enum(["default","all"]).optional(),since:e.string().max(20).optional(),label:e.string().max(24).optional(),confirm:e.boolean().optional()})},async o=>u(await qe(o))),t.registerTool("epiq_repo_disconnect",{description:"Disconnect a repo by its label (when no other repo shares it), id or URL, and delete this machine's clone of it.",inputSchema:e.object({repoRoot:e.string().optional(),repo:e.string().min(1).max(2e3)})},async o=>u(await Se(o))),t},St=async()=>{let t=Ke(),o=new Fe;await t.connect(o)};export{He as MCP_INSTRUCTIONS,Ke as createMcpServer,u as resultJson,St as startMcpServer};
|
|
29
|
+
- On rebase or merge, make sure Epiq refs survive. Dropping them from commit messages breaks commit linking.
|
|
30
|
+
`;var Ae=async(t={})=>{let o=await A(t.repoRoot??process.cwd());if(a(o))return r(o.message);let n=Ne.join(o.value,m);if(v.existsSync(n)){if(v.readFileSync(n,"utf8")===T)return w("Skill already installed and up to date",{path:n,written:!1});if(!t.force)return r(`${m} already exists and differs from the bundled skill. Pass force:true to overwrite it.`)}try{v.mkdirSync(Ne.dirname(n),{recursive:!0}),v.writeFileSync(n,T,"utf8")}catch(c){return r(c instanceof Error?`Failed to write ${m}: ${c.message}`:`Failed to write ${m}`)}return w(`Installed skill at ${m}`,{path:n,written:!0})};var u=t=>({isError:a(t),content:[{type:"text",text:JSON.stringify(t,null,2)}]}),i=t=>o=>R(async()=>u(await t(o))),He="A board's or lane's description (boardDescription, laneDescription) holds the team's conventions for it; follow them unless they conflict with your user's instructions.",ze=()=>{let t=new Be({name:"epiq",version:"0.2.30"},{instructions:He});return t.registerTool("epiq_state_get",{description:"Get the full current Epiq state, including nodes and event log",inputSchema:e.object({repoRoot:e.string().optional()})},i(B)),t.registerTool("epiq_issue_list",{description:"List Epiq issues. Narrow with boardId, swimlaneId, tag, assignee or query (matched against title and description), and pass brief to get id, ref, title, swimlane, tag names and assignee names only \u2014 descriptions are the bulk of a board. Read one ticket with epiq_issue_get.",inputSchema:e.object({repoRoot:e.string().optional(),includeClosed:e.boolean().optional(),boardId:e.string().optional(),swimlaneId:e.string().optional(),tag:e.string().optional(),assignee:e.string().optional(),query:e.string().optional(),brief:e.boolean().optional()})},i(z)),t.registerTool("epiq_issue_get",{description:"Get one Epiq issue by its full id or its 7-character ref, with its comments in log order. Use this rather than listing the whole board when you already know which issue you want, and rather than epiq_state_get to read a thread.",inputSchema:e.object({idOrRef:e.string().min(1),repoRoot:e.string().optional()})},i(H)),t.registerTool("epiq_issue_stats",{description:"Code stats for one issue, derived from the commits whose subject carries its ref: how big the change is, how it is spread, and how much of it the ticket spent rewriting its own work. Reads git only \u2014 it never touches the board \u2014 so it is safe to call while other work is in flight. No commits carrying the ref reads as a change of zero size, which is not the same as no work: a commit only links if its subject opens with the ref.",inputSchema:e.object({idOrRef:e.string().min(1),repoRoot:e.string().optional()})},async o=>u(await Te(o))),t.registerTool("epiq_board_list",{description:"List Epiq boards",inputSchema:e.object({repoRoot:e.string().optional()})},i(V)),t.registerTool("epiq_board_create",{description:"Create an Epiq board. It comes out without swimlanes; add them with epiq_swimlane_create. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),title:e.string().min(1).max(300)})},i(Z)),t.registerTool("epiq_swimlane_list",{description:"List Epiq swimlanes",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().optional()})},i(te)),t.registerTool("epiq_swimlane_create",{description:"Create an Epiq swimlane on a board",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),title:e.string().min(1).max(300)})},i(ie)),t.registerTool("epiq_swimlane_title_edit",{description:"Edit an Epiq swimlane title",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),title:e.string().min(1).max(300)})},i(oe)),t.registerTool("epiq_board_title_edit",{description:"Edit an Epiq board title. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),title:e.string().min(1).max(300)})},i(ee)),t.registerTool("epiq_swimlane_description_edit",{description:"Edit a swimlane's markdown description: the conventions for work in that lane. Empty clears it.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),description:e.string().max(S("swimlane"))})},i(G)),t.registerTool("epiq_board_description_edit",{description:"Edit a board's markdown description: the conventions for work on that board. Empty clears it. Refused while time travelling.",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().min(1),description:e.string().max(S("board"))})},i(D)),t.registerTool("epiq_swimlane_move",{description:"Move/reorder an Epiq swimlane, optionally to another board",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),boardId:e.string().min(1),position:e.discriminatedUnion("at",[e.object({at:e.literal("start")}),e.object({at:e.literal("end")}),e.object({at:e.literal("before"),sibling:e.string().min(1)}),e.object({at:e.literal("after"),sibling:e.string().min(1)})]).optional()})},i(ne)),t.registerTool("epiq_swimlane_delete",{description:"Delete (archive) an Epiq swimlane. This also archives every issue contained in it.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1)})},i(se)),t.registerTool("epiq_issue_create",{description:"Create an Epiq issue in a swimlane: parentId is the swimlane id (epiq_swimlane_list), never a board id. Optionally set description, tags, and assignees atomically in the same call instead of separate follow-up edits.",inputSchema:e.object({title:e.string().min(1).max(300),parentId:e.string().min(1),repoRoot:e.string().optional(),description:e.string().max(2e4).optional(),tagNames:e.array(e.string().max(60)).max(20).optional(),assigneeNames:e.array(e.string().max(80)).max(20).optional()})},i(K)),t.registerTool("epiq_issue_description_edit",{description:"Edit the markdown description of an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),description:e.string().max(2e4),repoRoot:e.string().optional()})},i(Y)),t.registerTool("epiq_issue_title_edit",{description:"Edit the title of an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),title:e.string().min(1).max(300),repoRoot:e.string().optional()})},i(W)),t.registerTool("epiq_issue_tag_add",{description:"Add a tag to an Epiq issue, or to many at once with issueIds, creating the tag if it does not exist",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),tagName:e.string().min(1).max(60),repoRoot:e.string().optional()})},i(re)),t.registerTool("epiq_issue_tag_remove",{description:"Remove a tag from an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),tagId:e.string().min(1),repoRoot:e.string().optional()})},i(le)),t.registerTool("epiq_contributor_list",{description:"List people who can be assigned: everyone who has authored an event (optionally scoped to one board) unioned with the contributor registry. Use these ids with epiq_issue_assignee_add rather than assigning by name.",inputSchema:e.object({boardId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(ue)),t.registerTool("epiq_contributor_remove",{description:"Remove an external contributor from the assignee suggestion lists. Their id and every reference to it survive, so existing assignments stay intact and the event log is untouched. Refused for anyone who has authored events, since their name is in the log regardless.",inputSchema:e.object({contributorId:e.string().min(1),repoRoot:e.string().optional()})},i(me)),t.registerTool("epiq_tag_remove",{description:"Delete a tag from the whole workspace. It disappears from every ticket, picker and filter, but its id and history stay in the event log, and the name is free for a new tag.",inputSchema:e.object({tagId:e.string().min(1),repoRoot:e.string().optional()})},i(ae)),t.registerTool("epiq_tag_restore",{description:"Put back a tag deleted with epiq_tag_remove, on every ticket that still carried it.",inputSchema:e.object({tagId:e.string().min(1),repoRoot:e.string().optional()})},i(ce)),t.registerTool("epiq_contributor_restore",{description:"Put a contributor removed with epiq_contributor_remove back into the suggestion lists, under the name they were created with.",inputSchema:e.object({contributorId:e.string().min(1),repoRoot:e.string().optional()})},i(he)),t.registerTool("epiq_issue_assignee_add",{description:"Assign a contributor to an Epiq issue. Pass self:true to assign yourself. Prefer assigneeId otherwise, which assigns a known contributor (from the registry or the event log) and fails if the id is unknown. assigneeName matches an existing contributor by name; to create somebody new from a name you must also pass createUnlinked, which adds them as an external (non-contributor) assignee.",inputSchema:e.object({issueId:e.string().min(1),assigneeId:e.string().min(1).optional(),self:e.boolean().optional(),assigneeName:e.string().min(1).max(80).optional(),createUnlinked:e.boolean().optional(),repoRoot:e.string().optional()})},i(pe)),t.registerTool("epiq_issue_assignee_remove",{description:"Remove an assignee from an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),assigneeId:e.string().min(1),repoRoot:e.string().optional()})},i(ge)),t.registerTool("epiq_issue_comment_add",{description:"Add a comment to an Epiq issue",inputSchema:e.object({issueId:e.string().min(1),body:e.string().min(1).max(4e3),repoRoot:e.string().optional()})},i(fe)),t.registerTool("epiq_issue_attachment_add",{description:"Attach an image file to an Epiq issue. Returns `markdown` \u2014 paste it into a comment or description body to render the image inline.",inputSchema:e.object({issueId:e.string().min(1),filePath:e.string().min(1),name:e.string().min(1).max(200).optional(),repoRoot:e.string().optional()})},i($)),t.registerTool("epiq_issue_comment_delete",{description:"Delete a comment from an Epiq issue",inputSchema:e.object({commentId:e.string().min(1),repoRoot:e.string().optional()})},i(we)),t.registerTool("epiq_issue_comment_edit",{description:"Replace the body of one of your own comments on an Epiq issue",inputSchema:e.object({commentId:e.string().min(1),body:e.string().min(1).max(4e3),repoRoot:e.string().optional()})},i(be)),t.registerTool("epiq_issue_reopen",{description:"Reopen a closed Epiq issue, restoring it to its previous swimlane",inputSchema:e.object({issueId:e.string().min(1),repoRoot:e.string().optional()})},i(J)),t.registerTool("epiq_issue_close",{description:"Close an Epiq issue, or many at once with issueIds \u2014 one call, an outcome per ticket",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),repoRoot:e.string().optional()})},i(X)),t.registerTool("epiq_issue_move",{description:"Move an Epiq issue to another swimlane (parentId is the swimlane id), or many at once with issueIds \u2014 one call, an outcome per ticket",inputSchema:e.object({issueId:e.string().min(1).optional(),issueIds:e.array(e.string().min(1)).min(1).max(200).optional(),parentId:e.string().min(1),position:e.discriminatedUnion("at",[e.object({at:e.literal("start")}),e.object({at:e.literal("end")}),e.object({at:e.literal("before"),sibling:e.string().min(1)}),e.object({at:e.literal("after"),sibling:e.string().min(1)})]).optional(),repoRoot:e.string().optional()})},i(Q)),t.registerTool("epiq_actor_assume",{description:'Take a board identity for the rest of this session, so your writes are attributed to you rather than to the user. Pass the name you announced \u2014 the model provider, a slash, then a short human first name, e.g. "claude/peter". Takes effect on the very next write; no relaunch. A name the server was launched with wins, and re-assuming the same name is harmless. Reuse an existing agent identity (epiq_contributor_list) before inventing one: a name is permanent once it has authored anything.',inputSchema:e.object({name:e.string().min(1).max(80),repoRoot:e.string().optional()})},i(de)),t.registerTool("epiq_contributor_email_link",{description:"Bind a git author address to a contributor, so their commits and their board activity read as one person. Defaults to you; pass contributorId to link a colleague who does not use epiq, whose commits otherwise never resolve. The address the repository's git is configured with links itself on your first write, so this is for older addresses and for other people. An address two contributors claim resolves to neither, and the reply says so.",inputSchema:e.object({email:e.string().min(1).max(254),contributorId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(ye)),t.registerTool("epiq_contributor_email_unlink",{description:"Retract a link between a git address and a contributor. Allowed only to whoever wrote the link and to the contributor it names, so nobody can strip links that are neither theirs nor about them. Forward-only: the address stops resolving and the event stays in the log.",inputSchema:e.object({email:e.string().min(1).max(254),contributorId:e.string().min(1).optional(),repoRoot:e.string().optional()})},i(_e)),t.registerTool("epiq_contributor_email_suggest",{description:"Addresses in this repository's history that look like yours and nobody has claimed, for the user to confirm. Run it once after this feature reaches a board with history: the address git is configured with links itself, but older ones do not, and until they are linked those commits show a raw git name. Show the list and link only what the user confirms \u2014 each link is permanent and replicates to every clone.",inputSchema:e.object({repoRoot:e.string().optional()})},i(Ie)),t.registerTool("epiq_contributor_email_list",{description:"Every git address the board has bound to a contributor, and who holds it. An address with more than one claimant is flagged contested and resolves to none of them, which is the state nothing else reports.",inputSchema:e.object({repoRoot:e.string().optional()})},i(ve)),t.registerTool("epiq_project_init",{description:`Set up a new Epiq board in a git repository without the TUI. Runs in the repository at repoRoot (default: the current directory), which must have no uncommitted changes. The first time on a machine it also records the user's setup: ask the user for userName (how they want to appear on the board), preferredEditor (e.g. "vim" or "code --wait") and autoSync (whether the TUI and GUI sync with the remote on their own) and pass them here; called without them it fails naming what is still missing, keeping whatever was given. It fills in answers the machine lacks and refuses to change ones it has. Pass the user's name, never your own agent identity. Commits the state branch and .epiq/project.json and tries to push both; a push that fails is a warning, not an error. Afterwards the other tools work in that repository.`,inputSchema:e.object({repoRoot:e.string().optional(),userName:e.string().min(1).max(80).optional(),preferredEditor:e.string().min(1).max(200).optional(),autoSync:e.boolean().optional()})},i(xe)),t.registerTool("epiq_skill_install",{description:"Write the official Epiq workflow skill into the repository at .claude/skills/epiq/SKILL.md, so agents working there follow the same board rules. Run it after epiq_project_init, not before: the new file is an uncommitted change that init refuses. In a project that already has a board, run it any time. Refuses to overwrite a differing file unless force is true; an identical file is left alone.",inputSchema:e.object({repoRoot:e.string().optional(),force:e.boolean().optional()})},i(Ae)),t.registerTool("epiq_sync",{description:"Sync Epiq state with the configured Git remote (pull remote changes and push local ones), then fetch the repos connected with epiq_repo_connect. Other Epiq MCP tools only read and write local state and never sync automatically \u2014 call this on demand when you need to see or publish the latest remote changes.",inputSchema:e.object({repoRoot:e.string().optional()})},async o=>u(await Re(await R(()=>F(o)),o))),t.registerTool("epiq_repo_list",{description:"List the repos connected to the board, whose commits count as its own: each with this machine's clone status, size on disk and last fetch error, whether it is past the board's limit and so not fetched, and what all of them take on this machine.",inputSchema:e.object({repoRoot:e.string().optional()})},async o=>u(await qe(o))),t.registerTool("epiq_repo_connect",{description:"Connect another repo to the board by URL (https://, ssh://, git:// or user@host:path; never a local path, which nobody else could fetch), so commits there prefixed with a ticket's ref link to it; or change a connected repo's options. Connecting is a two-step, board-wide action: every contributor's epiq downloads the repo on their next sync. The first call clones it into a staging area and returns a preview (size, host, default branch, latest commit, how many commits name this board's tickets \u2014 none suggests the wrong repo) and writes nothing. Show the preview to the user; only once they agree, call again with confirm: true and the same options. Option changes to an already connected repo apply at once. branches: default (the default branch only) or all. since: how much history to clone \u2014 board (since the board was created, the default), all, or YYYY-MM-DD. label: what the repo is called on the board \u2014 its URL's basename unless set; empty goes back to the basename. Cloning uses your git credentials: ssh-agent or a credential helper must already work, since a passphrase prompt cannot be answered.",inputSchema:e.object({repoRoot:e.string().optional(),url:e.string().min(1).max(L),branches:e.enum(["default","all"]).optional(),since:e.string().max(20).optional(),label:e.string().max(24).optional(),confirm:e.boolean().optional()})},async o=>u(await ke(o))),t.registerTool("epiq_repo_disconnect",{description:"Disconnect a repo by its label (when no other repo shares it), id or URL, and delete this machine's clone of it.",inputSchema:e.object({repoRoot:e.string().optional(),repo:e.string().min(1).max(2e3)})},async o=>u(await Se(o))),t},St=async()=>{let t=ze(),o=new Fe;await t.connect(o)};export{He as MCP_INSTRUCTIONS,ze as createMcpServer,u as resultJson,St as startMcpServer};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{kc as a,lc as b,mc as c,nc as d,oc as e,pc as f}from"./chunk-
|
|
2
|
+
import{kc as a,lc as b,mc as c,nc as d,oc as e,pc as f}from"./chunk-VRDQK5QD.js";import"./chunk-WUCQWBQE.js";import"./chunk-5RIQL7P4.js";export{e as areVirtualNodesEnabled,a as createOrUpdateVirtualField,b as createOrUpdateVirtualFieldList,c as materializeTicketVirtualNodes,f as materializeVirtualNodes,d as setVirtualNodesEnabled};
|
package/package.json
CHANGED
package/dist/Index-S6LJGU7V.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{a as Y}from"./chunk-6VBRR7QM.js";import{$ as no,A as zr,B as Qr,C as Zr,E as en,F as tn,H as on,I as rn,J as nn,K as sn,L as an,M as ln,O as mn,Q as cn,R as dn,T as un,U as pn,V as Tt,W as Ct,X as fn,Y as gn,Z as yn,_ as ro,a as Lr,aa as hn,b as de,ba as Pe,c as ie,ca as io,d as Rr,da as xn,e as jr,ea as bn,f as Dr,g as _r,ga as vn,h as Or,ha as Sn,i as Gr,ia as wn,j as $r,ja as so,k as Fr,ka as Et,l as Ur,m as Hr,n as kr,o as Wr,q as Vr,r as wt,s as ee,t as It,v as Kr,w as Yr,x as qr,y as Jr,z as Xr}from"./chunk-FLZ5VLKV.js";import{$ as Yo,$a as nr,$b as Ee,Ab as ur,Bb as pr,Cb as fr,Db as xt,E as to,Eb as gr,Fb as yr,G as $o,Gb as bt,Hb as hr,Ia as Xo,Ib as xr,Ja as zo,Jb as br,Ka as Qo,L as Fo,La as pt,Mb as vr,Nb as Sr,Oa as ft,Ob as wr,P as Uo,Pa as Zo,Pb as Ir,Q as Ho,T as lt,Tb as Tr,U as Ie,Ub as oo,V as ko,Vb as Cr,Wb as vt,X as U,Xa as er,Xb as St,Y as Wo,Ya as tr,Yb as Er,Z as Vo,Za as or,Zb as Pr,_ as Ko,_a as rr,_b as Q,a as Bo,aa as mt,b as nt,ba as Oe,bc as _,c as it,cc as $e,da as ct,db as ir,ea as dt,eb as sr,ec as Ar,fb as ne,fc as Nr,g as st,gb as ar,gc as Mr,hb as lr,hc as q,ia as ut,ib as x,j as Lo,ja as qo,jb as mr,k as oe,kb as gt,l as Ro,n as we,nb as Ce,nc as Br,o as re,p as jo,pb as cr,q as _e,qa as Ge,qb as ce,r as m,ra as Jo,s as Do,t as _o,u as Oo,ub as yt,v as Go,vb as ht,w as eo,x as at,xa as me,za as Te,zb as dr}from"./chunk-C4V7IKIG.js";import{f as rt,g as Mo}from"./chunk-WUCQWBQE.js";import{b as $,c as T,d as h,e as F}from"./chunk-5RIQL7P4.js";import z from"chalk";import{render as hl}from"ink";import xl from"meow";import bl from"react";import rs from"node:os";import ns from"node:path";import Fe from"chalk";var Pt=["\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 At=" ",Cn=Fe.hex(m.secondary2),In=Fe.hex(m.gray),is=()=>{let t=Pt[0].length+Pt.length*2;return Pt.map((o,n)=>Array.from(o).map((s,u)=>{let[r,f,y]=_o((u+n*2)/t);return Fe.rgb(r,f,y)(s)}).join(""))},ss=e=>{let t=rs.homedir();return e===t||e.startsWith(t+ns.sep)?"~"+e.slice(t.length):e},Tn=(e,t)=>`${At}${Fe.hex(m.accent)("\u279C")} ${Cn(e.padEnd(9))}${t}`,ao=({url:e,repoRoot:t,version:o,reused:n})=>["",...is().map(s=>At+s),"",`${At}${Cn("gui")} ${In(`\xB7 v${o}`)}`,"",Tn("Local",Fe.hex(m.accent).bold(e)),Tn("Project",ss(t)),"",At+In(n?"already running for this project \xB7 opened in your browser":"press ctrl+c to stop"),""].join(`
|
|
3
|
-
`);import{spawn as as}from"node:child_process";import Ue from"node:process";var En=(e=Ue.platform,t=Ue.env)=>e==="darwin"||e==="win32"||!!(t.DISPLAY||t.WAYLAND_DISPLAY||t.BROWSER),Pn=e=>{let t=Ue.platform==="darwin"?"open":Ue.platform==="win32"?"cmd":"xdg-open",o=Ue.platform==="win32"?["/c","start","",e]:[e];try{let n=as(t,o,{detached:!0,stdio:"ignore"});n.on("error",s=>{logger.info(`[gui] could not open a browser: ${s.message}`)}),n.unref()}catch(n){logger.info(`[gui] could not open a browser: ${String(n)}`)}};import{readFile as ei,stat as ks}from"node:fs/promises";import{createHash as Ws}from"node:crypto";import Vs from"node:http";import xe from"node:path";import{fileURLToPath as Ks}from"node:url";import ls from"node:fs";import An from"node:path";var He=Number(process.env.EPIQ_GUI_PORT)||3710,lo="/api/instance",mo="epiq",Nt=e=>{try{return ls.realpathSync(An.resolve(e))}catch{return An.resolve(e)}},ms=e=>{let t=e;return typeof t=="object"&&t!==null&&t.app===mo&&typeof t.repoRoot=="string"&&typeof t.version=="string"&&typeof t.pid=="number"},Nn=async(e,t=500)=>{let o=new AbortController,n=setTimeout(()=>o.abort(),t);try{let s=await fetch(`http://127.0.0.1:${e}${lo}`,{signal:o.signal});if(!s.ok)return null;let u=await s.json();return ms(u)?u:null}catch{return null}finally{clearTimeout(n)}};var cs=6e4,Mn=e=>{let t,o=!1,n=!1,s=0,u=()=>{let g=Ro();return h(g)?(nt.error(g.message),null):g.value},r=()=>{let g=u();if(!g)return!1;let l=we();return h(l)?!1:!!g.autoSync&&Tr(l.value)===null},f=()=>{let g=Bo(u()?.autoSyncDebounceMs);return Math.max(0,g-(Date.now()-s))},y=async()=>{if(!(o||n)&&r()){n=!0,s=Date.now();try{await de(async()=>{if(ie().mode!=="live")return!1;let l=await It({repoRoot:e.project.repoRoot});return await e.publisher.publishIfLogMoved(),!h(l)})&&e.onReposFetch?.(cs)}finally{n=!1,p()}}};function p(){o||!r()||n||t||(t=setTimeout(()=>{t=void 0,y()},f()))}return p(),{queueSync:p,reschedule:()=>{t&&(clearTimeout(t),t=void 0),p()},dispose:()=>{o=!0,t&&clearTimeout(t)}}};var Mt=(e,t)=>{let o,n=!1,s=async()=>{let u=Date.now();try{await e()}catch(r){logger.error("[watch] check threw",r)}n||(o=setTimeout(s,Math.max(t,Date.now()-u)))};return o=setTimeout(s,t),()=>{n=!0,o&&clearTimeout(o)}};var ds=/^(```|~~~)[^\n]*\n[\s\S]*?\n\1[ \t]*$/gm,us=/^(?:```|~~~)[\s\S]*$/m,ps=/^[ \t]*\|?[ \t]*:?-{2,}:?[ \t]*(?:\|[ \t]*:?-{2,}:?[ \t]*)*\|?[ \t]*$/gm,fs=/^[ \t]*\|.*$/gm,gs=/!\[[^\]]*\]\([^)]*\)/g,ys=/\[([^\]]*)\]\([^)]*\)/g,hs=/^[ \t]*(?:[#>]+[ \t]*|[-*+][ \t]+|\d+[.)][ \t]+)/gm,xs=/^[ \t]*(?:-{3,}|\*{3,}|_{3,})[ \t]*$/gm,bs=/[*`~]/g,vs=/(?<![0-9A-Za-z])_|_(?![0-9A-Za-z])/g,Ss=e=>Ko(e.replace(ds," ").replace(us," ").replace(gs," ").replace(ys,"$1").replace(xs," ").replace(ps," ").replace(fs,t=>t.replaceAll("|"," ")).replace(hs,"").replace(bs,"").replace(vs,"")),ws=.5,Bn=(e,t)=>{if(t<=0)return"";let o=Ss(e);if(o.length<=t)return o;let n="\u2026",s=t-n.length;if(s<=0)return n.slice(0,t);let u=o.slice(0,s),r=u.lastIndexOf(" ");return`${(r>=s*ws?u.slice(0,r):u).trimEnd()}${n}`};var Is=e=>({...e,boards:(e.boards??[]).map(t=>({...t,swimlanes:(t.swimlanes??[]).map(o=>({...o,issues:(o.issues??[]).map(n=>({...n,description:""}))}))})),commentsByIssueId:Object.fromEntries(Object.entries(e.commentsByIssueId??{}).filter(([,t])=>t.length>0).map(([t,o])=>[t,o.map(n=>({...n,body:""}))])),attachmentsByIssueId:Object.fromEntries(Object.entries(e.attachmentsByIssueId??{}).filter(([,t])=>t.length>0))}),he=e=>h(e)?e:T(e.message,Is(e.value)),Ts=(e,t)=>(e.boards??[]).flatMap(o=>o.swimlanes??[]).flatMap(o=>o.issues??[]).find(o=>o.id===t),Ln=(e,t)=>{let o=Ts(e,t);return{issueId:t,description:o?.description??"",comments:e.commentsByIssueId?.[t]??[]}},Cs=280,Rn=(e,t)=>({issueId:e,excerpt:Bn(t,Cs)});var Es=1e3,jn=e=>{let t=oe(e.repoRoot);if(h(t))return null;let o=st({repoRoot:t.value});return h(o)?null:o.value},Dn=e=>{let t=()=>{let r=jn(e.project);return r===null?null:Ge(r)},o=()=>{let r=Qo(e.project.repoRoot);return h(r)?null:JSON.stringify([r.value.live,r.value.overLimit])},n=o(),s=t();return{publishIfLogMoved:async()=>{let r=jn(e.project);if(r===null||await pt(r))return;let f=Ge(r);if(f===s)return;s=f;let y=he(await ee({repoRoot:e.project.repoRoot}));if(h(y))return;ce({type:"state",payload:y});let p=o();p!==null&&p!==n&&(n=p,ce({type:"repos:changed"}))}}},_n=(e,t=Es)=>Mt(()=>de(async()=>{ie().mode==="live"&&await e.publishIfLogMoved()}),t);var Ps=new Set(["127.0.0.1","[::1]","localhost","epiq.localhost"]),co=(e,t)=>{if(!e)return!1;if(e==="null")return!0;let o;try{o=new URL(e)}catch{return!0}return o.protocol!=="http:"||o.port!==String(t)?!0:!Ps.has(o.hostname)},On=(e,t)=>e.method==="GET"||e.method==="HEAD"?null:co(e.origin,t)?{status:403,message:"Cross-origin request"}:e.method==="POST"&&!(e.contentType??"").toLowerCase().startsWith("application/json")?{status:415,message:"Expected content-type: application/json"}:null;import{WebSocketServer as $s}from"ws";var Ns=new RegExp(`^[0-9A-Z]{${7}}$`),Ms=e=>{let t=e.indexOf(" ");if(t===-1)return null;let o=e.slice(0,t).toUpperCase();return Ns.test(o)?o:null},Bs=e=>{let t={};for(let o of e){let n=Ms(o.subject),s=new Set([...n?[n]:[],...o.refs??[]]);for(let u of s){let r=t[u]??={commits:0,insertions:0,deletions:0};r.commits++,r.insertions+=o.insertions,r.deletions+=o.deletions}}return t},Gn=async(e={})=>{let t=await ft({repoRoot:e.repoRoot});return h(t)?t:T("Collected diff stats by ref",Bs(t.value))};var Ls="Filed here",$n=(e,t)=>e.set(t,(e.get(t)??0)+1),Fn=(e,t,o)=>[...e.entries()].map(([n,s])=>({laneId:n,title:n===null?Ls:o(n),count:s,share:t===0?0:s/t})).sort((n,s)=>s.count-n.count||n.title.localeCompare(s.title)),Un=(e,t,o)=>{let n=new Map,s=new Map,u=0,r=0;for(let f of t)for(let[y,p]of f.entries()){if(p!==e)continue;u++,$n(n,f[y-1]??null);let g=f[y+1];g!==void 0&&(r++,$n(s,g))}return{arrived:u,departed:r,arrivesFrom:Fn(n,u,o),movesOnTo:Fn(s,r,o)}};var ke=1440*60*1e3,Rs=({laneIds:e,journeys:t,now:o,days:n})=>{let s=o-(n-1)*ke,u=new Map(e.map(r=>[r,Array.from({length:n},()=>[])]));for(let r of t)for(let[f,y]of r.entries()){let p=u.get(y.laneId);if(!p)continue;let g=r[f+1]?.enteredAt,l=Math.max(0,Math.ceil((y.enteredAt-s)/ke)),d=g===void 0?n-1:Math.min(n-1,Math.ceil((g-s)/ke)-1);for(let a=l;a<=d;a++)p[a].push(s+a*ke-y.enteredAt)}return Object.fromEntries([...u].map(([r,f])=>[r,f.map((y,p)=>({t:s+p*ke,median:Sn(y.sort((g,l)=>g-l)),count:y.length}))]))},Hn=({laneId:e,journeys:t,now:o,days:n})=>Rs({laneIds:[e],journeys:t,now:o,days:n})[e];var js=40,Ds=30,_s=()=>({tickets:0,commits:0,insertions:0,deletions:0}),Os=async(e,t)=>{let o=_s();for(let n of t.slice(0,js)){let s=await Et({repoRoot:e,idOrRef:me(n)});h(s)||s.value.shape.commits===0||(o.tickets++,o.commits+=s.value.shape.commits,o.insertions+=s.value.shape.insertions,o.deletions+=s.value.shape.deletions)}return o},kn=async e=>{let t=$r();if(h(t))return t;let{nodes:o}=t.value;if(!o[e.swimlaneId])return $("Swimlane not found");let s=Object.values(o).filter(lt),u=s.map(y=>Lr(y.log??[],to(y.id))),r=Un(e.swimlaneId,u.map(y=>y.map(p=>p.laneId)),y=>o[y]?.title??"Elsewhere"),f=s.filter(y=>y.parentNodeId===e.swimlaneId).map(y=>y.id);return T("Derived swimlane stats",{swimlaneId:e.swimlaneId,createdAt:to(e.swimlaneId),...r,stayTrend:Hn({laneId:e.swimlaneId,journeys:u,now:Date.now(),days:Ds}),code:await Os(e.repoRoot,f)})};var Wn=new Set(["sync","email:link","email:unlink","repo:connect","repo:disconnect","issues:create","board:create","board:edit:title","swimlane:create","swimlane:edit:title","board:edit:description","swimlane:edit:description","swimlane:delete","swimlane:move","issues:move","issue:close","issue:reopen","issue:edit:title","issue:edit:description","issue:tag:add","issue:tag:remove","contributor:remove","tag:remove","issue:assignee:add","issue:assignee:remove","issue:comment:add","issue:comment:delete"]);var Vn=e=>{let t=Oe({exclude:e});return h(t)?[]:t.value.map(o=>({projectId:o.projectId,name:mt(o.root),root:o.root,lastOpenedAt:o.lastOpenedAt}))},Kn=e=>{let t=Oe();if(h(t))return $(t.message);let o=t.value.find(n=>n.root===e);return o?T("Resolved recent project",o.root):$(`Not a recent project: ${e}`)};import{z as c}from"zod";var w=c.string().min(1),Yn=c.discriminatedUnion("at",[c.object({at:c.literal("start")}),c.object({at:c.literal("end")}),c.object({at:c.literal("before"),sibling:w}),c.object({at:c.literal("after"),sibling:w})]),We=c.number().finite(),v=(e,t)=>c.object({type:c.literal(e),payload:t}),ue=e=>c.object({type:c.literal(e)}),Gs=c.discriminatedUnion("type",[ue("state:get"),ue("issues:list"),ue("sync"),ue("time-travel:live"),ue("diff-stats:get"),v("project:open",c.object({root:c.string().min(1)})),v("issues:create",c.object({title:c.string(),parentId:w,description:c.string().optional(),tagNames:c.array(c.string()).optional()})),v("board:create",c.object({title:c.string()})),v("board:edit:title",c.object({boardId:w,title:c.string()})),v("swimlane:create",c.object({title:c.string(),boardId:w})),v("swimlane:edit:title",c.object({swimlaneId:w,title:c.string()})),v("board:edit:description",c.object({boardId:w,description:c.string()})),v("swimlane:edit:description",c.object({swimlaneId:w,description:c.string()})),v("swimlane:delete",c.object({swimlaneId:w})),v("swimlane:move",c.object({swimlaneId:w,boardId:w,position:Yn.optional()})),v("issues:move",c.object({issueId:w,parentId:w,position:Yn.optional()})),v("issue:edit:title",c.object({issueId:w,title:c.string()})),v("issue:edit:description",c.object({issueId:w,description:c.string()})),v("issue:tag:add",c.object({issueId:w,tagName:c.string()})),v("issue:tag:remove",c.object({issueId:w,tagId:w})),v("contributor:remove",c.object({contributorId:w})),v("tag:remove",c.object({tagId:w})),c.object({type:c.literal("contributors:get"),payload:c.object({boardId:w.optional()}).optional()}),v("issue:assignee:add",c.object({issueId:w,assigneeId:w.optional(),assigneeName:c.string().optional(),createUnlinked:c.boolean().optional()})),v("issue:assignee:remove",c.object({issueId:w,assigneeId:w})),v("issue:close",c.object({issueId:w})),v("issue:reopen",c.object({issueId:w})),v("issue:comment:add",c.object({issueId:w,body:c.string()})),v("issue:comment:delete",c.object({issueId:w,commentId:w})),v("issue:comment:edit",c.object({issueId:w,commentId:w,body:c.string()})),v("issue:get",c.object({issueId:w})),v("issue:preview:get",c.object({issueId:w})),c.object({type:c.literal("timeline:get"),payload:c.object({start:We.optional(),end:We.optional(),boardId:w.optional(),requestId:c.number().finite().optional()}).optional()}),c.object({type:c.literal("commits:get"),payload:c.object({start:We.optional(),end:We.optional(),requestId:c.number().finite().optional()}).optional()}),v("time-travel:scrub",c.object({targetTime:We})),v("time-travel:checkout-event",c.object({eventId:c.string().min(1)})),v("commit:inspect",c.object({sha:c.string(),repo:c.string().max(80).optional()})),ue("repos:get"),v("repo:preview",c.object({url:c.string().min(1).max(at),branches:c.enum(["default","all"]).optional(),since:c.string().max(20).optional(),label:c.string().max(24).optional()})),v("repo:preview:cancel",c.union([c.object({repo:c.string().min(1).max(80)}),c.object({url:c.string().min(1).max(at)})])),v("repo:connect",c.object({url:c.string().min(1).max(at),branches:c.enum(["default","all"]).optional(),since:c.string().max(20).optional(),label:c.string().max(24).optional()})),v("repo:disconnect",c.object({repo:c.string().min(1).max(2e3)})),c.object({type:c.literal("emails:get")}),v("email:link",c.object({email:c.string().min(1).max(254),contributorId:c.string().min(1).optional()})),v("email:unlink",c.object({email:c.string().min(1).max(254),contributorId:c.string().min(1).optional()})),v("commit:diff:get",c.object({sha:c.string(),repo:c.string().max(80).optional()})),v("issue:commits:get",c.object({issueId:w})),v("issue:squashed-diff:get",c.object({issueId:w})),v("issue:stats:get",c.object({issueId:w})),v("swimlane:stats:get",c.object({swimlaneId:w})),v("board:overview:get",c.object({boardId:w})),ue("me:stats:get"),ue("settings:get"),v("settings:set",c.object({autoSync:c.boolean().optional(),autoSyncIntervalMs:c.number().finite().optional()}))]);var qn=e=>{let t=Gs.safeParse(e);return t.success?{ok:!0,message:t.data}:{ok:!1,error:`Invalid message: ${t.error.issues.map(n=>`${n.path.join(".")||"<root>"}: ${n.message}`).join(", ")}`}};var Fs=1024*1024,uo=()=>{ce({type:"state",payload:he(wt())})},Jn=()=>{ce({type:"repos:changed"})},po=async(e,t)=>{Us(await vn({repoRoot:e,minIntervalMs:t}))},Us=e=>{h(e)||(e.value.some(t=>t.changed)&&Jn(),e.value.some(t=>t.changed||!t.ok)&&ce({type:"repos:fetched"}))},b=(e,t)=>{e.send(JSON.stringify(t))},Ve=async(e,t)=>{let o=he(await ee({repoRoot:t}));return h(o)&&o.message===Lo?b(e,{type:"state:unavailable",payload:{message:o.message,repoRoot:t,recentProjects:Vn(t)}}):b(e,{type:"state",payload:o})},Hs=async(e,t)=>{let o=()=>b(e,{type:"state",payload:he(wt())});if(ie().mode!=="live")return o();let n=await ee({repoRoot:t});return ie().mode!=="live"?o():b(e,{type:"state",payload:he(n)})},L=async(e,t,o,n,s)=>{if(b(e,{type:n,payload:s}),h(s))return b(e,{type:"failed",payload:s.message});o(),Hs(e,t)},Xn=(e,t,{onStateChanged:o,onSyncSettingsChanged:n,getPort:s})=>{new $s({server:e,path:"/ws",maxPayload:Fs,verifyClient:r=>!co(r.origin,s())}).on("connection",r=>{cr(r),r.on("message",async f=>{let y=async l=>{let{type:d}=l,a=t.repoRoot;if(d==="project:open"){let i=Kn(l.payload.root);return b(r,{type:"project:open:result",payload:i}),h(i)?void 0:(t.repoRoot=i.value,Ve(r,i.value))}if(d==="timeline:get"){let{requestId:i,...S}=l.payload??{};return b(r,{type:"timeline",requestId:i,payload:await Rr({repoRoot:a,...S})})}if(d==="issue:get"){let i=l.payload?.issueId,S=wt(),G=zr(i);return b(r,{type:"issue",payload:h(S)?S:T("Issue detail",{...Ln(S.value,i),history:h(G)?[]:G.value})})}if(d==="issue:preview:get"){let{issueId:i}=l.payload,S=Vr(i);return b(r,{type:"issue:preview:result",payload:{issueId:i,result:h(S)?S:T("Issue preview",Rn(i,S.value))}})}if(d==="commits:get"){let{requestId:i,...S}=l.payload??{};return b(r,{type:"commits",requestId:i,payload:so(await ft({repoRoot:a,...S}))})}if(d==="emails:get")return b(r,{type:"emails",payload:await ro({repoRoot:a}),suggestions:await no({repoRoot:a})});if(d==="email:link"||d==="email:unlink"){let S=await(d==="email:link"?gn:yn)({repoRoot:a,...l.payload});return b(r,{type:"emails",payload:await ro({repoRoot:a}),suggestions:await no({repoRoot:a}),lastAction:h(S)?{ok:!1,message:S.message}:{ok:!0,message:S.message}}),L(r,a,o,`${d}:result`,S)}if(d==="me:stats:get")return b(r,{type:"me:stats",payload:await hn({repoRoot:a})});if(d==="settings:get")return b(r,{type:"settings",payload:oo()});if(d==="settings:set"){let i=Cr({enabled:l.payload.autoSync,intervalMs:l.payload.autoSyncIntervalMs});return h(i)||n(),b(r,{type:"settings",payload:h(i)?oo():i,lastAction:h(i)?{ok:!1,message:i.message}:{ok:!0,message:i.message}})}if(d==="commit:inspect")return b(r,{type:"commit:inspect:result",payload:await nr({repoRoot:a,sha:l.payload.sha,repo:l.payload.repo})});if(d==="commit:diff:get"){let{sha:i,repo:S}=l.payload;return b(r,{type:"commit:diff:result",payload:{sha:i,repo:S,result:await or({repoRoot:a,sha:i,repo:S})}})}if(d==="repos:get"){let i=await er(a);return b(r,{type:"repos",payload:await Pe({repoRoot:a}),own:i})}if(d==="repo:preview"){let i=await io({repoRoot:a,...l.payload,previewOnly:!0});return b(r,{type:"repos",for:d,url:l.payload.url.trim(),payload:h(i)?await Pe({repoRoot:a}):i,preview:h(i)?null:i.value.preview??null,lastAction:{ok:!h(i),message:i.message}})}if(d==="repo:preview:cancel")return bn(l.payload),b(r,{type:"repos",for:d,payload:await Pe({repoRoot:a}),preview:null});if(d==="repo:connect"||d==="repo:disconnect"){let i=d==="repo:connect"?await io({repoRoot:a,...l.payload,confirm:!0}):await xn({repoRoot:a,...l.payload});return b(r,{type:"repos",for:d,payload:h(i)?await Pe({repoRoot:a}):i,preview:null,lastAction:{ok:!h(i),message:i.message}}),h(i)?b(r,{type:`${d}:result`,payload:i}):(!h(i)&&i.message!==Xo&&!i.message.startsWith(zo)&&Jn(),L(r,a,o,`${d}:result`,i))}if(d==="issue:commits:get"){let{issueId:i}=l.payload;return b(r,{type:"issue:commits:result",payload:{issueId:i,result:await tr(a,so(await Zo({repoRoot:a,ref:me(i)})))}})}if(d==="issue:squashed-diff:get"){let{issueId:i}=l.payload;return b(r,{type:"issue:squashed-diff:result",payload:{issueId:i,result:await rr({repoRoot:a,ref:me(i)})}})}if(d==="issue:stats:get"){let{issueId:i}=l.payload;return b(r,{type:"issue:stats:result",payload:{issueId:i,result:await Et({repoRoot:a,idOrRef:me(i)})}})}if(d==="diff-stats:get")return b(r,{type:"diff-stats",payload:await Gn({repoRoot:a})});if(d==="swimlane:stats:get"){let{swimlaneId:i}=l.payload;return b(r,{type:"swimlane:stats:result",payload:{swimlaneId:i,result:await kn({repoRoot:a,swimlaneId:i})}})}if(d==="board:overview:get"){let{boardId:i}=l.payload;return b(r,{type:"board:overview:result",payload:{boardId:i,result:wn({boardId:i})}})}if(d==="time-travel:scrub"){let i=await jr({repoRoot:a,targetTime:l.payload.targetTime});return b(r,{type:"time-travel:result",payload:i}),h(i)?void 0:uo()}if(d==="time-travel:checkout-event"){let i=await Dr({repoRoot:a,eventId:l.payload.eventId});return b(r,{type:"time-travel:result",payload:i}),h(i)?void 0:uo()}if(d==="time-travel:live"){let i=await _r({repoRoot:a});return b(r,{type:"time-travel:result",payload:i}),h(i)?void 0:uo()}if(d==="state:get")return Ve(r,a);if(d==="sync"){let i=await It({repoRoot:a});return b(r,{type:"sync:result",payload:i}),o(),h(i)||po(a),Ve(r,a)}if(d==="issue:comment:add"){let i=await Tt({repoRoot:a,...l.payload});return L(r,a,o,"issue:comment:add:result",i)}if(d==="issue:comment:edit"){let i=await fn({repoRoot:a,...l.payload});return L(r,a,o,"issue:comment:edit:result",i)}if(d==="issue:comment:delete"){let i=await Ct({repoRoot:a,...l.payload});return b(r,{type:"issue:comment:delete:result",payload:i}),h(i)?b(r,{type:"failed",payload:i.message}):(o(),Ve(r,a))}if(d==="issue:edit:description"){let i=await Qr({repoRoot:a,...l.payload});return L(r,a,o,"issue:edit:description:result",i)}if(d==="issue:edit:title"){let i=await Zr({repoRoot:a,...l.payload});return L(r,a,o,"issue:edit:title:result",i)}if(d==="issue:tag:add"){let i=await an({repoRoot:a,...l.payload});return L(r,a,o,"issue:tag:add:result",i)}if(d==="issue:tag:remove"){let i=await mn({repoRoot:a,...l.payload});return L(r,a,o,"issue:tag:remove:result",i)}if(d==="contributor:remove"){let i=await dn({repoRoot:a,...l.payload});return L(r,a,o,"contributor:remove:result",i)}if(d==="tag:remove"){let i=await ln({repoRoot:a,...l.payload});return L(r,a,o,"tag:remove:result",i)}if(d==="contributors:get")return b(r,{type:"contributors",boardId:l.payload?.boardId,payload:await un({repoRoot:a,...l.payload})});if(d==="issue:assignee:add"){let i=await cn({repoRoot:a,...l.payload});return L(r,a,o,"issue:assignee:add:result",i)}if(d==="issue:assignee:remove"){let i=await pn({repoRoot:a,...l.payload});return L(r,a,o,"issue:assignee:remove:result",i)}if(d==="issues:list")return b(r,{type:"issues",payload:await Kr({repoRoot:a})});if(d==="issues:create"){let i=await Yr({...l.payload,repoRoot:a});return b(r,{type:"issues:create:result",payload:i}),h(i)?ce({type:"failed",payload:i.message}):(o(),Ve(r,a))}if(d==="board:create"){let i=await en({...l.payload,repoRoot:a});return L(r,a,o,"board:create:result",i)}if(d==="board:edit:title"){let i=await tn({...l.payload,repoRoot:a});return L(r,a,o,"board:edit:title:result",i)}if(d==="swimlane:create"){let i=await on({...l.payload,repoRoot:a});return L(r,a,o,"swimlane:create:result",i)}if(d==="swimlane:edit:title"){let i=await rn({...l.payload,repoRoot:a});return L(r,a,o,"swimlane:edit:title:result",i)}if(d==="board:edit:description"){let i=await Fr({...l.payload,repoRoot:a});return L(r,a,o,"board:edit:description:result",i)}if(d==="swimlane:edit:description"){let i=await Ur({...l.payload,repoRoot:a});return L(r,a,o,"swimlane:edit:description:result",i)}if(d==="swimlane:delete"){let i=await sn({...l.payload,repoRoot:a});return L(r,a,o,"swimlane:delete:result",i)}if(d==="swimlane:move"){if(!l.payload.position)return b(r,{type:"error",message:"Missing move position"});let i=await nn({...l.payload,repoRoot:a});return L(r,a,o,"swimlane:move:result",i)}if(d==="issues:move"){if(!l.payload.position)return b(r,{type:"error",message:"Missing move position"});let i=await Xr({...l.payload,repoRoot:a});return L(r,a,o,"issues:move:result",i)}if(d==="issue:close"){let i=await qr({repoRoot:a,issueId:l.payload.issueId});return L(r,a,o,"issue:close:result",i)}if(d==="issue:reopen"){let i=await Jr({repoRoot:a,issueId:l.payload.issueId});return L(r,a,o,"issue:reopen:result",i)}return b(r,{type:"error",message:"Unknown message type"})},p,g=async l=>{if(p!=="repo:connect"&&p!=="repo:disconnect"&&p!=="repo:preview")return b(r,{type:"error",message:l});b(r,{type:"repos",for:p,payload:await Pe({repoRoot:t.repoRoot}),preview:null,lastAction:{ok:!1,message:l}}),p!=="repo:preview"&&b(r,{type:`${p}:result`,payload:$(l)})};try{let l=JSON.parse(f.toString());p=l?.type;let d=qn(l);if(!d.ok)return await g(d.error);let a=d.message;return Wn.has(a.type)?await de(async()=>ie().mode!=="live"?b(r,{type:"failed",payload:"Read-only while viewing history"}):y(a)):await y(a)}catch(l){return g(l instanceof Error?l.message:String(l))}})})};var Ys=xe.dirname(Ks(import.meta.url)),qs=process.env.IS_LOCAL==="true"?xe.resolve(process.cwd(),"dist/gui"):xe.join(Ys,"gui"),Bt,Js=async()=>(Bt===void 0&&(Bt=await import("node:sea").catch(()=>null)),Bt?.isSea()?Bt:null),M=(e,t,o)=>{e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(o))},Xs=e=>M(e,409,{isError:!0,message:"Read-only while viewing history"}),Lt=(e,t)=>de(async()=>ie().mode!=="live"?Xs(e):t()),zn=async(e,t=1024*1024)=>new Promise((o,n)=>{let s=[],u=0;e.on("data",r=>{if(u+=r.length,u>t){e.destroy(),n(new Error("Request body too large"));return}s.push(r)}),e.on("end",()=>{let r=Buffer.concat(s).toString("utf8");try{o(r?JSON.parse(r):{})}catch{n(new Error("Invalid JSON body"))}}),e.on("error",n)}),zs=2*1024*1024,Qs={png:"image/png",jpg:"image/jpeg",gif:"image/gif",webp:"image/webp"},Zs=e=>e.endsWith(".html")?"text/html; charset=utf-8":e.endsWith(".js")?"text/javascript; charset=utf-8":e.endsWith(".css")?"text/css; charset=utf-8":e.endsWith(".json")?"application/json; charset=utf-8":e.endsWith(".ico")?"image/x-icon":"application/octet-stream",Qn=new Map,ea=e=>`"${Ws("sha1").update(e).digest("base64url")}"`,ta=async e=>{try{let{size:t,mtimeMs:o}=await ks(e);return`${t}:${o}`}catch{return null}},oa=e=>{try{return decodeURIComponent(e)}catch{return null}},Zn=async(e,t,o)=>{let n=e==="/"?"/index.html":oa(e);if(n===null)return M(o,404,{isError:!0,message:"Not found"});let s=n.replace(/^\/+/,""),u=xe.resolve(qs),r=xe.resolve(u,s),f=xe.relative(u,r);if(f.startsWith("..")||xe.isAbsolute(f))return M(o,403,{isError:!0,message:"Forbidden"});let y=await Js(),p=y?"sea":await ta(r),g=p===null?void 0:Qn.get(f),l=g&&g.stamp===p?g.etag:null;if(l&&t.headers["if-none-match"]===l)return o.writeHead(304,{etag:l,"cache-control":"no-cache"}),o.end();try{let d=y?Buffer.from(y.getAsset(`gui/${f}`)):await ei(r),a=l??ea(d);return p!==null&&Qn.set(f,{stamp:p,etag:a}),o.writeHead(200,{"content-type":Zs(r),etag:a,"cache-control":"no-cache"}),o.end(d)}catch{return M(o,404,{isError:!0,message:`Not found: ${s}`})}},ra=async(e,t=He)=>new Promise((o,n)=>{let s=u=>{let r=y=>{if(e.off("listening",f),y.code==="EADDRINUSE"&&u===t){e.removeListener("error",r),s(0);return}n(y)},f=()=>{e.off("error",r);let y=e.address();if(!y||typeof y=="string"){n(new Error("Unable to resolve address"));return}o(y.port)};e.once("error",r),e.once("listening",f),e.listen(u,"127.0.0.1")};s(t)}),ti=async e=>{Br(!1);let t=0,o={repoRoot:e.repoRoot},n=Vs.createServer((p,g)=>{s(p,g).catch(l=>(logger.error(`[gui] ${p.method} ${p.url}: ${l instanceof Error?l.message:String(l)}`),g.headersSent?g.end():M(g,500,{isError:!0,message:"Internal error"})))});async function s(p,g){let l=new URL(p.url??"/","http://127.0.0.1"),d=On({method:p.method,origin:p.headers.origin,contentType:p.headers["content-type"]},t);if(d)return M(g,d.status,{isError:!0,message:d.message});if(p.method==="GET"&&l.pathname===lo)return M(g,200,{app:mo,repoRoot:Nt(o.repoRoot),version:Y,pid:process.pid});if(l.pathname==="/api/state")return M(g,200,await ee({repoRoot:o.repoRoot}));if(p.method==="POST"&&l.pathname==="/api/comments")try{let a=await zn(p);if(!a.issueId||!a.body?.trim())return M(g,400,{isError:!0,message:"Missing issueId or body"});let i=a.issueId,S=a.body;return await Lt(g,async()=>{let G=await Tt({repoRoot:o.repoRoot,issueId:i,body:S});return h(G)?M(g,400,{isError:!0,message:G.message}):M(g,200,await ee({repoRoot:o.repoRoot}))})}catch(a){return M(g,400,{isError:!0,message:a instanceof Error?a.message:"Unable to add comment"})}if(p.method==="POST"&&l.pathname==="/api/attachments")try{let a=await zn(p,zs);if(!a.issueId||!a.dataBase64)return M(g,400,{isError:!0,message:"Missing issueId or dataBase64"});let i=a.issueId,S=a.dataBase64,G=a.name??"";return await Lt(g,async()=>{let D=await Hr({repoRoot:o.repoRoot,issueId:i,name:G,dataBase64:S});return h(D)?M(g,400,{isError:!0,message:D.message}):M(g,200,{...await ee({repoRoot:o.repoRoot}),attachment:D.value})})}catch(a){return M(g,400,{isError:!0,message:a instanceof Error?a.message:"Unable to add attachment"})}if(p.method==="DELETE"&&l.pathname.startsWith("/api/attachments/")){let a=decodeURIComponent(l.pathname.replace("/api/attachments/",""));return a?Lt(g,async()=>{let i=await kr({repoRoot:o.repoRoot,attachmentId:a});return h(i)?M(g,400,{isError:!0,message:i.message}):M(g,200,await ee({repoRoot:o.repoRoot}))}):M(g,400,{isError:!0,message:"Missing attachment id"})}if(p.method==="GET"&&l.pathname.startsWith("/media/")){let a=decodeURIComponent(l.pathname.replace("/media/","")),i=await Wr({repoRoot:o.repoRoot,fileName:a});if(h(i))return M(g,404,{isError:!0,message:i.message});try{let S=await ei(i.value.filePath);return g.writeHead(200,{"content-type":Qs[i.value.ext]??"application/octet-stream","cache-control":"public, max-age=31536000, immutable"}),g.end(S)}catch{return M(g,404,{isError:!0,message:"Attachment blob not found"})}}if(p.method==="DELETE"&&l.pathname.startsWith("/api/comments/")){let a=decodeURIComponent(l.pathname.replace("/api/comments/",""));return a?Lt(g,async()=>{let i=await Ct({repoRoot:o.repoRoot,commentId:a});return h(i)?M(g,400,{isError:!0,message:i.message}):M(g,200,await ee({repoRoot:o.repoRoot}))}):M(g,400,{isError:!0,message:"Missing comment id"})}return l.pathname.startsWith("/board/")||l.pathname==="/log"?Zn("/",p,g):Zn(l.pathname,p,g)}try{t=await ra(n)}catch(p){return $(p instanceof Error?`Unable to start GUI server: ${p.message}`:`Unable to start GUI server: ${String(p)}`)}let u=Dn({project:o}),r=Mn({project:o,publisher:u,onReposFetch:p=>po(o.repoRoot,p)}),f=_n(u);Xn(n,o,{onStateChanged:()=>r.queueSync(),onSyncSettingsChanged:()=>r.reschedule(),getPort:()=>t}),n.on("close",()=>{r.dispose(),f()});let y=n.address();return!y||typeof y=="string"?(n.close(),$("Unable to resolve GUI server address")):T("Started GUI server",{url:`http://epiq.localhost:${y.port}${e.boardId?`/board/${e.boardId}`:""}`,server:n})};var oi=async e=>{let t=f=>{e.open!==!1&&En()&&Pn(f)},o=rt({});if(h(o))return $(o.message);let n=we();F(n)&&_e(n.value);let s=await Nn(He);if(s&&s.repoRoot===Nt(e.repoRoot)){let f=`http://127.0.0.1:${He}`;return console.log(ao({url:f,repoRoot:e.repoRoot,version:Y,reused:!0})),t(f),T("Reused running GUI",{url:f})}let u=await ti({repoRoot:e.repoRoot,boardId:""});if(h(u))return u;let{url:r}=u.value;return console.log(ao({url:r,repoRoot:e.repoRoot,version:Y,reused:!1})),t(r),T("Started GUI",{url:r})};import{Box as le}from"ink";import N from"react";import{Box as fo,Text as Ke}from"ink";import te,{useEffect as na,useMemo as ia}from"react";import{ulid as sa}from"ulid";var ri=({text:e,match:t,color:o,highlightColor:n=m.secondary,dimColor:s=!1})=>{if(!t)return te.createElement(Ke,{color:o,dimColor:s},e);let u=e.toLowerCase(),r=t.toLowerCase(),f=u.indexOf(r);return f===-1?te.createElement(Ke,{color:o,dimColor:s},e):te.createElement(Ke,{color:o,dimColor:s},e.slice(0,f),te.createElement(Ke,{backgroundColor:n,bold:!0},e.slice(f,f+t.length)),e.slice(f+t.length))},ni=sa(),aa=e=>`${e}`,la=e=>{let{pendingNavTarget:t}=xr();if(!t)return[];let{breadCrumb:o,contextNode:n,selectedNode:s}=t,u=new Set(qo(ut.NONE,{breadCrumb:o,contextNode:n,readOnly:Q().readOnly,selectedNode:s}));return[...new Set(Object.values(ut))].filter(r=>r!=="move").filter(r=>r.length>0).filter(r=>r!==ut.PALETTE).map(r=>{let f=pr(r),y=Er.find(p=>p.intent===f);return{command:r,description:y?.description??`[${r}] Run command`,isAvailable:u.has(r)}}).filter(r=>r.command.toLowerCase().startsWith(e)||e.length>=2&&r.description.toLowerCase().includes(e)).sort((r,f)=>r.isAvailable!==f.isAvailable?r.isAvailable?-1:1:r.command.localeCompare(f.command))},ma=e=>Te.text({id:ni,parentNodeId:e,rank:"000000",name:"Command Palette",readonly:!0,isVirtual:!0}),ca=(e,t,o)=>Te.text({id:aa(e.command),parentNodeId:o,rank:String(t).padStart(6,"0"),name:e.command,disabled:!e.isAvailable,readonly:!0,isVirtual:!0}),go=[],da=e=>{ii();let t=q.createNode(ma(Q().rootNodeId));h(t)||!Ie(t.value)||(go=[t.value,...e.map((o,n)=>ca(o,n,ni)).map(q.createNode).filter(F).map(({value:o})=>o).filter(Ie)],Ce.navigate({contextNode:t.value,selectedIndex:0}))},ii=()=>{let e=go.map(t=>t.id);go=[];for(let t of e)q.deleteNode(t)};function si({width:e,height:t}){let n=lr().value.trim().toLowerCase(),s=ia(()=>la(n),[n]);na(()=>(da(s),()=>{ii()}),[s]);let u=Q().selectedIndex;return te.createElement(fo,{flexDirection:"column",width:e,height:t-2},te.createElement(xt,{height:t-4,itemHeight:3,selectedIndex:u},s.map((r,f)=>{let y=f===u,p=r.isAvailable?m.accent:m.secondary2,g=r.isAvailable?"":"[unavailable] ";return te.createElement(fo,{key:r.command,flexDirection:"column",paddingX:1,borderLeft:!1,borderBottom:!1,borderRight:!1,borderColor:m.secondary,borderStyle:"single"},te.createElement(Ke,{color:p,dimColor:!r.isAvailable},y?"\u276F ":" ",te.createElement(ri,{text:Yo(r.command),match:n,color:p,dimColor:!r.isAvailable})),te.createElement(fo,{paddingLeft:2},te.createElement(ri,{text:g+r.description,match:n.length>=2?n:"",color:y&&r.isAvailable?m.primary:m.secondary2,dimColor:!r.isAvailable})))})))}import{Box as Ea}from"ink";import Dt from"react";import qe from"chalk";import{Box as Ye,Text as ci}from"ink";import be,{useEffect as di,useMemo as ua,useState as ui}from"react";var Ae=["\u2803","\u2806","\u2830","\u2818"],ai=120,li=({isPalette:e,isPending:t,frame:o})=>{if(t){let n=(o%Ae.length+Ae.length)%Ae.length;return Ae[n]}return e?"?":":"},mi=({infoMessage:e,isPending:t})=>t&&e.includes(sr)?"":e;var pi=qe.hex(m.secondary),pa=qe.inverse,fa=qe.inverse.hex(m.secondary2),ga={hint:"",hints:[],overlap:0,remainder:""},gi=({value:e,command:t})=>{if(!t)return null;let o=e.trimStart(),s=e.length-o.length;return e.slice(s,s+t.length)!==t?null:{start:s,end:s+t.length}},ya=({command:e,modifier:t})=>{if(!t)return null;if(e==="tag"||e==="assign"){let o=Do(t);return{bg:n=>qe.bgHex(o).black(n),bgCursor:n=>qe.bgHex(o).inverse.black(n)}}return eo(t)},ha=({value:e,command:t,modifier:o})=>{if(!t||!o)return null;let n=gi({value:e,command:t});if(!n)return null;let u=e.slice(n.end).match(/^\s*/)?.[0].length??0,r=n.end+u;return e.slice(r,r+o.length)!==o?null:{start:r,end:r+o.length}},fi=()=>({value:ne.value,cursorPosition:ne.cursorPosition,commandIsPending:ne.commandIsPending,autoCompletion:ne.commandMeta.autoCompletion??ga,infoMessage:ne.commandMeta.infoMessage,validationStatus:ne.commandMeta.validity,command:ne.commandMeta.command,inputString:ne.commandMeta.inputString,modifier:ne.commandMeta.modifier}),xa=(e,t)=>e.value===t.value&&e.cursorPosition===t.cursorPosition&&e.commandIsPending===t.commandIsPending&&e.infoMessage===t.infoMessage&&e.autoCompletion.hint===t.autoCompletion.hint&&e.autoCompletion.overlap===t.autoCompletion.overlap&&e.autoCompletion.remainder===t.autoCompletion.remainder&&e.validationStatus===t.validationStatus&&e.command===t.command&&e.modifier===t.modifier&&e.inputString===t.inputString,yi=({width:e,mode:t})=>{let[o,n]=ui(fi());di(()=>{let B=()=>{let C=fi();n(I=>xa(I,C)?I:C)},E=ar(B);return B(),()=>{E()}},[]);let{value:s,cursorPosition:u,infoMessage:r,commandIsPending:f,autoCompletion:y,command:p,modifier:g,validationStatus:l}=o,d=f&&l===ir.Invalid,a=mi({infoMessage:r,isPending:f}),[i,S]=ui(0);di(()=>{if(!f){S(0);return}let B=setInterval(()=>{S(E=>(E+1)%Ae.length)},ai);return()=>{clearInterval(B)}},[f]);let G=li({isPalette:t===U.PALETTE,isPending:f,frame:i}),D=ua(()=>{let B=Math.max(0,Math.min(u,s.length)),E=gi({value:s,command:p}),C=ha({value:s,command:p,modifier:g}),I=p?eo(p):null,W=ya({command:p,modifier:g}),Se=(V,K)=>{let Qt=E&&K>=E.start&&K<E.end,Zt=C&&K>=C.start&&K<C.end;return Qt&&I?I.fg(V):Zt&&W?W.bg(V):V},je=(V,K)=>{let Qt=E&&K>=E.start&&K<E.end,Zt=C&&K>=C.start&&K<C.end;return Qt&&I?I.fgCursor(V):Zt&&W?W.bgCursor(V):pa(V)},ye=s.slice(0,B),Z=s[B]??" ",De=B<s.length?s.slice(B+1):"",ot=Array.from(ye).map((V,K)=>Se(V,K)).join(""),Ao=je(Z,B),No=Array.from(De).map((V,K)=>Se(V,B+1+K)).join("");if(y.hint){let V=y.hint[y.overlap]??Z;Ao=fa(V),No=pi(y.remainder.slice(1)+De)}return ot+Ao+No},[s,u,y,p,g]);return be.createElement(Ye,{flexDirection:"column",justifyContent:"flex-start"},be.createElement(Ye,{flexDirection:"column",paddingX:1,borderColor:m.secondary,borderStyle:"round",width:e},be.createElement(Ye,{height:1,flexWrap:"nowrap"},be.createElement(Ye,{flexShrink:0},be.createElement(ci,{wrap:"truncate-start"},pi(G),D)),a&&be.createElement(Ye,{flexShrink:1,minWidth:0},be.createElement(ci,{wrap:"truncate",color:d?m.red:m.secondary2},` ${a} `)))))};import{Box as ba,Text as Je}from"ink";import Ne from"react";var hi=" ",va=({keys:e,label:t})=>e.length+1+t.length,Sa=(e,t)=>{let o=[],n=0;for(let s of e){let r=(o.length>0?hi.length:0)+va(s);if(n+r>t-4)break;o.push(s),n+=r}return o},xi=({width:e,availableHints:t})=>{let o=Sa(t,e);return Ne.createElement(ba,{width:e,borderStyle:"round",borderColor:m.secondary,paddingX:1},o.length?Ne.createElement(Je,{wrap:"truncate"},o.map(({keys:s,label:u},r)=>Ne.createElement(Je,{key:`${s}-${u}`},r>0?hi:"",Ne.createElement(Je,{color:m.accent},s),Ne.createElement(Je,{color:m.secondary2}," ",u)))):Ne.createElement(Je,{color:m.secondary2},"\xA0"))};import{Box as wa,Text as Rt}from"ink";import Xe,{useEffect as Ia,useRef as Me,useState as Ta}from"react";var Ca=40,jt=.3,yo="\u2500",bi=1,vi=16,Si=({width:e})=>{let{replay:t}=_(),o=t!==null,n=t?Math.min(1,Math.max(0,t.progress)):0,u=Math.max(4,e-6),r=u*bi,[f,y]=Ta(0),p=Me(n);p.current=n;let g=Me(0),l=Me(0),d=Me(0),a=Me(0),i=Me(0);if(Ia(()=>{if(!o){g.current=0,d.current=0,a.current=0,i.current=0,y(0);return}g.current=p.current,l.current=Date.now(),d.current=p.current;let E=setInterval(()=>{let C=Date.now(),I=p.current;if(I!==d.current){let Z=I-d.current,De=C-l.current;if(Z<0)a.current=0,i.current=0;else if(Z>0&&De>0){let ot=Z/De;a.current=a.current===0?ot:a.current*(1-jt)+ot*jt,i.current=i.current===0?Z:i.current*(1-jt)+Z*jt}g.current=I,l.current=C,d.current=I}let W=C-l.current,Se=Math.min(i.current,a.current*W),je=Math.min(1,g.current+Se),ye=Math.round(je*r);y(Z=>Z===ye?Z:ye)},Ca);return()=>clearInterval(E)},[o,r]),!t)return null;let S=E=>{let C=u>1?E/(u-1):0,I=Math.round(C*(vi-1))/(vi-1);return Go(I)},G=Math.min(u,Math.floor(f/bi)),D=[];for(let E=0;E<G;E++){let C=S(E),I=D[D.length-1];I&&I.color===C?I.text+=yo:D.push({text:yo,color:C})}let B=yo.repeat(Math.max(0,u-G));return Xe.createElement(wa,{width:e,borderStyle:"round",borderColor:m.secondary,paddingX:1,columnGap:1},Xe.createElement(Rt,{color:m.secondary2},"\u25B6"),Xe.createElement(Rt,null,D.map((E,C)=>Xe.createElement(Rt,{key:C,color:E.color},E.text)),Xe.createElement(Rt,{color:m.secondary,dimColor:!0},B)))};var ze=({width:e,mode:t,availableHints:o})=>{let{timeMode:n}=_(),s=t===U.COMMAND_LINE||t===U.PALETTE;return Dt.createElement(Ea,null,s?Dt.createElement(yi,{width:e,mode:t}):n==="replay"?Dt.createElement(Si,{width:e}):Dt.createElement(xi,{width:e,mode:t,availableHints:o}))};import{Box as pe,Text as Be}from"ink";import H,{useEffect as Pa,useMemo as Aa}from"react";import{ulid as wi}from"ulid";var Ot=wi(),Na=()=>[...new Set([...Q().availableActions].map(e=>e.description).filter(e=>e!==void 0))].map(Pr).filter(e=>e!==null).sort(({keys:e},{keys:t})=>e.length===1&&t.length!==1?-1:e.length!==1&&t.length===1?1:e.localeCompare(t,void 0,{sensitivity:"base"})).map(({keys:e,label:t})=>({keys:e,action:t})),Ma=e=>Te.text({id:Ot,parentNodeId:e,rank:"000000",name:"Help",isVirtual:!0,readonly:!0}),Ba=(e,t,o)=>Te.text({id:wi(),parentNodeId:o,rank:String(t).padStart(6,"0"),name:e.keys,readonly:!0,isVirtual:!0}),_t=[],Ii=()=>{let e=_t.filter(o=>o.id!==Ot).map(o=>o.id),t=_t.filter(o=>o.id===Ot).map(o=>o.id);_t=[];for(let o of[...e,...t])q.deleteNode(o)},La=e=>{Ii();let t=q.createNode(Ma(Q().rootNodeId));if(h(t)||!Ie(t.value))return logger.error("Could not attach help nodes");_t=[t.value,...e.map((o,n)=>Ba(o,n,Ot)).map(q.createNode).filter(F).map(({value:o})=>o).filter(Ie)],Ce.navigate({contextNode:t.value,selectedIndex:0})},Ti=({width:e,height:t})=>{let o=Aa(()=>Na(),[]);Pa(()=>(La(o),()=>{Ii()}),[o]);let n=Q().selectedIndex;return H.createElement(pe,{flexDirection:"column",marginTop:3,borderColor:m.secondary,borderStyle:"round",width:e,height:t-2},H.createElement(pe,{paddingX:1,justifyContent:"center"},H.createElement(Be,{color:m.accent},"Help"),H.createElement(Be,{dimColor:!0}," \u2014 navigate with arrows/hjkl, press q to close")),H.createElement(pe,{paddingX:1,marginTop:1},H.createElement(pe,{width:20,justifyContent:"flex-end"},H.createElement(Be,{color:m.secondary},"Key(s)")),H.createElement(pe,{flexGrow:1,width:40,paddingLeft:2},H.createElement(Be,{color:m.secondary},"Action"))),H.createElement(xt,{height:t-7,itemHeight:1,selectedIndex:n},o.map(({keys:s,action:u},r)=>{let f=r===n;return H.createElement(pe,{paddingX:1,key:`${s}-${u}-${r}`,flexDirection:"row"},H.createElement(pe,{width:20,justifyContent:"flex-end"},H.createElement(Be,{color:m.accent},s)),H.createElement(pe,{flexGrow:1,width:40,paddingLeft:2},H.createElement(Be,{color:f?m.primary:m.secondary2},u)))})))};import{Box as Le,Text as k}from"ink";import P,{useEffect as Ra,useState as ho}from"react";var Gt=({index:e,email:t,note:o,noteColor:n})=>P.createElement(Le,null,P.createElement(k,{color:m.accent},e===void 0?" ":` ${e}.`),P.createElement(k,null," ",t),o&&P.createElement(k,{color:n??m.secondary2},` ${o}`)),Ci=({height:e})=>{let[t,o]=ho([]),[n,s]=ho([]),[u,r]=ho(null),{userName:f,gitEmail:y,gitName:p,userId:g}=re();return Ra(()=>{let l=!0;return(async()=>{let a=Ee(),i=oe(process.cwd());if(h(a)||h(i)||!g)return;let S=a.value.emailLinks,G=Ho(S,g);o(G.map(C=>({email:C,others:Uo(S,C).filter(I=>I!==g).map(I=>a.value.contributors[I]?.name??I)})));let D=it(i.value),B=await vt({repoRoot:i.value,stateBranch:h(D)?void 0:D.value,names:[f,p],links:S});if(!l)return;if(h(B)){r(B.message);return}let E=St(B.value);ct(E.map(C=>C.email)),s(E)})(),()=>{l=!1}},[g,f,p,y]),P.createElement(Le,{height:e-4,flexDirection:"column",paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},P.createElement(Le,null,P.createElement(k,{color:m.accent,bold:!0},f??"Not configured"),P.createElement(k,{color:m.secondary2}," on this board")),u&&P.createElement(k,{color:m.red},u),P.createElement(Le,{flexDirection:"column"},P.createElement(k,{color:m.secondary2},"CLAIMED"),t.length===0?P.createElement(Gt,{email:"Nothing claimed \u2014 your commits show the name git signed them with.",note:""}):t.map(l=>P.createElement(Gt,{key:l.email,email:l.email,note:l.others.length>0?`CONTESTED: also ${l.others.join(", ")}, resolves to nobody`:l.email===y?"your git identity here":void 0,noteColor:l.others.length>0?m.yellow:void 0}))),P.createElement(Le,{flexDirection:"column"},P.createElement(k,{color:m.secondary2},"UNCLAIMED IN THIS HISTORY"),n.length===0?P.createElement(Gt,{email:"Nothing left to claim here."}):n.map(l=>P.createElement(Gt,{key:l.email,email:l.email,note:`${l.commits} commit${l.commits===1?"":"s"} as ${l.names.join(", ")||"unknown"}`}))),P.createElement(Le,{flexDirection:"column"},P.createElement(k,{color:m.secondary2},P.createElement(k,{color:m.accent},"[enter]")," writes a claim for the first into the command line, to confirm or change."),P.createElement(k,{color:m.secondary2},P.createElement(k,{color:m.accent},":config emails")," claims by address,",P.createElement(k,{color:m.accent}," :config emails-unclaim "),"gives one back."),P.createElement(k,{color:m.secondary2},P.createElement(k,{color:m.accent},"[esc]")," to close")))};import ja from"chalk";import{Box as ve,Text as O}from"ink";import A from"react";var Da=8,_a=()=>{let e=Oe({exclude:process.cwd()});return h(e)?[]:e.value.slice(0,Da)},Ei=({width:e,height:t})=>{let o=_a();return A.createElement(ve,{height:t-4,flexDirection:"column",width:e,paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},A.createElement(O,{color:m.accent,bold:!0},"Initialize project"),A.createElement(O,null,`This folder is not an ${ja.hex(m.accent)("epiq")} project yet.`),A.createElement(O,{color:m.primary},"To start tracking issues here, we need to initialize a new",A.createElement(O,{color:m.primary,backgroundColor:m.secondary}," .epiq/project.json "),"file in this repository."),A.createElement(ve,{marginTop:1,flexDirection:"column"},A.createElement(ve,null,A.createElement(O,{color:m.accent}," "),A.createElement(O,{color:m.primary},"Type "),A.createElement(O,{backgroundColor:m.secondary}," :init "))),A.createElement(ve,{marginTop:1},A.createElement(O,{color:m.secondary2},"This will create, commit and push "),A.createElement(O,{color:m.primary,backgroundColor:m.secondary}," .epiq/project.json ")),o.length>0&&A.createElement(ve,{marginTop:1,flexDirection:"column"},A.createElement(O,{color:m.accent,bold:!0},"Or open a recent project"),o.map((n,s)=>A.createElement(ve,{key:n.projectId},A.createElement(O,{color:m.accent},` ${s+1} `),A.createElement(O,{color:m.primary},mt(n.root)),A.createElement(O,{color:m.secondary2},` ${n.root}`))),A.createElement(ve,{marginTop:1},A.createElement(O,{color:m.accent}," "),A.createElement(O,{color:m.primary},"Type "),A.createElement(O,{backgroundColor:m.secondary}," :open 1 "),A.createElement(O,{color:m.secondary2}," or "),A.createElement(O,{backgroundColor:m.secondary}," :open <path> "))))};import{Box as Ft,Text as X}from"ink";import R from"react";import{Box as $t,Text as ae}from"ink";import J,{useEffect as Oa,useState as Pi}from"react";var Ai=()=>{let[e,t]=Pi(null),[o,n]=Pi(null);return Oa(()=>{let s=!0;return(async()=>{let r=Ee(),f=oe(process.cwd());if(h(r)||h(f))return;let y=it(f.value),{userName:p,gitName:g}=re(),l=await vt({repoRoot:f.value,stateBranch:h(y)?void 0:y.value,names:[p,g],links:r.value.emailLinks});if(!s)return;if(h(l)){n(l.message);return}let d=St(l.value);ct(d.map(a=>a.email)),t(d)})(),()=>{s=!1}},[]),o?J.createElement($t,{marginTop:1},J.createElement(ae,{color:m.red},o)):e===null?null:e.length===0?J.createElement($t,{marginTop:1},J.createElement(ae,{color:m.secondary2},"No unclaimed addresses in this history \u2014 type",J.createElement(ae,{color:m.accent}," :config emails none "),"to move on.")):J.createElement($t,{flexDirection:"column",marginTop:1},e.map(s=>J.createElement(ae,{key:s.email},J.createElement(ae,{color:m.accent}," \xB7 "),J.createElement(ae,null,s.email),J.createElement(ae,{color:m.secondary2},` ${s.commits} commit${s.commits===1?"":"s"} as ${s.names.join(", ")||"unknown"}`))),J.createElement($t,{marginTop:1},J.createElement(ae,{color:m.secondary2},"Claim yours by address, or",J.createElement(ae,{color:m.accent}," none "),"to skip.")))};var Ga=({isDone:e,command:t,value:o,verb:n="Type",hint:s})=>R.createElement(Ft,null,R.createElement(X,{color:m.accent,dimColor:e},e?" \u2714 ":" "),R.createElement(X,{dimColor:e},n," "),R.createElement(X,{backgroundColor:m.secondary,dimColor:e}," "+t+" "),o!==void 0&&R.createElement(R.Fragment,null,R.createElement(X,{dimColor:e}," "),R.createElement(X,{color:m.secondary,dimColor:e},"<"+o+">")),s),$a=(e,t)=>e.length===0?void 0:Vo(e.join(", "),Math.max(12,t-34)),Fa=e=>{if(typeof e=="string")return e;if(typeof e=="boolean")return e?"on":"off"};function xo({width:e,height:t}){let{isSetPreferredEditor:o,isSetUserName:n,userName:s,preferredEditor:u,autoSync:r,isSetAutoSync:f,isSetEmails:y,claimedEmails:p,emailSetupDeclined:g}=dt(),l=[{key:"username",done:n,command:":config username",value:s,message:"First, choose your username."},{key:"editor",done:o,command:":config editor",value:u,message:"Nice. Now pick your editor."},{key:"autosync",done:f,command:":config autosync",value:r,message:"Almost there. Configure auto sync."},{key:"emails",done:y,command:":config emails",value:g?"declined":$a(p,e),message:"Last one. Claim the git addresses whose commits are yours, so the board calls them by your name."}],d=l.findIndex(i=>!i.done),a=d===-1?void 0:l[d];return R.createElement(Ft,{height:t-4,flexDirection:"column",width:e,paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},R.createElement(X,{color:m.accent,bold:!0},"Welcome! \u{1F539}"),R.createElement(X,null,"Let's get you started - it's a breeze."),R.createElement(X,{color:m.secondary2},"Remember - you can always search available commands by typing:",R.createElement(X,{color:m.accent}," ? ")),a&&R.createElement(X,{color:m.secondary2},a.message),R.createElement(Ft,{flexDirection:"column"},l.map((i,S)=>{if(!(d===-1||S<=d))return null;let D=S===d,B=D&&d===0;return R.createElement(Ft,{key:i.key,flexDirection:"column",marginBottom:1},R.createElement(Ga,{isDone:i.done,command:B?":config us":i.command,value:i.done?Fa(i.value):void 0,verb:D&&!B?"Waiting:":"Type",hint:B?R.createElement(X,{color:m.secondary2}," then ",R.createElement(X,{color:m.accent},"tab")," to auto-complete ",R.createElement(X,{backgroundColor:m.secondary},` ${i.command.split(" ").pop()} `)):void 0}),i.key==="emails"&&!i.done&&R.createElement(Ai,null))})))}import Vt from"chalk";import{Box as Ze,Text as Re}from"ink";import j from"react";import{Box as Ut,Text as Ni}from"ink";import fe from"react";import Ua from"chalk";var Ha=e=>(q.getTag(e)?.name??"").length+3,ka=e=>{let t=q.getContributor(e);return(t?t.name:"").length+3},Mi=({width:e})=>{let{viewMode:t}=re(),o=_(),{breadCrumb:n,contextNode:s,selectedIndex:u,renderedChildrenIndex:r}=o,f=r[s.id]?.[u],y=Nr(f?.id??s.id,"TICKET"),p=F(y)?y.value:void 0,g=(p?.props.tags??[]).filter(I=>q.getTag(I)),l=p?.props.assignees??[],d=p?.parentNodeId?!Mr(s.id,p.parentNodeId)&&t==="dense":!1,a=n.map((I,W)=>{let Se=W===n.length-1,je=gt(I.id),ye=Se?je?.[u]?.title:void 0;return`${W?" / ":""}${I.title??""}${ye?` \u25B8 ${ye}`:""}`}).join(""),i=p?q.getCommentsByIssue(p.id):[],S=i.length?String(i.length).length+11:0,G=d?g.reduce((I,W)=>I+Ha(W),0)+l.reduce((I,W)=>I+ka(W),0)+S:0,D=f?.id!=null&&!(t==="wide"&<(f)),B=Math.max(0,e-G),E=a.substring(0,B)+(D?Ua.hex(m.secondary2).dim(` ${me(f.id)}`):""),C=d?[...g.map(I=>fe.createElement(Ut,{key:`tag-${I}`,paddingLeft:1},fe.createElement(yr,{id:I}))),...l.map(I=>fe.createElement(Ut,{key:`assignee-${I}`,paddingLeft:1},fe.createElement(gr,{id:I}))),i.length?fe.createElement(Ut,{key:"comments",paddingLeft:1},fe.createElement(Ni,{color:m.accent},"[",i.length," comment",i.length===1?"":"s","]")):null]:[];return fe.createElement(Ut,{overflow:"hidden",justifyContent:"flex-start",alignItems:"flex-start"},fe.createElement(Ni,{color:m.secondary2},E),C)};import{Box as Wa,Text as Bi}from"ink";import Ht from"react";var Va=({filters:e})=>Ht.createElement(Wa,{columnGap:1},Ht.createElement(Bi,{color:"red"},"APPLIED FILTERS:"),e.map(({value:t,target:o,operator:n})=>Ht.createElement(Bi,{backgroundColor:"black",color:"white"},` ${o}${n}"${t}" `))),Li=Ht.memo(Va);import{Box as Ka,Text as kt}from"ink";import Qe from"react";function Ri(){let{eventLog:e,unappliedEvents:t}=_(),o=e.at(-1)?.id,n=$o(o??""),s=F(n)?bt(n.value):"INVALID DATE";return Qe.createElement(Ka,{paddingLeft:1},Qe.createElement(kt,{backgroundColor:m.accent,color:m.secondary}," Readonly "),Qe.createElement(kt,{color:m.accent}," "+t.length+" edits ago at "+s+"."),Qe.createElement(kt,{color:m.accent}," Resume with "),Qe.createElement(kt,{backgroundColor:m.accent,color:m.secondary}," ",":peek now"," "))}import{Box as Ya,Text as bo}from"ink";import Wt from"react";function ji(){let{replay:e}=_();if(!e)return null;let{appliedCount:t,totalCount:o,currentTime:n}=e;return Wt.createElement(Ya,{paddingRight:2,columnGap:1,justifyContent:"flex-end"},Wt.createElement(bo,{backgroundColor:m.accent,color:m.secondary}," \u25B6 REPLAY "),Wt.createElement(bo,{color:m.secondary2},bt(new Date(n))),Wt.createElement(bo,{color:m.accent},`${t}/${o} edits`))}import vo from"chalk";import{Box as qa,Text as Di}from"ink";import So,{useEffect as Ja,useState as Xa}from"react";var za=["#4c567a","#9d7cd8","#7aa2f7","#7dcfff","#9d7cd8"],Qa=150,_i=12,Za=.36;function Oi({syncStatus:e,autoSync:t}){let[o,n]=Xa(0);Ja(()=>{if(e.status!=="syncing"){n(0);return}let f=0,y=setInterval(()=>{f+=1;let p=(Math.sin(f*Za)+1)/2,g=Math.round(p*(_i-1));n(l=>l===g?l:g)},Qa);return()=>clearInterval(y)},[e.status]);let s={synced:" ",failed:"---",offline:"off",syncing:"...",pending:"idle"},r={synced:m.secondary2,failed:m.yellow,offline:m.secondary2,pending:m.secondary2,syncing:Oo(za,o/(_i-1))??""}[e.status];return So.createElement(qa,null,So.createElement(Di,null,vo.hex(m.secondary2).dim(t?"Sync (auto): ":"Sync: ")),So.createElement(Di,null,vo.hex(r)("\u25CF")+vo.hex(m.secondary2).dim(` ${s[e.status].padEnd(4)} `)))}import Hi from"chalk";import{Text as ki}from"ink";import Wi,{useEffect as rl,useState as nl}from"react";import wo from"chalk";var el="https://registry.npmjs.org/epiq/latest",Io=null,Gi=0,tl=1e3*60*60*24,$i=e=>e.replace(/^v/,""),ol=(e,t)=>{let o=$i(e).split(".").map(Number),n=$i(t).split(".").map(Number);for(let s=0;s<Math.max(o.length,n.length);s++){let u=o[s]??0,r=n[s]??0;if(u>r)return 1;if(u<r)return-1}return 0},Fi=async e=>{if(process.env.IS_CI==="true")return{current:"1.2.3",latest:"1.2.3",updateAvailable:!1};if(Io&&Date.now()-Gi<tl)return Io;try{let t=await fetch(el);if(!t.ok)throw new Error(`Failed to fetch latest version: ${t.status}`);let n=(await t.json()).version??null,s={current:e,latest:n,updateAvailable:n?ol(n,e)>0:!1};return Io=s,Gi=Date.now(),s}catch{return{current:e,latest:null,updateAvailable:!1}}},Ui=(e,t)=>{let o=e.split("."),n=t.split("."),s=n.findIndex((u,r)=>u!=o[r]);return n.map((u,r)=>r>=s?wo.hex(m.accent).dim(u):wo.hex(m.secondary).dim(u)).join(wo.hex(m.secondary2).dim("."))};function Vi(){let[e,t]=nl({current:Y,latest:null,updateAvailable:!1});return rl(()=>{let o=!0;return Fi(Y).then(n=>{o&&t(n)}),()=>{o=!1}},[]),!e.updateAvailable||!e.latest?Wi.createElement(ki,{dimColor:!0,color:m.secondary2},Y+" "):Wi.createElement(ki,null,Hi.hex(m.secondary2).dim(Y),Hi.hex(m.accent).dim(" \u2197 "),Ui(Y,e.latest))}function et({filters:e,hideBreadCrumb:t=!1}){let{timeMode:o,syncStatus:n,mode:s,replay:u}=_(),{userName:r,preferredEditor:f,autoSync:y}=re(),p=64,g=process.stdout.columns-p-8,l=t||o==="replay",d=u?Wo(u.currentLabel,Math.max(0,g)):"";return j.createElement(Ze,{justifyContent:"space-between",flexDirection:"row","max-width":process.stdout.columns-40,overflow:"hidden"},o==="replay"?j.createElement(Ze,{paddingLeft:1},j.createElement(Re,{color:m.secondary2},d)):l?j.createElement(Re,null," "):s===U.PALETTE?j.createElement(Ze,null,j.createElement(Re,{color:m.accent},"Command Palette"),j.createElement(Re,{dimColor:!0,color:m.secondary2}," ","- search, select and press enter")):j.createElement(Ze,{paddingLeft:1},e.length>0?j.createElement(Li,{filters:e}):j.createElement(Mi,{width:g})),o==="live"?j.createElement(Ze,{columnGap:1,paddingRight:2,"max-width":p,overflow:"hidden",justifyContent:"flex-end"},j.createElement(Oi,{autoSync:!!y,syncStatus:n}),j.createElement(Re,null,Vt.hex(m.secondary2).dim("Mode: ")+Vt.hex(m.secondary2).dim(s.padEnd(8," "))," "),j.createElement(Ki,{icon:"@",value:r}),j.createElement(Ki,{icon:"\u276F",value:f}),j.createElement(Vi,null)):"",o==="peek"?j.createElement(Ri,null):"",o==="replay"?j.createElement(ji,null):"")}function Ki({icon:e,value:t}){return j.createElement(Re,null,Vt.dim(e)+Vt.hex(m.accent)(` ${t??"-"} `))}import{Box as il,Text as sl}from"ink";import tt from"react";import{Box as Kt,Text as To}from"ink";import ge from"react";function Co(){let e=_(),t=e.nodes[e.rootNodeId],s=process.stdout.rows-1-3,u=process.stdout.columns||120,r=t?.id?$e(t?.id):[];return ge.createElement(Kt,{flexDirection:"column",height:s,padding:1,borderStyle:"round",borderColor:m.secondary,width:u},ge.createElement(Kt,{padding:1,paddingTop:0,paddingBottom:0},ge.createElement(To,null,"Select a board:")),ge.createElement(Kt,{padding:1,flexDirection:"column"},r.map((f,y)=>{let p=e.contextNode.context==="WORKSPACE"&&e.selectedIndex===y,l=$e(f.id).flatMap(({id:d})=>gt(d)).length;return ge.createElement(Kt,{key:f.id??y},ge.createElement(To,{color:p?m.accent:m.secondary2},ge.createElement(fr,{isSelected:p})),ge.createElement(To,{color:p?m.accent:m.secondary2},f.title," (",l," issues)",f.readonly?" \u{1F512}":""))})))}var al=({contextNode:e,selectedIndex:t,breadCrumb:o,mode:n,viewMode:s,height:u,width:r})=>{let{renderedChildrenIndex:f}=_(),y=o.find(({context:d})=>d==="BOARD"),l=u-1-3;return tt.createElement(il,{flexDirection:"row"},e.context==="WORKSPACE"?tt.createElement(Co,null):y?tt.createElement(hr,{height:l,width:r,swimlanes:(f[y.id]??[]).filter(d=>d!==void 0&&ko(d)),contextNode:e,selectedIndex:t,breadCrumb:o,viewMode:s,mode:n}):tt.createElement(sl,null))},Yi=tt.memo(al);import{useEffect as ll}from"react";var ml=e=>{ll(()=>{if(!e)return;let t,o=!1,n=()=>{if(o)return;let{autoSyncIntervalMs:s,userName:u,preferredEditor:r}=re();r&&u&&s&&(t=setTimeout(()=>{if(o)return;let{readOnly:f,mode:y}=Q();y==="default"&&!f&&ur(),n()},s))};return n(),()=>{o=!0,t&&clearTimeout(t)}},[e])},qi=({autoSync:e})=>(ml(e),null);import{useEffect as cl}from"react";var Ji=()=>{let e=oe(process.cwd());return h(e)?T("No project here",null):st({repoRoot:e.value})},Xi=async()=>{let e=Ji();if(h(e))return $(e.message);if(e.value===null)return T("No project here",null);let t=e.value,o=await pt(t);if(!Ar())return T("State not initialized",null);let n=Ee();if(h(n))return T("State not initialized",null);let{mode:s,readOnly:u,timeMode:r,syncStatus:f,selectedNode:y,contextNode:p}=n.value;if(vr())return T("Project loading",null);let g=Ji();return h(g)||g.value!==t?T("Project changed",null):s!==U.DEFAULT||u||r!=="live"?T("Skipped while not on the live board",null):y?.isVirtual||p?.isVirtual?T("Skipped on a virtual node",null):f?.status==="syncing"?T("Sync in progress",null):o?T("Worktree held by a sync",null):Ge(t)===Jo(t)?T("Log unchanged",null):(nt.debug("[watch] event log moved, reloading state"),dr(t))};var dl=1e3,zi=()=>(cl(()=>Mt(Xi,dl),[]),null);function Eo({width:e,height:t}){let o=_(),{autoSync:n,viewMode:s}=jo(),u=o.filters;if(o.mode===U.HELP)return N.createElement(le,{flexDirection:"column"},N.createElement(Ti,{width:e,height:t}));if(o.mode===U.IDENTITY)return N.createElement(le,{flexDirection:"column"},N.createElement(Ci,{width:e,height:t}));if(o.mode===U.PALETTE)return N.createElement(le,{flexDirection:"column"},N.createElement(et,{filters:u}),N.createElement(si,{width:e,height:t-2}),N.createElement(ze,{width:e,mode:o.mode,availableHints:o.availableHints}));let{isSetupDone:r}=dt(),f=!r,y=r&&!o.hasProjectDefinition;if(f)return N.createElement(le,{flexDirection:"column"},N.createElement(le,{flexDirection:"column"},N.createElement(et,{hideBreadCrumb:!0,filters:u}),N.createElement(xo,{height:t,width:e})),N.createElement(ze,{width:e,mode:o.mode,availableHints:[]}));if(y)return N.createElement(le,{flexDirection:"column"},N.createElement(le,{flexDirection:"column"},N.createElement(et,{hideBreadCrumb:!0,filters:u}),N.createElement(Ei,{height:t,width:e})),N.createElement(ze,{width:e,mode:o.mode,availableHints:[]}));let p=Fo(o.breadCrumb??[],"BOARD");if(F(p)){let g=p.value.id,l=$e(g).length,d=3,a=Math.floor(e/d),i=Math.floor(e/Math.max(l,1));e=Math.min(i,a)*Math.max(l,d)}return N.createElement(le,{flexDirection:"column"},N.createElement(qi,{autoSync:n}),N.createElement(zi,null),N.createElement(le,{flexDirection:"column"},N.createElement(et,{filters:u}),N.createElement(Yi,{width:e,height:t,contextNode:o.contextNode,selectedIndex:o.selectedIndex,breadCrumb:o.breadCrumb,viewMode:s??"dense",mode:o.mode})),N.createElement(ze,{width:e,mode:o.mode,availableHints:o.availableHints}))}import ul from"readline";var Yt,qt,se,pl=new Set([x.MoveCursorLeft,x.EraseInputWord,x.MoveCursorLeftOfWord,x.MoveCursorRight,x.MoveCursorRightOfWord,x.NavToPreviousContainer,x.NavToNextContainer,x.NavPreviousItem,x.NavNextItem,x.NavPreviousItemJump,x.NavNextItemJump,x.SetViewDense,x.SetViewWide,x.Confirm,x.Exit,x.Yank,x.InitCommandLine,x.InitCommandPalette,x.ExitCommandLine,x.CaptureInput,x.EraseInput,x.EraseInputWord,x.HideHelp,x.ViewHelp,x.SetViewDense,x.SetViewWide,x.GetLastCommandFromHistory,x.GetNextCommandFromHistory,x.AutoCompleteCommand]),fl=new Set([x.NavPreviousItem,x.NavNextItem,x.NavPreviousItemJump,x.NavNextItemJump,x.NavToPreviousContainer,x.NavToNextContainer,x.Confirm,x.Exit,x.InitCommandPalette,x.InitMove,x.MoveNextItem,x.MovePreviousItem,x.MoveNextItemJump,x.MovePreviousItemJump,x.MoveToNextContainer,x.MoveToPreviousContainer,x.Delete,x.AddItem,x.EditTitle,x.EditDescription,x.ConfirmMove,x.Edit,x.ViewHelp,x.Yank]),Qi=async e=>{if(e.ctrl&&e.name==="c")return Ce.exit();let{actionIndex:t,mode:o,readOnly:n,timeMode:s}=Q(),u=mr(e,o);if(!u||n&&!pl.has(u)||s==="replay"&&o===U.DEFAULT&&fl.has(u))return;let r=t[o]?.[u];if(r?.action)try{await r.action(r,e)}catch(f){logger.error(f)}},gl=()=>async function(t,o){o.name!=="escape"&&(se&&(clearTimeout(se),se=void 0),await Qi(o))},yl=()=>async function(t){if(t.length===1&&t[0]===27){se&&clearTimeout(se),se=setTimeout(()=>{Qi({name:"escape",ctrl:!1,meta:!1,shift:!1,sequence:"\x1B"}),se=void 0},25);return}se&&(clearTimeout(se),se=void 0)};function Zi(){Yt&&process.stdin.removeListener("keypress",Yt),qt&&process.stdin.removeListener("data",qt),Yt=gl(),qt=yl(),ul.emitKeypressEvents(process.stdin),process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.on("data",qt),process.stdin.on("keypress",Yt)}async function es(){try{let e=rt({});if(h(e))return yt(0,e.message);let t=we();F(t)&&_e(t.value);let o=oe(process.cwd());_e({gitEmail:await Or(process.cwd()),gitName:await Gr(process.cwd())});let n=F(o)?await Sr(o.value):Ir();if(h(n))return n;let s=Po();return h(s)?yt(6,s.message):(Zi(),F(o)&&wr(o.value),T("Booted Epiq",void 0))}catch(e){return yt(0,ht(e))}}br();var vl=`${z.bold("Epiq CLI")}
|
|
4
|
-
|
|
5
|
-
${z.dim("Boot in directory:")}
|
|
6
|
-
${z.cyan("$ epiq")}
|
|
7
|
-
|
|
8
|
-
${z.dim("Launch GUI:")}
|
|
9
|
-
${z.cyan("$ epiq gui")}
|
|
10
|
-
${z.cyan("$ epiq gui --no-open")} ${z.dim("no browser")}
|
|
11
|
-
|
|
12
|
-
${z.dim("Act as somebody other than the configured user:")}
|
|
13
|
-
${z.cyan("$ epiq --as claude")}
|
|
14
|
-
`,zt=xl(vl,{importMeta:import.meta,version:Y,flags:{init:{type:"boolean",default:!1},as:{type:"string"},open:{type:"boolean",default:!0}}}),Jt=zt.input[0];Jt&&Jt!=="gui"&&(console.error(z.red(`Unknown command: ${Jt}`)),process.exit(1));if(zt.flags.as!==void 0){let e=Mo(zt.flags.as,"--as");h(e)&&(console.error(z.red(e.message)),process.exit(1))}var ts=process.stdout.columns||120,os=process.stdout.rows||20,Xt=null,Sl=e=>{try{return Xt?(Xt.rerender(e),T("Rerendered app",void 0)):(Xt=hl(e),T("Rendered app",void 0))}catch(t){return $(`Unable to render app: ${ht(t)}`)}},Po=()=>Sl(bl.createElement(Eo,{width:ts,height:os}));process.stdout.on("resize",()=>{if(ts=process.stdout.columns||120,os=process.stdout.rows||20,!Xt)return;let e=Po();h(e)&&logger.info(`[boot:resize] ${e.message}`)});if(Jt==="gui"){let e=await oi({repoRoot:process.cwd(),open:zt.flags.open});h(e)&&(console.error(z.red(`Failed to start Epiq GUI:
|
|
15
|
-
${e.message}`)),process.exitCode=1)}else{console.clear();let e=await es();h(e)&&(logger.info(e.message),console.error(z.red(`Failed to boot Epiq:
|
|
16
|
-
${e.message}`)),process.exitCode=1)}export{Po as renderApp};
|
package/dist/chunk-6VBRR7QM.js
DELETED