epiq 1.16.0 → 1.16.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-WQDRC3CF.js +17 -0
- package/dist/{args-VQK4D7QS.js → args-6LT6KUMQ.js} +1 -1
- package/dist/chunk-5E42KQM3.js +10 -0
- package/dist/{chunk-4BPR3FGA.js → chunk-GOROXQFX.js} +27 -27
- package/dist/chunk-MTEK6CI6.js +2 -0
- package/dist/gui/main.js +121 -121
- package/dist/index.js +1 -1
- package/dist/mcp.js +1 -1
- package/dist/server-JWNOKRFL.js +2 -0
- package/dist/{virtual-nodes-PIX2S3SV.js → virtual-nodes-W5WJQXFR.js} +1 -1
- package/package.json +1 -1
- package/readme.md +4 -4
- package/dist/Index-CFIOSP3B.js +0 -17
- package/dist/chunk-BE2ONDXH.js +0 -8
- package/dist/chunk-BGP4XGKD.js +0 -2
- package/dist/server-OJXRDAZM.js +0 -31
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-WQDRC3CF.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-6LT6KUMQ.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-W5WJQXFR.js");n(!1);var{startMcpServer:a}=await import("./server-JWNOKRFL.js");await a();
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{$ as ve,B as ne,C as se,D as re,E as ae,F as le,G as ce,H as de,J as pe,K as me,L as ue,M as he,N as ge,O as fe,P as we,Q as be,R as ye,S as _e,U as Ie,X as Re,Y as ke,Z as qe,_ as Se,aa as Te,b as A,ba as Ee,ca as je,da as xe,ea as Ae,fa as Ne,ga as Ce,ha as Pe,i as H,ia as Le,ja as Me,k as z,ka as Oe,l as X,la as Ge,m as W,ma as Ue,n as Y,o as J,oa as De,p as Q,pa as $e,q as V,qa as Fe,r as Z,s as ee,sa as Ke,t as te,u as oe,x as ie}from"./chunk-5E42KQM3.js";import{Ra as R,b as M,ca as $,dc as K,h as O,ja as F,l as G,m as U,uc as B,vb as k,x as D}from"./chunk-GOROXQFX.js";import{a as L}from"./chunk-WUCQWBQE.js";import{b as d,c as l,d as a}from"./chunk-5RIQL7P4.js";import{McpServer as ht}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as gt}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as e}from"zod";var ct=t=>{let o=new Map,n=[t.nodes,t.contributors,t.tags,t.goals,t.comments,t.attachments];for(let s of n)for(let r of Object.keys(s??{})){let c=R(r),m=o.get(c);m?m.includes(r)||m.push(r):o.set(c,[r])}return{byRef:o,goals:new Set(Object.keys(t.goals??{}))}},Be=()=>{let t=B();return a(t)?null:ct(t.value)},He="goal",ze=t=>/(Id|Ids)$/.test(t)||t==="sibling"||t==="idOrRef"||t===He,S=t=>typeof t=="string"&&t.length===7,v=t=>Array.isArray(t)?t.some(v):!t||typeof t!="object"?!1:Object.entries(t).some(([o,n])=>ze(o)?S(n)||Array.isArray(n)&&n.some(S):v(n)),Xe=(t,o,n=!1)=>{let s=(t.byRef.get(o.toUpperCase())??[]).filter(r=>!n||t.goals.has(r));return s.length>1?d(`Ref ${o} is ambiguous: use one of ${s.join(", ")}`):l("Resolved ref",s[0]??o)},We=(t,o)=>{let n=[];for(let s of t){let r=o(s);if(a(r))return r;n.push(r.value)}return l("Expanded",n)},Ye=(t,o)=>S(o)?Xe(t,o):Array.isArray(o)?We(o,n=>Ye(t,n)):l("Kept",o),N=(t,o)=>{if(Array.isArray(o))return We(o,s=>N(t,s));if(!o||typeof o!="object")return l("Kept",o);let n={};for(let[s,r]of Object.entries(o)){let c=s===He&&S(r)?Xe(t,r,!0):ze(s)?Ye(t,r):N(t,r);if(a(c))return c;n[s]=c.value}return l("Expanded",n)},Je=t=>{let o=Be();return o?N(o,t):l("No state to resolve against",t)},q=(t,o)=>{if(typeof o=="string"){let s=t.byRef.get(R(o));return s?.length===1&&s[0]===o?R(o):o}if(Array.isArray(o))return o.map(s=>q(t,s));if(!o||typeof o!="object")return o;let n={};for(let[s,r]of Object.entries(o))n[q(t,s)]=q(t,r);return typeof n.id=="string"&&n.id===n.ref&&delete n.ref,n},Qe=t=>{let o=Be();return o?q(o,t):t};import{ulid as dt}from"ulid";var Ve=[{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)"}],Ze=t=>t.trim().toLowerCase(),et=async(t={})=>{let o=G();if(a(o))return d(o.message);let n=o.value,s=t.userName?.trim(),r=(process.env[L]??"").trim();if(s&&r&&Ze(s)===Ze(r))return d(`userName "${s}" is this agent's own identity. Pass the user's name, the one they want the TUI and GUI to write as.`);let c={userName:s||void 0,preferredEditor:t.preferredEditor?.trim()||void 0,autoSync:t.autoSync},m={userName:n.userName?.trim()||void 0,preferredEditor:n.preferredEditor?.trim()||void 0,autoSync:typeof n.autoSync=="boolean"?n.autoSync:void 0};for(let p of Ve){let h=c[p.name],b=m[p.name];if(!(h===void 0||b===void 0||h===b))return d(`This machine is already set up with ${p.name} ${JSON.stringify(b)}; epiq_project_init does not change it. Call again without ${p.name}, or let the user change it in the TUI with :config.`)}let u={};if(c.userName&&!m.userName&&(u.userName=c.userName),c.preferredEditor&&!m.preferredEditor&&(u.preferredEditor=c.preferredEditor),c.autoSync!==void 0&&m.autoSync===void 0&&(u.autoSync=c.autoSync),(u.userName||m.userName)&&!n.userId&&(u.userId=dt()),Object.keys(u).length>0){let p=U(u);if(a(p))return d(p.message)}let E={...n,...u},j=Ve.filter(p=>{let h=E[p.name];return typeof h=="boolean"?!1:!h?.trim()});if(j.length>0){let p=j.map(I=>`${I.name} (${I.question})`).join("; "),h=j.some(I=>I.name==="userName")?await H(t.repoRoot??process.cwd()):null,b=h?` This repository's git user.name is ${JSON.stringify(h)} \u2014 offer it as the default for userName, and use it only if the user agrees.`:"";return d(`Setup incomplete. Ask the user for: ${p}.${b} Then call epiq_project_init again with the answers; what was given so far is saved.`)}let y={userId:E.userId??"",userName:E.userName??""};if(!y.userId||!y.userName)return d("Missing Epiq user id");let x=await K({cwd:t.repoRoot??process.cwd(),user:y});if(a(x))return x;let{defaultEvents:yt,..._}=x.value,P=$({root:_.repoRoot});a(P)&&M.info(P.message);let at=_.warnings.length===0?"Project initialized":`Project initialized, with warnings: ${_.warnings.join(" ")}`;return l(at,{..._,user:y})};import T from"node:fs";import tt from"node:path";var g=".claude/skills/epiq/SKILL.md",C="---\nname: epiq\ndescription: 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.\n---\n\n# Epiq board workflow\n\n- **Use the `epiq_*` MCP tools** for every board read and write \u2014 never the CLI, hand edits, or the state branch directly.\n- **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.\n- Move tickets along the board with correct status\n- **The MCP never syncs on its own:** call `epiq_sync` to pull or publish.\n- **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.\n- **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.\n- **Keep tickets reasonably scoped**; put a small follow-up on its existing ticket instead of a new one.\n- **Read a ticket's comments before starting.**\n- **Board and lane descriptions describe team conventions** (`boardDescription`, `laneDescription` in responses): follow them unless they conflict with your user's instructions.\n- **Picking up a ticket:** assign yourself and move it to the in-progress lane. Ask before taking one assigned to someone else.\n- **Keep status, tags and description current**; reuse existing tags.\n- **Goals group tickets that serve one outcome, on any board.** Put a ticket in one with `epiq_issue_goal_set` (`goal`: its name, created if new, or null to take it out). A ticket has at most one goal; `epiq_goal_list` shows every goal and its progress. A ticket counts as done for its goal once closed, or in a lane named Done or marked done (`epiq_swimlane_rule_set`).\n- **Start bigger work with a goal.** Before a feature or larger task, create a goal (`epiq_goal_create`), describe its intent and expectations in a few lines, not its implementation (`epiq_goal_description_edit`), then break the work into tickets in that goal.\n- **Comment** on deviations, blockers, and the outcome when done.\n- **Prompt user for closing tickets and big decisions**\n- **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.\n- **Link commits** with an `Epiq-Ref: <ref>` line in the commit body. The MCP names every ticket by its 7-character ref; use that. Several tickets go on one line, comma-separated. A subject starting with the ref also links, but puts the ref in everyone's history.\n- *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.\n- **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.\n- **Be concise, use clear language.** Titles, descriptions, and comments should be scannable, easy to understand, not essays.\n- **When a ticket is done, Document the outcome in a comment starting with \"Solution:\"**. Use that exact prefix as the comment's opening line.\n- **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.\n- On rebase or merge, make sure Epiq refs survive. Dropping them from commit messages breaks commit linking.\n";var ot=async(t={})=>{let o=await O(t.repoRoot??process.cwd());if(a(o))return d(o.message);let n=tt.join(o.value,g);if(T.existsSync(n)){if(T.readFileSync(n,"utf8")===C)return l("Skill already installed and up to date",{path:n,written:!1});if(!t.force)return d(`${g} already exists and differs from the bundled skill. Pass force:true to overwrite it.`)}try{T.mkdirSync(tt.dirname(n),{recursive:!0}),T.writeFileSync(n,C,"utf8")}catch(s){return d(s instanceof Error?`Failed to write ${g}: ${s.message}`:`Failed to write ${g}`)}return l(`Installed skill at ${g}`,{path:n,written:!0})};var w=t=>({isError:a(t),content:[{type:"text",text:JSON.stringify(a(t)?{message:t.message}:{message:t.message,value:Qe(t.value)})}]}),ft=async t=>{if(!v(t))return l("No refs",t);let o=await z(t.repoRoot);return a(o)?l("Unbooted",t):Je(t)},i=t=>o=>A(async()=>{let n=await ft(o);return w(a(n)?n:await t(n.value))}),wt="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. Replies name nodes by their 7-character ref, and every id input takes one.",bt=()=>{let t=new ht({name:"epiq",version:"0.2.30"},{instructions:wt});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(ie)),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, 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(re)),t.registerTool("epiq_issue_get",{description:"Get one Epiq issue by its ref or full id, with its comments in log order: the latest three whole, earlier ones by their first three lines (olderComments says so), and allComments returns every one whole. 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),allComments:e.boolean().optional(),repoRoot:e.string().optional()})},i(se)),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=>w(await Ie(o))),t.registerTool("epiq_board_list",{description:"List Epiq boards",inputSchema:e.object({repoRoot:e.string().optional()})},i(ue)),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(he)),t.registerTool("epiq_swimlane_list",{description:"List Epiq swimlanes",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().optional()})},i(fe)),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(we)),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(be)),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(ge)),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(k("swimlane"))})},i(W)),t.registerTool("epiq_swimlane_rule_set",{description:"Turn a swimlane rule on or off. The one rule is `done`: an open ticket in a lane with it counts as done for its goal. A lane named Done always counts.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),rule:e.enum(F),on:e.boolean()})},i(te)),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(k("board"))})},i(X)),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(ye)),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(_e)),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(ae)),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(pe)),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(me)),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(ke)),t.registerTool("epiq_issue_goal_set",{description:"Put an Epiq issue in a goal (a group of tickets serving one outcome, on any board), by the goal's name or id, creating the goal if there is none of that name; null takes it out. One goal per ticket. epiq_goal_list lists every goal with its progress.",inputSchema:e.object({issueId:e.string().min(1),goal:e.string().min(1).nullable(),repoRoot:e.string().optional()})},i(Q)),t.registerTool("epiq_goal_list",{description:"List the goals in the project: each a group of tickets serving one outcome, with done/total (done is closed, or in a done lane: see epiq_swimlane_rule_set) and the boards its tickets are on. Put a ticket in one with epiq_issue_goal_set; epiq_goal_stats gives its code stats.",inputSchema:e.object({repoRoot:e.string().optional()})},i(J)),t.registerTool("epiq_goal_stats",{description:"Code stats for a goal, by its name or id: epiq_issue_stats over every commit of every ticket in it, each commit counted once. Its `ref` field holds the goal id, not a ticket ref.",inputSchema:e.object({goal:e.string().min(1),repoRoot:e.string().optional()})},i(Re)),t.registerTool("epiq_goal_create",{description:"Create a goal with no tickets yet. To create one and put a ticket in it at once, use epiq_issue_goal_set with the new name.",inputSchema:e.object({name:e.string().min(1),repoRoot:e.string().optional()})},i(V)),t.registerTool("epiq_goal_rename",{description:"Rename a goal; its colour and tickets stay. Ids are in epiq_goal_list.",inputSchema:e.object({goalId:e.string().min(1),name:e.string().min(1),repoRoot:e.string().optional()})},i(Z)),t.registerTool("epiq_goal_description_edit",{description:"Edit a goal's markdown description: what it is for and when it is done. Empty clears it. epiq_goal_list returns it.",inputSchema:e.object({goal:e.string().min(1),description:e.string().max(k("goal")),repoRoot:e.string().optional()})},i(Y)),t.registerTool("epiq_goal_remove",{description:"Remove a goal; its tickets stay where they are, in no goal. Ids are in epiq_goal_list.",inputSchema:e.object({goalId:e.string().min(1),repoRoot:e.string().optional()})},i(ee)),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(ve)),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(Ae)),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(je)),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(qe)),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(Se)),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(xe)),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(Ee)),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(Ne)),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(Ce)),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(oe)),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(Pe)),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(Le)),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(ce)),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(le)),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(de)),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(Te)),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(Me)),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(Oe)),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(Ue)),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(Ge)),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(et)),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(ot)),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=>w(await Ke(await A(()=>ne(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=>w(await De(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(D),branches:e.enum(["default","all"]).optional(),since:e.string().max(20).optional(),label:e.string().max(24).optional(),confirm:e.boolean().optional()})},async o=>w(await $e(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=>w(await Fe(o))),t},ao=async()=>{let t=bt(),o=new gt;await t.connect(o)};export{wt as MCP_INSTRUCTIONS,bt as createMcpServer,w as resultJson,ao as startMcpServer};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Fc as a,Gc as b,Hc as c,Ic as d,Jc as e,Kc as f}from"./chunk-
|
|
2
|
+
import{Fc as a,Gc as b,Hc as c,Ic as d,Jc as e,Kc as f}from"./chunk-GOROXQFX.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/readme.md
CHANGED
|
@@ -53,9 +53,9 @@ Since anyone on the board can connect a repo, URLs are read with care: only `htt
|
|
|
53
53
|
|
|
54
54
|
A goal groups the tickets that serve one outcome, on any board. A ticket can be in one goal. Goals are not tickets: a board shows the goals its tickets are in as a strip above the lanes, each pill underlined as far as the goal's tickets are done (closed, or in a done lane), on every board. A lane named Done counts, and so does any lane ticked "Tickets here count as done" in its panel.
|
|
55
55
|
|
|
56
|
-
- **GUI:** pick a goal in a ticket's Goal dropdown, or type a new name there to create one; from the keyboard, **Put in a goal** and **Take out of its goal** in the palette (⌘K, then `goal`). Click a pill to show only that goal's tickets and open its panel:
|
|
57
|
-
- **TUI:** `:goal <name>` puts the selected ticket in that goal, creating it if needed; `:ungoal` takes it out; `:filter goal <name>` shows only its tickets. A ticket in a goal carries `◆` in the goal's colour. Renaming and removing a goal is done in the GUI or the MCP, as with tags.
|
|
58
|
-
- **MCP:** `epiq_issue_goal_set` with a goal's name (created if needed) or `null`; `epiq_goal_list` lists every goal with its progress and boards; `epiq_goal_stats` gives a goal's code stats; `epiq_goal_create`, `epiq_goal_rename`, `epiq_goal_remove
|
|
56
|
+
- **GUI:** pick a goal in a ticket's Goal dropdown, or type a new name there to create one; from the keyboard, **Put in a goal** and **Take out of its goal** in the palette (⌘K, then `goal`). Click a pill to show only that goal's tickets and open its panel: a description of what it's for, progress and every ticket in it on any board, a Stats tab measuring the code of all of them together, and a Code tab listing every commit on them. **Manage goals** (the strip, the dropdown or the palette) adds, renames and removes them.
|
|
57
|
+
- **TUI:** `:goal <name>` puts the selected ticket in that goal, creating it if needed; `:ungoal` takes it out; `:filter goal <name>` shows only its tickets. A ticket in a goal carries `◆` in the goal's colour. `:rule done` and `:unrule done` mark the selected lane done or not; a done lane shows `✓` after its count. Renaming and removing a goal is done in the GUI or the MCP, as with tags.
|
|
58
|
+
- **MCP:** `epiq_issue_goal_set` with a goal's name (created if needed) or `null`; `epiq_goal_list` lists every goal with its progress and boards; `epiq_goal_stats` gives a goal's code stats; `epiq_goal_create`, `epiq_goal_rename`, `epiq_goal_description_edit`, `epiq_goal_remove`; `epiq_goal_list` carries each goal's description. `epiq_board_list` lists the goals each board shows. `epiq_swimlane_rule_set` marks a lane done; `epiq_swimlane_list` says which lanes count.
|
|
59
59
|
|
|
60
60
|
A board shows a goal once one of its tickets is on it. Removing a goal leaves its tickets where they are, in no goal.
|
|
61
61
|
|
|
@@ -174,7 +174,7 @@ Every process — your TUI, your GUI, each agent's MCP server - writes as your u
|
|
|
174
174
|
|
|
175
175
|
That agent then shows up in the contributor list, assigns itself rather than you, and authors its own events. This can be useful when tracing many agents at the same time. Consider reusing names instead of inventing one per session, or the registry fills with single-run identities.
|
|
176
176
|
|
|
177
|
-
### Board and lane
|
|
177
|
+
### Board and lane conventions
|
|
178
178
|
|
|
179
179
|
A board's or a lane's description holds its conventions: "tests before review", "one ticket per PR". The MCP hands them to agents where they apply. Assuming an identity returns the board rules, getting or moving a ticket returns its lane's, and creating one returns both. Agents are told to follow them unless they conflict with their user's instructions. Write them with `epiq_board_description_edit` and `epiq_swimlane_description_edit`, in the board's or the lane's panel in the GUI, or with `edit description` on a selected lane or board in the TUI.
|
|
180
180
|
|
package/dist/Index-CFIOSP3B.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{a as F}from"./chunk-BGP4XGKD.js";import{$ as vn,B as tn,C as on,D as rn,E as nn,F as sn,G as an,H as ln,I as mn,K as cn,L as dn,N as un,O as pn,P as fn,Q as gn,R as io,S as Ct,T as yn,U as hn,W as xn,X as bn,Z as wn,a as Dr,aa as Sn,b as pe,c as ie,ca as In,d as Or,da as Tn,e as Ur,ea as Pt,f as Gr,fa as At,g as $r,ga as En,h as Fr,ha as Cn,i as Hr,ia as Pn,j as kr,ja as so,k as Wr,ka as ao,l as Vr,la as An,ma as Ae,n as Kr,na as lo,o as Yr,oa as Nn,p as qr,pa as Mn,q as Jr,r as Xr,ra as Rn,s as zr,sa as Bn,t as Qr,ta as Ln,u as Zr,w as en,x as Tt,y as ee,z as Et}from"./chunk-BE2ONDXH.js";import{$ as zo,$b as vt,Ab as ne,Ac as Lr,Bb as dr,Bc as jr,Cb as ur,Cc as q,Da as Qo,Db as x,E as ro,Eb as pr,Fb as ht,G as ko,Ib as Ce,Ic as _r,Ka as $e,Kb as fr,L as Wo,La as Zo,Lb as ue,P as Vo,Pb as xt,Q as Ko,Qb as bt,Ra as de,T as ct,Ta as Ee,U as Te,Ub as gr,V as Yo,Vb as yr,Wb as hr,X as H,Xb as xr,Y as qo,Yb as wt,Z as Jo,Zb as br,_ as Xo,_b as wr,a as _o,aa as dt,ab as er,ac as vr,b as st,ba as Ge,bb as tr,bc as Sr,c as at,cb as or,cc as Ir,da as ut,db as gt,ea as pt,fc as Tr,g as lt,gb as yt,gc as Er,hb as rr,hc as Cr,ia as ft,ic as Pr,j as Do,k as oe,l as Oo,mc as Ar,n as Ie,nc as no,o as re,oc as Nr,p as Uo,pc as St,q as Ue,qb as nr,qc as It,r as m,rb as ir,rc as Mr,s as Go,sb as sr,sc as Rr,t as $o,tb as ar,tc as Q,u as Fo,ub as lr,uc as Pe,v as Ho,w as oo,wc as O,x as mt,xc as Fe,yb as mr,zb as cr,zc as Br}from"./chunk-4BPR3FGA.js";import{f as it,g as jo}from"./chunk-WUCQWBQE.js";import{b as G,c as T,d as h,e as $}from"./chunk-5RIQL7P4.js";import z from"chalk";import{render as _l}from"ink";import Dl from"meow";import Ol from"react";import fs from"node:os";import gs from"node:path";import He from"chalk";var Nt=["\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 Mt=" ",Dn=He.hex(m.secondary2),jn=He.hex(m.gray),ys=()=>{let t=Nt[0].length+Nt.length*2;return Nt.map((o,n)=>Array.from(o).map((s,u)=>{let[r,f,y]=$o((u+n*2)/t);return He.rgb(r,f,y)(s)}).join(""))},hs=e=>{let t=fs.homedir();return e===t||e.startsWith(t+gs.sep)?"~"+e.slice(t.length):e},_n=(e,t)=>`${Mt}${He.hex(m.accent)("\u279C")} ${Dn(e.padEnd(9))}${t}`,mo=({url:e,repoRoot:t,version:o,reused:n})=>["",...ys().map(s=>Mt+s),"",`${Mt}${Dn("gui")} ${jn(`\xB7 v${o}`)}`,"",_n("Local",He.hex(m.accent).bold(e)),_n("Project",hs(t)),"",Mt+jn(n?"already running for this project \xB7 opened in your browser":"press ctrl+c to stop"),""].join(`
|
|
3
|
-
`);import{spawn as xs}from"node:child_process";import ke from"node:process";var On=(e=ke.platform,t=ke.env)=>e==="darwin"||e==="win32"||!!(t.DISPLAY||t.WAYLAND_DISPLAY||t.BROWSER),Un=e=>{let t=ke.platform==="darwin"?"open":ke.platform==="win32"?"cmd":"xdg-open",o=ke.platform==="win32"?["/c","start","",e]:[e];try{let n=xs(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 yi,stat as ma}from"node:fs/promises";import{createHash as ca}from"node:crypto";import da from"node:http";import be from"node:path";import{fileURLToPath as ua}from"node:url";import bs from"node:fs";import Gn from"node:path";var We=Number(process.env.EPIQ_GUI_PORT)||3710,co="/api/instance",uo="epiq",Rt=e=>{try{return bs.realpathSync(Gn.resolve(e))}catch{return Gn.resolve(e)}},ws=e=>{let t=e;return typeof t=="object"&&t!==null&&t.app===uo&&typeof t.repoRoot=="string"&&typeof t.version=="string"&&typeof t.pid=="number"},$n=async(e,t=500)=>{let o=new AbortController,n=setTimeout(()=>o.abort(),t);try{let s=await fetch(`http://127.0.0.1:${e}${co}`,{signal:o.signal});if(!s.ok)return null;let u=await s.json();return ws(u)?u:null}catch{return null}finally{clearTimeout(n)}};var vs=6e4,Fn=e=>{let t,o=!1,n=!1,s=0,u=()=>{let g=Oo();return h(g)?(st.error(g.message),null):g.value},r=()=>{let g=u();if(!g)return!1;let l=Ie();return h(l)?!1:!!g.autoSync&&Ar(l.value)===null},f=()=>{let g=_o(u()?.autoSyncDebounceMs);return Math.max(0,g-(Date.now()-s))},y=async()=>{if(!(o||n)&&r()){n=!0,s=Date.now();try{await pe(async()=>{if(ie().mode!=="live")return!1;let l=await Et({repoRoot:e.project.repoRoot});return await e.publisher.publishIfLogMoved(),!h(l)})&&e.onReposFetch?.(vs)}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 Bt=(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 Ss=/^(```|~~~)[^\n]*\n[\s\S]*?\n\1[ \t]*$/gm,Is=/^(?:```|~~~)[\s\S]*$/m,Ts=/^[ \t]*\|?[ \t]*:?-{2,}:?[ \t]*(?:\|[ \t]*:?-{2,}:?[ \t]*)*\|?[ \t]*$/gm,Es=/^[ \t]*\|.*$/gm,Cs=/!\[[^\]]*\]\([^)]*\)/g,Ps=/\[([^\]]*)\]\([^)]*\)/g,As=/^[ \t]*(?:[#>]+[ \t]*|[-*+][ \t]+|\d+[.)][ \t]+)/gm,Ns=/^[ \t]*(?:-{3,}|\*{3,}|_{3,})[ \t]*$/gm,Ms=/[*`~]/g,Rs=/(?<![0-9A-Za-z])_|_(?![0-9A-Za-z])/g,Bs=e=>Xo(e.replace(Ss," ").replace(Is," ").replace(Cs," ").replace(Ps,"$1").replace(Ns," ").replace(Ts," ").replace(Es,t=>t.replaceAll("|"," ")).replace(As,"").replace(Ms,"").replace(Rs,"")),Ls=.5,Hn=(e,t)=>{if(t<=0)return"";let o=Bs(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*Ls?u.slice(0,r):u).trimEnd()}${n}`};var js=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))}),xe=e=>h(e)?e:T(e.message,js(e.value)),_s=(e,t)=>(e.boards??[]).flatMap(o=>o.swimlanes??[]).flatMap(o=>o.issues??[]).find(o=>o.id===t),kn=(e,t)=>{let o=_s(e,t);return{issueId:t,description:o?.description??"",comments:e.commentsByIssueId?.[t]??[]}},Ds=280,Wn=(e,t)=>({issueId:e,excerpt:Hn(t,Ds)});var Os=1e3,Vn=e=>{let t=oe(e.repoRoot);if(h(t))return null;let o=lt({repoRoot:t.value});return h(o)?null:o.value},Kn=e=>{let t=()=>{let r=Vn(e.project);return r===null?null:$e(r)},o=()=>{let r=or(e.project.repoRoot);return h(r)?null:JSON.stringify([r.value.live,r.value.overLimit])},n=o(),s=t();return{publishIfLogMoved:async()=>{let r=Vn(e.project);if(r===null||await gt(r))return;let f=$e(r);if(f===s)return;s=f;let y=xe(await ee({repoRoot:e.project.repoRoot}));if(h(y))return;ue({type:"state",payload:y});let p=o();p!==null&&p!==n&&(n=p,ue({type:"repos:changed"}))}}},Yn=(e,t=Os)=>Bt(()=>pe(async()=>{ie().mode==="live"&&await e.publishIfLogMoved()}),t);var Us=new Set(["127.0.0.1","[::1]","localhost","epiq.localhost"]),po=(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:!Us.has(o.hostname)},qn=(e,t)=>e.method==="GET"||e.method==="HEAD"?null:po(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 ia}from"ws";var $s=new RegExp(`^[0-9A-Z]{${7}}$`),Fs=e=>{let t=e.indexOf(" ");if(t===-1)return null;let o=e.slice(0,t).toUpperCase();return $s.test(o)?o:null},Hs=e=>{let t={};for(let o of e){let n=Fs(o.subject),s=new Set([...n?[n]:[],...o.refs??[]]);for(let u of s)(t[u]??=[]).push({time:o.time,insertions:o.insertions,deletions:o.deletions})}return t},Jn=async(e={})=>{let t=await yt({repoRoot:e.repoRoot});return h(t)?t:T("Collected commits by ref",Hs(t.value))};var ks="Filed here",Xn=(e,t)=>e.set(t,(e.get(t)??0)+1),zn=(e,t,o)=>[...e.entries()].map(([n,s])=>({laneId:n,title:n===null?ks:o(n),count:s,share:t===0?0:s/t})).sort((n,s)=>s.count-n.count||n.title.localeCompare(s.title)),Qn=(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++,Xn(n,f[y-1]??null);let g=f[y+1];g!==void 0&&(r++,Xn(s,g))}return{arrived:u,departed:r,arrivesFrom:zn(n,u,o),movesOnTo:zn(s,r,o)}};var Ve=1440*60*1e3,Ws=({laneIds:e,journeys:t,now:o,days:n})=>{let s=o-(n-1)*Ve,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)/Ve)),d=g===void 0?n-1:Math.min(n-1,Math.ceil((g-s)/Ve)-1);for(let a=l;a<=d;a++)p[a].push(s+a*Ve-y.enteredAt)}return Object.fromEntries([...u].map(([r,f])=>[r,f.map((y,p)=>({t:s+p*Ve,median:Bn(y.sort((g,l)=>g-l)),count:y.length}))]))},Zn=({laneId:e,journeys:t,now:o,days:n})=>Ws({laneIds:[e],journeys:t,now:o,days:n})[e];var Vs=40,Ks=30,Ys=()=>({tickets:0,commits:0,insertions:0,deletions:0}),qs=async(e,t)=>{let o=Ys();for(let n of t.slice(0,Vs)){let s=await Ct({repoRoot:e,idOrRef:de(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},ei=async e=>{let t=kr();if(h(t))return t;let{nodes:o}=t.value;if(!o[e.swimlaneId])return G("Swimlane not found");let s=Object.values(o).filter(ct),u=s.map(y=>Dr(y.log??[],ro(y.id))),r=Qn(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:ro(e.swimlaneId),...r,stayTrend:Zn({laneId:e.swimlaneId,journeys:u,now:Date.now(),days:Ks}),code:await qs(e.repoRoot,f)})};var ti=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:rule:set","swimlane:delete","swimlane:move","issues:move","issue:close","issue:reopen","issue:edit:title","issue:edit:description","issue:tag:add","issue:tag:remove","issue:goal:set","goal:create","goal:rename","goal:remove","contributor:remove","tag:remove","issue:assignee:add","issue:assignee:remove","issue:comment:add","issue:comment:delete"]);var oi=e=>{let t=Ge({exclude:e});return h(t)?[]:t.value.map(o=>({projectId:o.projectId,name:dt(o.root),root:o.root,lastOpenedAt:o.lastOpenedAt}))},ri=e=>{let t=Ge();if(h(t))return G(t.message);let o=t.value.find(n=>n.root===e);return o?T("Resolved recent project",o.root):G(`Not a recent project: ${e}`)};import{z as c}from"zod";var v=c.string().min(1),ni=c.discriminatedUnion("at",[c.object({at:c.literal("start")}),c.object({at:c.literal("end")}),c.object({at:c.literal("before"),sibling:v}),c.object({at:c.literal("after"),sibling:v})]),ae=c.number().finite(),w=(e,t)=>c.object({type:c.literal(e),payload:t}),le=e=>c.object({type:c.literal(e)}),Js=c.discriminatedUnion("type",[le("state:get"),le("issues:list"),le("sync"),le("time-travel:live"),le("diff-stats:get"),w("project:open",c.object({root:c.string().min(1)})),w("issues:create",c.object({title:c.string(),parentId:v,description:c.string().optional(),tagNames:c.array(c.string()).optional()})),w("board:create",c.object({title:c.string()})),w("board:edit:title",c.object({boardId:v,title:c.string()})),w("swimlane:create",c.object({title:c.string(),boardId:v})),w("swimlane:edit:title",c.object({swimlaneId:v,title:c.string()})),w("board:edit:description",c.object({boardId:v,description:c.string()})),w("swimlane:edit:description",c.object({swimlaneId:v,description:c.string()})),w("swimlane:rule:set",c.object({swimlaneId:v,rule:c.string().min(1).max(64),on:c.boolean()})),w("swimlane:delete",c.object({swimlaneId:v})),w("swimlane:move",c.object({swimlaneId:v,boardId:v,position:ni.optional()})),w("issues:move",c.object({issueId:v,parentId:v,position:ni.optional()})),w("issue:edit:title",c.object({issueId:v,title:c.string()})),w("issue:edit:description",c.object({issueId:v,description:c.string()})),w("issue:tag:add",c.object({issueId:v,tagName:c.string()})),w("issue:goal:set",c.object({issueId:v,goal:v.nullable()})),w("goal:create",c.object({name:c.string(),issueId:v.optional()})),w("goal:rename",c.object({goalId:v,name:c.string()})),w("goal:remove",c.object({goalId:v})),w("issue:tag:remove",c.object({issueId:v,tagId:v})),w("contributor:remove",c.object({contributorId:v})),w("tag:remove",c.object({tagId:v})),c.object({type:c.literal("contributors:get"),payload:c.object({boardId:v.optional()}).optional()}),w("issue:assignee:add",c.object({issueId:v,assigneeId:v.optional(),assigneeName:c.string().optional(),createUnlinked:c.boolean().optional()})),w("issue:assignee:remove",c.object({issueId:v,assigneeId:v})),w("issue:close",c.object({issueId:v})),w("issue:reopen",c.object({issueId:v})),w("issue:comment:add",c.object({issueId:v,body:c.string()})),w("issue:comment:delete",c.object({issueId:v,commentId:v})),w("issue:comment:edit",c.object({issueId:v,commentId:v,body:c.string()})),w("issue:get",c.object({issueId:v})),w("issue:preview:get",c.object({issueId:v})),c.object({type:c.literal("timeline:get"),payload:c.object({start:ae.optional(),end:ae.optional(),boardId:v.optional(),requestId:c.number().finite().optional()}).optional()}),c.object({type:c.literal("commits:get"),payload:c.object({start:ae.optional(),end:ae.optional(),requestId:c.number().finite().optional()}).optional()}),w("time-travel:scrub",c.object({targetTime:ae})),w("time-travel:checkout-event",c.object({eventId:c.string().min(1)})),w("commit:inspect",c.object({sha:c.string(),repo:c.string().max(80).optional()})),le("repos:get"),w("repo:preview",c.object({url:c.string().min(1).max(mt),branches:c.enum(["default","all"]).optional(),since:c.string().max(20).optional(),label:c.string().max(24).optional()})),w("repo:preview:cancel",c.union([c.object({repo:c.string().min(1).max(80)}),c.object({url:c.string().min(1).max(mt)})])),w("repo:connect",c.object({url:c.string().min(1).max(mt),branches:c.enum(["default","all"]).optional(),since:c.string().max(20).optional(),label:c.string().max(24).optional()})),w("repo:disconnect",c.object({repo:c.string().min(1).max(2e3)})),c.object({type:c.literal("emails:get")}),w("email:link",c.object({email:c.string().min(1).max(254),contributorId:c.string().min(1).optional()})),w("email:unlink",c.object({email:c.string().min(1).max(254),contributorId:c.string().min(1).optional()})),w("commit:diff:get",c.object({sha:c.string(),repo:c.string().max(80).optional()})),w("issue:commits:get",c.object({issueId:v})),w("issue:squashed-diff:get",c.object({issueId:v,asOfTime:ae.optional()})),w("issue:stats:get",c.object({issueId:v,asOfTime:ae.optional()})),w("swimlane:stats:get",c.object({swimlaneId:v})),w("goal:stats:get",c.object({goalId:v,key:c.string().max(200),asOfTime:ae.optional()})),w("goal:commits:get",c.object({goalId:v,key:c.string().max(200),asOfTime:ae.optional()})),w("board:overview:get",c.object({boardId:v})),le("me:stats:get"),le("settings:get"),le("version:get"),w("settings:set",c.object({autoSync:c.boolean().optional(),autoSyncIntervalMs:c.number().finite().optional()}))]);var ii=e=>{let t=Js.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 Xs="https://registry.npmjs.org/epiq/latest",zs="https://api.github.com/repos/ljtn/epiq/releases?per_page=30",Qs="https://raw.githubusercontent.com/ljtn/epiq/main/install.sh";var si=new Map,fo=new Map;var yo=/^v?\d+\.\d+\.\d+$/,go=e=>e.replace(/^v/,""),Ne=(e,t)=>{let o=go(e).split(".").map(Number),n=go(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},Zs=()=>process.env.IS_CI==="true"||process.env.EPIQ_NO_UPDATE_CHECK==="1",ea=async e=>{try{let t=await fetch(e,{signal:AbortSignal.timeout(5e3),headers:{accept:"application/json"}});return t.ok?await t.json():null}catch{return null}},mi=(e,t=()=>!0)=>{let o=si.get(e);if(o&&Date.now()-o.at<o.ttl)return Promise.resolve(o.body);let n=fo.get(e);if(n)return n;let s=ea(e).then(u=>(si.set(e,{at:Date.now(),ttl:u!==null&&t(u)?864e5:36e5,body:u}),fo.delete(e),u));return fo.set(e,s),s},ho=async e=>{if(Zs())return{current:e,latest:null,updateAvailable:!1};let t=await mi(Xs),o=typeof t?.version=="string"&&yo.test(t.version)?t.version:null;return{current:e,latest:o,updateAvailable:o?Ne(o,e)>0:!1}},ta=e=>{let t=[],o=null;for(let n of e.replace(/\r/g,"").split(`
|
|
4
|
-
`)){let s=n.trimEnd();if(s.trim())if(/^[-*] /.test(s.trimStart())&&!/^\s{2,}/.test(s))o||(o={title:null,items:[]},t.push(o)),o.items.push(s.trimStart().slice(2).trim());else if(/^\s+/.test(s)&&o?.items.length)o.items[o.items.length-1]+=` ${s.trim()}`;else{if(yo.test(s.trim())&&t.length===0)continue;o={title:s.replace(/^#+\s*/,"").trim(),items:[]},t.push(o)}}return t.filter(n=>n.items.length>0)},oa=e=>{let t=e;return typeof t?.tag_name!="string"||!yo.test(t.tag_name)||t.draft||t.prerelease?null:{version:go(t.tag_name),url:typeof t.html_url=="string"?t.html_url:"",publishedAt:typeof t.published_at=="string"&&!Number.isNaN(Date.parse(t.published_at))?t.published_at:null,sections:typeof t.body=="string"?ta(t.body):[]}},ai=e=>Array.isArray(e)?e.map(oa).filter(t=>!!t):[],ra=async e=>ai(await mi(zs,t=>ai(t).some(o=>Ne(o.version,e)===0))),na=(e,t,o)=>e.filter(n=>Ne(n.version,t)>0&&Ne(n.version,o)<=0).sort((n,s)=>Ne(s.version,n.version)),li={script:`curl -fsSL ${Qs} | sh`,npm:"npm install --global epiq@latest"},ci=async e=>{let t=await ho(e);if(!t.updateAvailable||!t.latest)return{...t,releases:[],currentPublishedAt:null,commands:li};let o=await ra(t.latest);return{...t,releases:na(o,e,t.latest),currentPublishedAt:o.find(n=>Ne(n.version,e)===0)?.publishedAt??null,commands:li}};var sa=1024*1024,xo=()=>{ue({type:"state",payload:xe(Tt())})},di=()=>{ue({type:"repos:changed"})},bo=async(e,t)=>{aa(await Rn({repoRoot:e,minIntervalMs:t}))},aa=e=>{h(e)||(e.value.some(t=>t.changed)&&di(),e.value.some(t=>t.changed||!t.ok)&&ue({type:"repos:fetched"}))},S=(e,t)=>{e.send(JSON.stringify(t))},Ke=async(e,t)=>{let o=xe(await ee({repoRoot:t}));return h(o)&&o.message===Do?S(e,{type:"state:unavailable",payload:{message:o.message,repoRoot:t,recentProjects:oi(t)}}):S(e,{type:"state",payload:o})},la=async(e,t)=>{let o=()=>S(e,{type:"state",payload:xe(Tt())});if(ie().mode!=="live")return o();let n=await ee({repoRoot:t});return ie().mode!=="live"?o():S(e,{type:"state",payload:xe(n)})},E=async(e,t,o,n,s)=>{if(S(e,{type:n,payload:s}),h(s))return S(e,{type:"failed",payload:s.message});o(),la(e,t)},ui=(e,t,{onStateChanged:o,onSyncSettingsChanged:n,getPort:s})=>{new ia({server:e,path:"/ws",maxPayload:sa,verifyClient:r=>!po(r.origin,s())}).on("connection",r=>{fr(r),r.on("message",async f=>{let y=async l=>{let{type:d}=l,a=t.repoRoot;if(d==="project:open"){let i=ri(l.payload.root);return S(r,{type:"project:open:result",payload:i}),h(i)?void 0:(t.repoRoot=i.value,Ke(r,i.value))}if(d==="timeline:get"){let{requestId:i,...b}=l.payload??{};return S(r,{type:"timeline",requestId:i,payload:await Or({repoRoot:a,...b})})}if(d==="issue:get"){let i=l.payload?.issueId,b=Tt(),L=an(i);return S(r,{type:"issue",payload:h(b)?b:T("Issue detail",{...kn(b.value,i),history:h(L)?[]:L.value})})}if(d==="issue:preview:get"){let{issueId:i}=l.payload,b=en(i);return S(r,{type:"issue:preview:result",payload:{issueId:i,result:h(b)?b:T("Issue preview",Wn(i,b.value))}})}if(d==="commits:get"){let{requestId:i,...b}=l.payload??{};return S(r,{type:"commits",requestId:i,payload:io(await yt({repoRoot:a,...b}))})}if(d==="emails:get")return S(r,{type:"emails",payload:await so({repoRoot:a}),suggestions:await ao({repoRoot:a})});if(d==="email:link"||d==="email:unlink"){let b=await(d==="email:link"?Cn:Pn)({repoRoot:a,...l.payload});return S(r,{type:"emails",payload:await so({repoRoot:a}),suggestions:await ao({repoRoot:a}),lastAction:h(b)?{ok:!1,message:b.message}:{ok:!0,message:b.message}}),E(r,a,o,`${d}:result`,b)}if(d==="me:stats:get")return S(r,{type:"me:stats",payload:await An({repoRoot:a})});if(d==="version:get")return S(r,{type:"version",payload:await ci(F)});if(d==="settings:get")return S(r,{type:"settings",payload:no()});if(d==="settings:set"){let i=Nr({enabled:l.payload.autoSync,intervalMs:l.payload.autoSyncIntervalMs});return h(i)||n(),S(r,{type:"settings",payload:h(i)?no():i,lastAction:h(i)?{ok:!1,message:i.message}:{ok:!0,message:i.message}})}if(d==="commit:inspect")return S(r,{type:"commit:inspect:result",payload:await lr({repoRoot:a,sha:l.payload.sha,repo:l.payload.repo})});if(d==="commit:diff:get"){let{sha:i,repo:b}=l.payload;return S(r,{type:"commit:diff:result",payload:{sha:i,repo:b,result:await sr({repoRoot:a,sha:i,repo:b})}})}if(d==="repos:get"){let i=await nr(a);return S(r,{type:"repos",payload:await Ae({repoRoot:a}),own:i})}if(d==="repo:preview"){let i=await lo({repoRoot:a,...l.payload,previewOnly:!0});return S(r,{type:"repos",for:d,url:l.payload.url.trim(),payload:h(i)?await Ae({repoRoot:a}):i,preview:h(i)?null:i.value.preview??null,lastAction:{ok:!h(i),message:i.message}})}if(d==="repo:preview:cancel")return Mn(l.payload),S(r,{type:"repos",for:d,payload:await Ae({repoRoot:a}),preview:null});if(d==="repo:connect"||d==="repo:disconnect"){let i=d==="repo:connect"?await lo({repoRoot:a,...l.payload,confirm:!0}):await Nn({repoRoot:a,...l.payload});return S(r,{type:"repos",for:d,payload:h(i)?await Ae({repoRoot:a}):i,preview:null,lastAction:{ok:!h(i),message:i.message}}),h(i)?S(r,{type:`${d}:result`,payload:i}):(!h(i)&&i.message!==er&&!i.message.startsWith(tr)&&di(),E(r,a,o,`${d}:result`,i))}if(d==="issue:commits:get"){let{issueId:i}=l.payload;return S(r,{type:"issue:commits:result",payload:{issueId:i,result:await ir(a,io(await rr({repoRoot:a,ref:de(i)})))}})}if(d==="issue:squashed-diff:get"){let{issueId:i,asOfTime:b}=l.payload;return S(r,{type:"issue:squashed-diff:result",payload:{issueId:i,asOfTime:b??null,result:await ar({repoRoot:a,ref:de(i),end:b})}})}if(d==="issue:stats:get"){let{issueId:i,asOfTime:b}=l.payload;return S(r,{type:"issue:stats:result",payload:{issueId:i,asOfTime:b??null,result:await Ct({repoRoot:a,idOrRef:de(i),end:b})}})}if(d==="diff-stats:get")return S(r,{type:"diff-stats",payload:await Jn({repoRoot:a})});if(d==="swimlane:stats:get"){let{swimlaneId:i}=l.payload;return S(r,{type:"swimlane:stats:result",payload:{swimlaneId:i,result:await ei({repoRoot:a,swimlaneId:i})}})}if(d==="goal:stats:get"){let{goalId:i,key:b,asOfTime:L}=l.payload;return S(r,{type:"goal:stats:result",payload:{goalId:i,key:b,result:await yn({repoRoot:a,goal:i,end:L})}})}if(d==="goal:commits:get"){let{goalId:i,key:b,asOfTime:L}=l.payload;return S(r,{type:"goal:commits:result",payload:{goalId:i,key:b,result:await hn({repoRoot:a,goal:i,end:L})}})}if(d==="board:overview:get"){let{boardId:i}=l.payload;return S(r,{type:"board:overview:result",payload:{boardId:i,result:Ln({boardId:i})}})}if(d==="time-travel:scrub"){let i=await Ur({repoRoot:a,targetTime:l.payload.targetTime});return S(r,{type:"time-travel:result",payload:i}),h(i)?void 0:xo()}if(d==="time-travel:checkout-event"){let i=await Gr({repoRoot:a,eventId:l.payload.eventId});return S(r,{type:"time-travel:result",payload:i}),h(i)?void 0:xo()}if(d==="time-travel:live"){let i=await $r({repoRoot:a});return S(r,{type:"time-travel:result",payload:i}),h(i)?void 0:xo()}if(d==="state:get")return Ke(r,a);if(d==="sync"){let i=await Et({repoRoot:a});return S(r,{type:"sync:result",payload:i}),o(),h(i)||bo(a),Ke(r,a)}if(d==="issue:comment:add"){let i=await Pt({repoRoot:a,...l.payload});return E(r,a,o,"issue:comment:add:result",i)}if(d==="issue:comment:edit"){let i=await En({repoRoot:a,...l.payload});return E(r,a,o,"issue:comment:edit:result",i)}if(d==="issue:comment:delete"){let i=await At({repoRoot:a,...l.payload});return S(r,{type:"issue:comment:delete:result",payload:i}),h(i)?S(r,{type:"failed",payload:i.message}):(o(),Ke(r,a))}if(d==="issue:edit:description"){let i=await ln({repoRoot:a,...l.payload});return E(r,a,o,"issue:edit:description:result",i)}if(d==="issue:edit:title"){let i=await mn({repoRoot:a,...l.payload});return E(r,a,o,"issue:edit:title:result",i)}if(d==="issue:tag:add"){let i=await xn({repoRoot:a,...l.payload});return E(r,a,o,"issue:tag:add:result",i)}if(d==="issue:goal:set")return E(r,a,o,"issue:goal:set:result",await Kr({repoRoot:a,...l.payload}));if(d==="goal:create")return E(r,a,o,"goal:create:result",await Yr({repoRoot:a,...l.payload}));if(d==="goal:rename")return E(r,a,o,"goal:rename:result",await qr({repoRoot:a,...l.payload}));if(d==="goal:remove")return E(r,a,o,"goal:remove:result",await Jr({repoRoot:a,...l.payload}));if(d==="issue:tag:remove"){let i=await wn({repoRoot:a,...l.payload});return E(r,a,o,"issue:tag:remove:result",i)}if(d==="contributor:remove"){let i=await Sn({repoRoot:a,...l.payload});return E(r,a,o,"contributor:remove:result",i)}if(d==="tag:remove"){let i=await bn({repoRoot:a,...l.payload});return E(r,a,o,"tag:remove:result",i)}if(d==="contributors:get")return S(r,{type:"contributors",boardId:l.payload?.boardId,payload:await In({repoRoot:a,...l.payload})});if(d==="issue:assignee:add"){let i=await vn({repoRoot:a,...l.payload});return E(r,a,o,"issue:assignee:add:result",i)}if(d==="issue:assignee:remove"){let i=await Tn({repoRoot:a,...l.payload});return E(r,a,o,"issue:assignee:remove:result",i)}if(d==="issues:list")return S(r,{type:"issues",payload:await tn({repoRoot:a})});if(d==="issues:create"){let i=await on({...l.payload,repoRoot:a});return S(r,{type:"issues:create:result",payload:i}),h(i)?ue({type:"failed",payload:i.message}):(o(),Ke(r,a))}if(d==="board:create"){let i=await cn({...l.payload,repoRoot:a});return E(r,a,o,"board:create:result",i)}if(d==="board:edit:title"){let i=await dn({...l.payload,repoRoot:a});return E(r,a,o,"board:edit:title:result",i)}if(d==="swimlane:create"){let i=await un({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:create:result",i)}if(d==="swimlane:edit:title"){let i=await pn({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:edit:title:result",i)}if(d==="board:edit:description"){let i=await Wr({...l.payload,repoRoot:a});return E(r,a,o,"board:edit:description:result",i)}if(d==="swimlane:edit:description"){let i=await Vr({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:edit:description:result",i)}if(d==="swimlane:rule:set"){let i=await Xr({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:rule:set:result",i)}if(d==="swimlane:delete"){let i=await gn({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:delete:result",i)}if(d==="swimlane:move"){if(!l.payload.position)return S(r,{type:"error",message:"Missing move position"});let i=await fn({...l.payload,repoRoot:a});return E(r,a,o,"swimlane:move:result",i)}if(d==="issues:move"){if(!l.payload.position)return S(r,{type:"error",message:"Missing move position"});let i=await sn({...l.payload,repoRoot:a});return E(r,a,o,"issues:move:result",i)}if(d==="issue:close"){let i=await rn({repoRoot:a,issueId:l.payload.issueId});return E(r,a,o,"issue:close:result",i)}if(d==="issue:reopen"){let i=await nn({repoRoot:a,issueId:l.payload.issueId});return E(r,a,o,"issue:reopen:result",i)}return S(r,{type:"error",message:"Unknown message type"})},p,g=async l=>{if(p!=="repo:connect"&&p!=="repo:disconnect"&&p!=="repo:preview")return S(r,{type:"error",message:l});S(r,{type:"repos",for:p,payload:await Ae({repoRoot:t.repoRoot}),preview:null,lastAction:{ok:!1,message:l}}),p!=="repo:preview"&&S(r,{type:`${p}:result`,payload:G(l)})};try{let l=JSON.parse(f.toString());p=l?.type;let d=ii(l);if(!d.ok)return await g(d.error);let a=d.message;return ti.has(a.type)?await pe(async()=>ie().mode!=="live"?S(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 pa=be.dirname(ua(import.meta.url)),fa=process.env.IS_LOCAL==="true"?be.resolve(process.cwd(),"dist/gui"):be.join(pa,"gui"),Lt,ga=async()=>(Lt===void 0&&(Lt=await import("node:sea").catch(()=>null)),Lt?.isSea()?Lt:null),R=(e,t,o)=>{e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(o))},ya=e=>R(e,409,{isError:!0,message:"Read-only while viewing history"}),jt=(e,t)=>pe(async()=>ie().mode!=="live"?ya(e):t()),pi=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)}),ha=2*1024*1024,xa={png:"image/png",jpg:"image/jpeg",gif:"image/gif",webp:"image/webp"},ba=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":e.endsWith(".woff2")?"font/woff2":"application/octet-stream",fi=new Map,wa=e=>`"${ca("sha1").update(e).digest("base64url")}"`,va=async e=>{try{let{size:t,mtimeMs:o}=await ma(e);return`${t}:${o}`}catch{return null}},Sa=e=>{try{return decodeURIComponent(e)}catch{return null}},gi=async(e,t,o)=>{let n=e==="/"?"/index.html":Sa(e);if(n===null)return R(o,404,{isError:!0,message:"Not found"});let s=n.replace(/^\/+/,""),u=be.resolve(fa),r=be.resolve(u,s),f=be.relative(u,r);if(f.startsWith("..")||be.isAbsolute(f))return R(o,403,{isError:!0,message:"Forbidden"});let y=await ga(),p=y?"sea":await va(r),g=p===null?void 0:fi.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 yi(r),a=l??wa(d);return p!==null&&fi.set(f,{stamp:p,etag:a}),o.writeHead(200,{"content-type":ba(r),etag:a,"cache-control":"no-cache"}),o.end(d)}catch{return R(o,404,{isError:!0,message:`Not found: ${s}`})}},Ia=async(e,t=We)=>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)}),hi=async e=>{_r(!1);let t=0,o={repoRoot:e.repoRoot},n=da.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():R(g,500,{isError:!0,message:"Internal error"})))});async function s(p,g){let l=new URL(p.url??"/","http://127.0.0.1"),d=qn({method:p.method,origin:p.headers.origin,contentType:p.headers["content-type"]},t);if(d)return R(g,d.status,{isError:!0,message:d.message});if(p.method==="GET"&&l.pathname===co)return R(g,200,{app:uo,repoRoot:Rt(o.repoRoot),version:F,pid:process.pid});if(l.pathname==="/api/state")return R(g,200,await ee({repoRoot:o.repoRoot}));if(p.method==="POST"&&l.pathname==="/api/comments")try{let a=await pi(p);if(!a.issueId||!a.body?.trim())return R(g,400,{isError:!0,message:"Missing issueId or body"});let i=a.issueId,b=a.body;return await jt(g,async()=>{let L=await Pt({repoRoot:o.repoRoot,issueId:i,body:b});return h(L)?R(g,400,{isError:!0,message:L.message}):R(g,200,await ee({repoRoot:o.repoRoot}))})}catch(a){return R(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 pi(p,ha);if(!a.issueId||!a.dataBase64)return R(g,400,{isError:!0,message:"Missing issueId or dataBase64"});let i=a.issueId,b=a.dataBase64,L=a.name??"";return await jt(g,async()=>{let D=await zr({repoRoot:o.repoRoot,issueId:i,name:L,dataBase64:b});return h(D)?R(g,400,{isError:!0,message:D.message}):R(g,200,{...await ee({repoRoot:o.repoRoot}),attachment:D.value})})}catch(a){return R(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?jt(g,async()=>{let i=await Qr({repoRoot:o.repoRoot,attachmentId:a});return h(i)?R(g,400,{isError:!0,message:i.message}):R(g,200,await ee({repoRoot:o.repoRoot}))}):R(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 Zr({repoRoot:o.repoRoot,fileName:a});if(h(i))return R(g,404,{isError:!0,message:i.message});try{let b=await yi(i.value.filePath);return g.writeHead(200,{"content-type":xa[i.value.ext]??"application/octet-stream","cache-control":"public, max-age=31536000, immutable"}),g.end(b)}catch{return R(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?jt(g,async()=>{let i=await At({repoRoot:o.repoRoot,commentId:a});return h(i)?R(g,400,{isError:!0,message:i.message}):R(g,200,await ee({repoRoot:o.repoRoot}))}):R(g,400,{isError:!0,message:"Missing comment id"})}return l.pathname.startsWith("/board/")||l.pathname==="/log"?gi("/",p,g):gi(l.pathname,p,g)}try{t=await Ia(n)}catch(p){return G(p instanceof Error?`Unable to start GUI server: ${p.message}`:`Unable to start GUI server: ${String(p)}`)}let u=Kn({project:o}),r=Fn({project:o,publisher:u,onReposFetch:p=>bo(o.repoRoot,p)}),f=Yn(u);ui(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(),G("Unable to resolve GUI server address")):T("Started GUI server",{url:`http://epiq.localhost:${y.port}${e.boardId?`/board/${e.boardId}`:""}`,server:n})};var xi=async e=>{let t=f=>{e.open!==!1&&On()&&Un(f)},o=it({});if(h(o))return G(o.message);let n=Ie();$(n)&&Ue(n.value);let s=await $n(We);if(s&&s.repoRoot===Rt(e.repoRoot)){let f=`http://127.0.0.1:${We}`;return console.log(mo({url:f,repoRoot:e.repoRoot,version:F,reused:!0})),t(f),T("Reused running GUI",{url:f})}let u=await hi({repoRoot:e.repoRoot,boardId:""});if(h(u))return u;let{url:r}=u.value;return console.log(mo({url:r,repoRoot:e.repoRoot,version:F,reused:!1})),t(r),T("Started GUI",{url:r})};import{Box as ce}from"ink";import M from"react";import{Box as wo,Text as Ye}from"ink";import te,{useEffect as Ta,useMemo as Ea}from"react";import{ulid as Ca}from"ulid";var bi=({text:e,match:t,color:o,highlightColor:n=m.secondary,dimColor:s=!1})=>{if(!t)return te.createElement(Ye,{color:o,dimColor:s},e);let u=e.toLowerCase(),r=t.toLowerCase(),f=u.indexOf(r);return f===-1?te.createElement(Ye,{color:o,dimColor:s},e):te.createElement(Ye,{color:o,dimColor:s},e.slice(0,f),te.createElement(Ye,{backgroundColor:n,bold:!0},e.slice(f,f+t.length)),e.slice(f+t.length))},wi=Ca(),Pa=e=>`${e}`,Aa=e=>{let{pendingNavTarget:t}=Sr();if(!t)return[];let{breadCrumb:o,contextNode:n,selectedNode:s}=t,u=new Set(Qo(ft.NONE,{breadCrumb:o,contextNode:n,readOnly:Q().readOnly,selectedNode:s}));return[...new Set(Object.values(ft))].filter(r=>r!=="move").filter(r=>r.length>0).filter(r=>r!==ft.PALETTE).map(r=>{let f=hr(r),y=Mr.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))},Na=e=>Ee.text({id:wi,parentNodeId:e,rank:"000000",name:"Command Palette",readonly:!0,isVirtual:!0}),Ma=(e,t,o)=>Ee.text({id:Pa(e.command),parentNodeId:o,rank:String(t).padStart(6,"0"),name:e.command,disabled:!e.isAvailable,readonly:!0,isVirtual:!0}),vo=[],Ra=e=>{vi();let t=q.createNode(Na(Q().rootNodeId));h(t)||!Te(t.value)||(vo=[t.value,...e.map((o,n)=>Ma(o,n,wi)).map(q.createNode).filter($).map(({value:o})=>o).filter(Te)],Ce.navigate({contextNode:t.value,selectedIndex:0}))},vi=()=>{let e=vo.map(t=>t.id);vo=[];for(let t of e)q.deleteNode(t)};function Si({width:e,height:t}){let n=ur().value.trim().toLowerCase(),s=Ea(()=>Aa(n),[n]);Ta(()=>(Ra(s),()=>{vi()}),[s]);let u=Q().selectedIndex;return te.createElement(wo,{flexDirection:"column",width:e,height:t-2},te.createElement(wt,{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(wo,{key:r.command,flexDirection:"column",paddingX:1,borderLeft:!1,borderBottom:!1,borderRight:!1,borderColor:m.secondary,borderStyle:"single"},te.createElement(Ye,{color:p,dimColor:!r.isAvailable},y?"\u276F ":" ",te.createElement(bi,{text:zo(r.command),match:n,color:p,dimColor:!r.isAvailable})),te.createElement(wo,{paddingLeft:2},te.createElement(bi,{text:g+r.description,match:n.length>=2?n:"",color:y&&r.isAvailable?m.primary:m.secondary2,dimColor:!r.isAvailable})))})))}import{Box as Ka}from"ink";import Ot from"react";import Je from"chalk";import{Box as qe,Text as Ci}from"ink";import we,{useEffect as Pi,useMemo as Ba,useState as Ai}from"react";var Me=["\u2803","\u2806","\u2830","\u2818"],Ii=120,Ti=({isPalette:e,isPending:t,frame:o})=>{if(t){let n=(o%Me.length+Me.length)%Me.length;return Me[n]}return e?"?":":"},Ei=({infoMessage:e,isPending:t})=>t&&e.includes(cr)?"":e;var Ni=Je.hex(m.secondary),La=Je.inverse,ja=Je.inverse.hex(m.secondary2),_a={hint:"",hints:[],overlap:0,remainder:""},Ri=({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}},Da=({command:e,modifier:t})=>{if(!t)return null;if(e==="tag"||e==="assign"){let o=Go(t);return{bg:n=>Je.bgHex(o).black(n),bgCursor:n=>Je.bgHex(o).inverse.black(n)}}return oo(t)},Oa=({value:e,command:t,modifier:o})=>{if(!t||!o)return null;let n=Ri({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}},Mi=()=>({value:ne.value,cursorPosition:ne.cursorPosition,commandIsPending:ne.commandIsPending,autoCompletion:ne.commandMeta.autoCompletion??_a,infoMessage:ne.commandMeta.infoMessage,validationStatus:ne.commandMeta.validity,command:ne.commandMeta.command,inputString:ne.commandMeta.inputString,modifier:ne.commandMeta.modifier}),Ua=(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,Bi=({width:e,mode:t})=>{let[o,n]=Ai(Mi());Pi(()=>{let B=()=>{let C=Mi();n(I=>Ua(I,C)?I:C)},P=dr(B);return B(),()=>{P()}},[]);let{value:s,cursorPosition:u,infoMessage:r,commandIsPending:f,autoCompletion:y,command:p,modifier:g,validationStatus:l}=o,d=f&&l===mr.Invalid,a=Ei({infoMessage:r,isPending:f}),[i,b]=Ai(0);Pi(()=>{if(!f){b(0);return}let B=setInterval(()=>{b(P=>(P+1)%Me.length)},Ii);return()=>{clearInterval(B)}},[f]);let L=Ti({isPalette:t===H.PALETTE,isPending:f,frame:i}),D=Ba(()=>{let B=Math.max(0,Math.min(u,s.length)),P=Ri({value:s,command:p}),C=Oa({value:s,command:p,modifier:g}),I=p?oo(p):null,V=Da({command:p,modifier:g}),Se=(K,Y)=>{let eo=P&&Y>=P.start&&Y<P.end,to=C&&Y>=C.start&&Y<C.end;return eo&&I?I.fg(K):to&&V?V.bg(K):K},De=(K,Y)=>{let eo=P&&Y>=P.start&&Y<P.end,to=C&&Y>=C.start&&Y<C.end;return eo&&I?I.fgCursor(K):to&&V?V.bgCursor(K):La(K)},he=s.slice(0,B),Z=s[B]??" ",Oe=B<s.length?s.slice(B+1):"",nt=Array.from(he).map((K,Y)=>Se(K,Y)).join(""),Bo=De(Z,B),Lo=Array.from(Oe).map((K,Y)=>Se(K,B+1+Y)).join("");if(y.hint){let K=y.hint[y.overlap]??Z;Bo=ja(K),Lo=Ni(y.remainder.slice(1)+Oe)}return nt+Bo+Lo},[s,u,y,p,g]);return we.createElement(qe,{flexDirection:"column",justifyContent:"flex-start"},we.createElement(qe,{flexDirection:"column",paddingX:1,borderColor:m.secondary,borderStyle:"round",width:e},we.createElement(qe,{height:1,flexWrap:"nowrap"},we.createElement(qe,{flexShrink:0},we.createElement(Ci,{wrap:"truncate-start"},Ni(L),D)),a&&we.createElement(qe,{flexShrink:1,minWidth:0},we.createElement(Ci,{wrap:"truncate",color:d?m.red:m.secondary2},` ${a} `)))))};import{Box as Ga,Text as Xe}from"ink";import Re from"react";var Li=" ",$a=({keys:e,label:t})=>e.length+1+t.length,Fa=(e,t)=>{let o=[],n=0;for(let s of e){let r=(o.length>0?Li.length:0)+$a(s);if(n+r>t-4)break;o.push(s),n+=r}return o},ji=({width:e,availableHints:t})=>{let o=Fa(t,e);return Re.createElement(Ga,{width:e,borderStyle:"round",borderColor:m.secondary,paddingX:1},o.length?Re.createElement(Xe,{wrap:"truncate"},o.map(({keys:s,label:u},r)=>Re.createElement(Xe,{key:`${s}-${u}`},r>0?Li:"",Re.createElement(Xe,{color:m.accent},s),Re.createElement(Xe,{color:m.secondary2}," ",u)))):Re.createElement(Xe,{color:m.secondary2},"\xA0"))};import{Box as Ha,Text as _t}from"ink";import ze,{useEffect as ka,useRef as Be,useState as Wa}from"react";var Va=40,Dt=.3,So="\u2500",_i=1,Di=16,Oi=({width:e})=>{let{replay:t}=O(),o=t!==null,n=t?Math.min(1,Math.max(0,t.progress)):0,u=Math.max(4,e-6),r=u*_i,[f,y]=Wa(0),p=Be(n);p.current=n;let g=Be(0),l=Be(0),d=Be(0),a=Be(0),i=Be(0);if(ka(()=>{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 P=setInterval(()=>{let C=Date.now(),I=p.current;if(I!==d.current){let Z=I-d.current,Oe=C-l.current;if(Z<0)a.current=0,i.current=0;else if(Z>0&&Oe>0){let nt=Z/Oe;a.current=a.current===0?nt:a.current*(1-Dt)+nt*Dt,i.current=i.current===0?Z:i.current*(1-Dt)+Z*Dt}g.current=I,l.current=C,d.current=I}let V=C-l.current,Se=Math.min(i.current,a.current*V),De=Math.min(1,g.current+Se),he=Math.round(De*r);y(Z=>Z===he?Z:he)},Va);return()=>clearInterval(P)},[o,r]),!t)return null;let b=P=>{let C=u>1?P/(u-1):0,I=Math.round(C*(Di-1))/(Di-1);return Ho(I)},L=Math.min(u,Math.floor(f/_i)),D=[];for(let P=0;P<L;P++){let C=b(P),I=D[D.length-1];I&&I.color===C?I.text+=So:D.push({text:So,color:C})}let B=So.repeat(Math.max(0,u-L));return ze.createElement(Ha,{width:e,borderStyle:"round",borderColor:m.secondary,paddingX:1,columnGap:1},ze.createElement(_t,{color:m.secondary2},"\u25B6"),ze.createElement(_t,null,D.map((P,C)=>ze.createElement(_t,{key:C,color:P.color},P.text)),ze.createElement(_t,{color:m.secondary,dimColor:!0},B)))};var Qe=({width:e,mode:t,availableHints:o})=>{let{timeMode:n}=O(),s=t===H.COMMAND_LINE||t===H.PALETTE;return Ot.createElement(Ka,null,s?Ot.createElement(Bi,{width:e,mode:t}):n==="replay"?Ot.createElement(Oi,{width:e}):Ot.createElement(ji,{width:e,mode:t,availableHints:o}))};import{Box as fe,Text as Le}from"ink";import k,{useEffect as Ya,useMemo as qa}from"react";import{ulid as Ui}from"ulid";var Gt=Ui(),Ja=()=>[...new Set([...Q().availableActions].map(e=>e.description).filter(e=>e!==void 0))].map(Rr).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})),Xa=e=>Ee.text({id:Gt,parentNodeId:e,rank:"000000",name:"Help",isVirtual:!0,readonly:!0}),za=(e,t,o)=>Ee.text({id:Ui(),parentNodeId:o,rank:String(t).padStart(6,"0"),name:e.keys,readonly:!0,isVirtual:!0}),Ut=[],Gi=()=>{let e=Ut.filter(o=>o.id!==Gt).map(o=>o.id),t=Ut.filter(o=>o.id===Gt).map(o=>o.id);Ut=[];for(let o of[...e,...t])q.deleteNode(o)},Qa=e=>{Gi();let t=q.createNode(Xa(Q().rootNodeId));if(h(t)||!Te(t.value))return logger.error("Could not attach help nodes");Ut=[t.value,...e.map((o,n)=>za(o,n,Gt)).map(q.createNode).filter($).map(({value:o})=>o).filter(Te)],Ce.navigate({contextNode:t.value,selectedIndex:0})},$i=({width:e,height:t})=>{let o=qa(()=>Ja(),[]);Ya(()=>(Qa(o),()=>{Gi()}),[o]);let n=Q().selectedIndex;return k.createElement(fe,{flexDirection:"column",marginTop:3,borderColor:m.secondary,borderStyle:"round",width:e,height:t-2},k.createElement(fe,{paddingX:1,justifyContent:"center"},k.createElement(Le,{color:m.accent},"Help"),k.createElement(Le,{dimColor:!0}," \u2014 navigate with arrows/hjkl, press q to close")),k.createElement(fe,{paddingX:1,marginTop:1},k.createElement(fe,{width:20,justifyContent:"flex-end"},k.createElement(Le,{color:m.secondary},"Key(s)")),k.createElement(fe,{flexGrow:1,width:40,paddingLeft:2},k.createElement(Le,{color:m.secondary},"Action"))),k.createElement(wt,{height:t-7,itemHeight:1,selectedIndex:n},o.map(({keys:s,action:u},r)=>{let f=r===n;return k.createElement(fe,{paddingX:1,key:`${s}-${u}-${r}`,flexDirection:"row"},k.createElement(fe,{width:20,justifyContent:"flex-end"},k.createElement(Le,{color:m.accent},s)),k.createElement(fe,{flexGrow:1,width:40,paddingLeft:2},k.createElement(Le,{color:f?m.primary:m.secondary2},u)))})))};import{Box as je,Text as W}from"ink";import A,{useEffect as Za,useState as Io}from"react";var $t=({index:e,email:t,note:o,noteColor:n})=>A.createElement(je,null,A.createElement(W,{color:m.accent},e===void 0?" ":` ${e}.`),A.createElement(W,null," ",t),o&&A.createElement(W,{color:n??m.secondary2},` ${o}`)),Fi=({height:e})=>{let[t,o]=Io([]),[n,s]=Io([]),[u,r]=Io(null),{userName:f,gitEmail:y,gitName:p,userId:g}=re();return Za(()=>{let l=!0;return(async()=>{let a=Pe(),i=oe(process.cwd());if(h(a)||h(i)||!g)return;let b=a.value.emailLinks,L=Ko(b,g);o(L.map(C=>({email:C,others:Vo(b,C).filter(I=>I!==g).map(I=>a.value.contributors[I]?.name??I)})));let D=at(i.value),B=await St({repoRoot:i.value,stateBranch:h(D)?void 0:D.value,names:[f,p],links:b});if(!l)return;if(h(B)){r(B.message);return}let P=It(B.value);ut(P.map(C=>C.email)),s(P)})(),()=>{l=!1}},[g,f,p,y]),A.createElement(je,{height:e-4,flexDirection:"column",paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},A.createElement(je,null,A.createElement(W,{color:m.accent,bold:!0},f??"Not configured"),A.createElement(W,{color:m.secondary2}," on this board")),u&&A.createElement(W,{color:m.red},u),A.createElement(je,{flexDirection:"column"},A.createElement(W,{color:m.secondary2},"CLAIMED"),t.length===0?A.createElement($t,{email:"Nothing claimed \u2014 your commits show the name git signed them with.",note:""}):t.map(l=>A.createElement($t,{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}))),A.createElement(je,{flexDirection:"column"},A.createElement(W,{color:m.secondary2},"UNCLAIMED IN THIS HISTORY"),n.length===0?A.createElement($t,{email:"Nothing left to claim here."}):n.map(l=>A.createElement($t,{key:l.email,email:l.email,note:`${l.commits} commit${l.commits===1?"":"s"} as ${l.names.join(", ")||"unknown"}`}))),A.createElement(je,{flexDirection:"column"},A.createElement(W,{color:m.secondary2},A.createElement(W,{color:m.accent},"[enter]")," writes a claim for the first into the command line, to confirm or change."),A.createElement(W,{color:m.secondary2},A.createElement(W,{color:m.accent},":config emails")," claims by address,",A.createElement(W,{color:m.accent}," :config emails-unclaim "),"gives one back."),A.createElement(W,{color:m.secondary2},A.createElement(W,{color:m.accent},"[esc]")," to close")))};import el from"chalk";import{Box as ve,Text as U}from"ink";import N from"react";var tl=8,ol=()=>{let e=Ge({exclude:process.cwd()});return h(e)?[]:e.value.slice(0,tl)},Hi=({width:e,height:t})=>{let o=ol();return N.createElement(ve,{height:t-4,flexDirection:"column",width:e,paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},N.createElement(U,{color:m.accent,bold:!0},"Initialize project"),N.createElement(U,null,`This folder is not an ${el.hex(m.accent)("epiq")} project yet.`),N.createElement(U,{color:m.primary},"To start tracking issues here, we need to initialize a new",N.createElement(U,{color:m.primary,backgroundColor:m.secondary}," .epiq/project.json "),"file in this repository."),N.createElement(ve,{marginTop:1,flexDirection:"column"},N.createElement(ve,null,N.createElement(U,{color:m.accent}," "),N.createElement(U,{color:m.primary},"Type "),N.createElement(U,{backgroundColor:m.secondary}," :init "))),N.createElement(ve,{marginTop:1},N.createElement(U,{color:m.secondary2},"This will create, commit and push "),N.createElement(U,{color:m.primary,backgroundColor:m.secondary}," .epiq/project.json ")),o.length>0&&N.createElement(ve,{marginTop:1,flexDirection:"column"},N.createElement(U,{color:m.accent,bold:!0},"Or open a recent project"),o.map((n,s)=>N.createElement(ve,{key:n.projectId},N.createElement(U,{color:m.accent},` ${s+1} `),N.createElement(U,{color:m.primary},dt(n.root)),N.createElement(U,{color:m.secondary2},` ${n.root}`))),N.createElement(ve,{marginTop:1},N.createElement(U,{color:m.accent}," "),N.createElement(U,{color:m.primary},"Type "),N.createElement(U,{backgroundColor:m.secondary}," :open 1 "),N.createElement(U,{color:m.secondary2}," or "),N.createElement(U,{backgroundColor:m.secondary}," :open <path> "))))};import{Box as Ht,Text as X}from"ink";import j from"react";import{Box as Ft,Text as me}from"ink";import J,{useEffect as rl,useState as ki}from"react";var Wi=()=>{let[e,t]=ki(null),[o,n]=ki(null);return rl(()=>{let s=!0;return(async()=>{let r=Pe(),f=oe(process.cwd());if(h(r)||h(f))return;let y=at(f.value),{userName:p,gitName:g}=re(),l=await St({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=It(l.value);ut(d.map(a=>a.email)),t(d)})(),()=>{s=!1}},[]),o?J.createElement(Ft,{marginTop:1},J.createElement(me,{color:m.red},o)):e===null?null:e.length===0?J.createElement(Ft,{marginTop:1},J.createElement(me,{color:m.secondary2},"No unclaimed addresses in this history \u2014 type",J.createElement(me,{color:m.accent}," :config emails none "),"to move on.")):J.createElement(Ft,{flexDirection:"column",marginTop:1},e.map(s=>J.createElement(me,{key:s.email},J.createElement(me,{color:m.accent}," \xB7 "),J.createElement(me,null,s.email),J.createElement(me,{color:m.secondary2},` ${s.commits} commit${s.commits===1?"":"s"} as ${s.names.join(", ")||"unknown"}`))),J.createElement(Ft,{marginTop:1},J.createElement(me,{color:m.secondary2},"Claim yours by address, or",J.createElement(me,{color:m.accent}," none "),"to skip.")))};var nl=({isDone:e,command:t,value:o,verb:n="Type",hint:s})=>j.createElement(Ht,null,j.createElement(X,{color:m.accent,dimColor:e},e?" \u2714 ":" "),j.createElement(X,{dimColor:e},n," "),j.createElement(X,{backgroundColor:m.secondary,dimColor:e}," "+t+" "),o!==void 0&&j.createElement(j.Fragment,null,j.createElement(X,{dimColor:e}," "),j.createElement(X,{color:m.secondary,dimColor:e},"<"+o+">")),s),il=(e,t)=>e.length===0?void 0:Jo(e.join(", "),Math.max(12,t-34)),sl=e=>{if(typeof e=="string")return e;if(typeof e=="boolean")return e?"on":"off"};function To({width:e,height:t}){let{isSetPreferredEditor:o,isSetUserName:n,userName:s,preferredEditor:u,autoSync:r,isSetAutoSync:f,isSetEmails:y,claimedEmails:p,emailSetupDeclined:g}=pt(),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":il(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 j.createElement(Ht,{height:t-4,flexDirection:"column",width:e,paddingTop:1,paddingLeft:2,borderStyle:"round",borderColor:m.secondary,rowGap:1},j.createElement(X,{color:m.accent,bold:!0},"Welcome! \u{1F539}"),j.createElement(X,null,"Let's get you started - it's a breeze."),j.createElement(X,{color:m.secondary2},"Remember - you can always search available commands by typing:",j.createElement(X,{color:m.accent}," ? ")),a&&j.createElement(X,{color:m.secondary2},a.message),j.createElement(Ht,{flexDirection:"column"},l.map((i,b)=>{if(!(d===-1||b<=d))return null;let D=b===d,B=D&&d===0;return j.createElement(Ht,{key:i.key,flexDirection:"column",marginBottom:1},j.createElement(nl,{isDone:i.done,command:B?":config us":i.command,value:i.done?sl(i.value):void 0,verb:D&&!B?"Waiting:":"Type",hint:B?j.createElement(X,{color:m.secondary2}," then ",j.createElement(X,{color:m.accent},"tab")," to auto-complete ",j.createElement(X,{backgroundColor:m.secondary},` ${i.command.split(" ").pop()} `)):void 0}),i.key==="emails"&&!i.done&&j.createElement(Wi,null))})))}import Yt from"chalk";import{Box as tt,Text as _e}from"ink";import _ from"react";import{Box as kt,Text as Vi}from"ink";import ge from"react";import al from"chalk";var ll=e=>(q.getTag(e)?.name??"").length+3,ml=e=>{let t=q.getContributor(e);return(t?t.name:"").length+3},Ki=({width:e})=>{let{viewMode:t}=re(),o=O(),{breadCrumb:n,contextNode:s,selectedIndex:u,renderedChildrenIndex:r}=o,f=r[s.id]?.[u],y=Lr(f?.id??s.id,"TICKET"),p=$(y)?y.value:void 0,g=(p?.props.tags??[]).filter(I=>q.getTag(I)),l=p?.props.assignees??[],d=p?.parentNodeId?!jr(s.id,p.parentNodeId)&&t==="dense":!1,a=n.map((I,V)=>{let Se=V===n.length-1,De=ht(I.id),he=Se?De?.[u]?.title:void 0;return`${V?" / ":""}${I.title??""}${he?` \u25B8 ${he}`:""}`}).join(""),i=p?q.getCommentsByIssue(p.id):[],b=i.length?String(i.length).length+11:0,L=d?g.reduce((I,V)=>I+ll(V),0)+l.reduce((I,V)=>I+ml(V),0)+b:0,D=f?.id!=null&&!(t==="wide"&&ct(f)),B=Math.max(0,e-L),P=a.substring(0,B)+(D?al.hex(m.secondary2).dim(` ${de(f.id)}`):""),C=d?[...g.map(I=>ge.createElement(kt,{key:`tag-${I}`,paddingLeft:1},ge.createElement(wr,{id:I}))),...l.map(I=>ge.createElement(kt,{key:`assignee-${I}`,paddingLeft:1},ge.createElement(br,{id:I}))),i.length?ge.createElement(kt,{key:"comments",paddingLeft:1},ge.createElement(Vi,{color:m.accent},"[",i.length," comment",i.length===1?"":"s","]")):null]:[];return ge.createElement(kt,{overflow:"hidden",justifyContent:"flex-start",alignItems:"flex-start"},ge.createElement(Vi,{color:m.secondary2},P),C)};import{Box as cl,Text as Yi}from"ink";import Wt from"react";var dl=({filters:e})=>Wt.createElement(cl,{columnGap:1},Wt.createElement(Yi,{color:"red"},"APPLIED FILTERS:"),e.map(({value:t,target:o,operator:n})=>Wt.createElement(Yi,{backgroundColor:"black",color:"white"},` ${o}${n}"${t}" `))),qi=Wt.memo(dl);import{Box as ul,Text as Vt}from"ink";import Ze from"react";function Ji(){let{eventLog:e,unappliedEvents:t}=O(),o=e.at(-1)?.id,n=ko(o??""),s=$(n)?vt(n.value):"INVALID DATE";return Ze.createElement(ul,{paddingLeft:1},Ze.createElement(Vt,{backgroundColor:m.accent,color:m.secondary}," Readonly "),Ze.createElement(Vt,{color:m.accent}," "+t.length+" edits ago at "+s+"."),Ze.createElement(Vt,{color:m.accent}," Resume with "),Ze.createElement(Vt,{backgroundColor:m.accent,color:m.secondary}," ",":peek now"," "))}import{Box as pl,Text as Eo}from"ink";import Kt from"react";function Xi(){let{replay:e}=O();if(!e)return null;let{appliedCount:t,totalCount:o,currentTime:n}=e;return Kt.createElement(pl,{paddingRight:2,columnGap:1,justifyContent:"flex-end"},Kt.createElement(Eo,{backgroundColor:m.accent,color:m.secondary}," \u25B6 REPLAY "),Kt.createElement(Eo,{color:m.secondary2},vt(new Date(n))),Kt.createElement(Eo,{color:m.accent},`${t}/${o} edits`))}import Co from"chalk";import{Box as fl,Text as zi}from"ink";import Po,{useEffect as gl,useState as yl}from"react";var hl=["#4c567a","#9d7cd8","#7aa2f7","#7dcfff","#9d7cd8"],xl=150,Qi=12,bl=.36;function Zi({syncStatus:e,autoSync:t}){let[o,n]=yl(0);gl(()=>{if(e.status!=="syncing"){n(0);return}let f=0,y=setInterval(()=>{f+=1;let p=(Math.sin(f*bl)+1)/2,g=Math.round(p*(Qi-1));n(l=>l===g?l:g)},xl);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:Fo(hl,o/(Qi-1))??""}[e.status];return Po.createElement(fl,null,Po.createElement(zi,null,Co.hex(m.secondary2).dim(t?"Sync (auto): ":"Sync: ")),Po.createElement(zi,null,Co.hex(r)("\u25CF")+Co.hex(m.secondary2).dim(` ${s[e.status].padEnd(4)} `)))}import et from"chalk";import{Text as es}from"ink";import ts,{useEffect as wl,useState as vl}from"react";var Sl=(e,t)=>{let o=e.split("."),n=t.split("."),s=n.findIndex((u,r)=>u!=o[r]);return n.map((u,r)=>r>=s?et.hex(m.accent).dim(u):et.hex(m.secondary).dim(u)).join(et.hex(m.secondary2).dim("."))};function os(){let[e,t]=vl({current:F,latest:null,updateAvailable:!1});return wl(()=>{let o=!0;return ho(F).then(n=>{o&&t(n)}),()=>{o=!1}},[]),!e.updateAvailable||!e.latest?ts.createElement(es,{dimColor:!0,color:m.secondary2},F+" "):ts.createElement(es,null,et.hex(m.secondary2).dim(F),et.hex(m.accent).dim(" \u2197 "),Sl(F,e.latest))}function ot({filters:e,hideBreadCrumb:t=!1}){let{timeMode:o,syncStatus:n,mode:s,replay:u}=O(),{userName:r,preferredEditor:f,autoSync:y}=re(),p=64,g=process.stdout.columns-p-8,l=t||o==="replay",d=u?qo(u.currentLabel,Math.max(0,g)):"";return _.createElement(tt,{justifyContent:"space-between",flexDirection:"row","max-width":process.stdout.columns-40,overflow:"hidden"},o==="replay"?_.createElement(tt,{paddingLeft:1},_.createElement(_e,{color:m.secondary2},d)):l?_.createElement(_e,null," "):s===H.PALETTE?_.createElement(tt,null,_.createElement(_e,{color:m.accent},"Command Palette"),_.createElement(_e,{dimColor:!0,color:m.secondary2}," ","- search, select and press enter")):_.createElement(tt,{paddingLeft:1},e.length>0?_.createElement(qi,{filters:e}):_.createElement(Ki,{width:g})),o==="live"?_.createElement(tt,{columnGap:1,paddingRight:2,"max-width":p,overflow:"hidden",justifyContent:"flex-end"},_.createElement(Zi,{autoSync:!!y,syncStatus:n}),_.createElement(_e,null,Yt.hex(m.secondary2).dim("Mode: ")+Yt.hex(m.secondary2).dim(s.padEnd(8," "))," "),_.createElement(rs,{icon:"@",value:r}),_.createElement(rs,{icon:"\u276F",value:f}),_.createElement(os,null)):"",o==="peek"?_.createElement(Ji,null):"",o==="replay"?_.createElement(Xi,null):"")}function rs({icon:e,value:t}){return _.createElement(_e,null,Yt.dim(e)+Yt.hex(m.accent)(` ${t??"-"} `))}import{Box as Il,Text as Tl}from"ink";import rt from"react";import{Box as qt,Text as Ao}from"ink";import ye from"react";function No(){let e=O(),t=e.nodes[e.rootNodeId],s=process.stdout.rows-1-3,u=process.stdout.columns||120,r=t?.id?Fe(t?.id):[];return ye.createElement(qt,{flexDirection:"column",height:s,padding:1,borderStyle:"round",borderColor:m.secondary,width:u},ye.createElement(qt,{padding:1,paddingTop:0,paddingBottom:0},ye.createElement(Ao,null,"Select a board:")),ye.createElement(qt,{padding:1,flexDirection:"column"},r.map((f,y)=>{let p=e.contextNode.context==="WORKSPACE"&&e.selectedIndex===y,l=Fe(f.id).flatMap(({id:d})=>ht(d)).length;return ye.createElement(qt,{key:f.id??y},ye.createElement(Ao,{color:p?m.accent:m.secondary2},ye.createElement(xr,{isSelected:p})),ye.createElement(Ao,{color:p?m.accent:m.secondary2},f.title," (",l," issues)",f.readonly?" \u{1F512}":""))})))}var El=({contextNode:e,selectedIndex:t,breadCrumb:o,mode:n,viewMode:s,height:u,width:r})=>{let{renderedChildrenIndex:f}=O(),y=o.find(({context:d})=>d==="BOARD"),l=u-1-3;return rt.createElement(Il,{flexDirection:"row"},e.context==="WORKSPACE"?rt.createElement(No,null):y?rt.createElement(vr,{height:l,width:r,swimlanes:(f[y.id]??[]).filter(d=>d!==void 0&&Yo(d)),contextNode:e,selectedIndex:t,breadCrumb:o,viewMode:s,mode:n}):rt.createElement(Tl,null))},ns=rt.memo(El);import{useEffect as Cl}from"react";var Pl=e=>{Cl(()=>{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&&yr(),n()},s))};return n(),()=>{o=!0,t&&clearTimeout(t)}},[e])},is=({autoSync:e})=>(Pl(e),null);import{useEffect as Al}from"react";var ss=()=>{let e=oe(process.cwd());return h(e)?T("No project here",null):lt({repoRoot:e.value})},as=async()=>{let e=ss();if(h(e))return G(e.message);if(e.value===null)return T("No project here",null);let t=e.value,o=await gt(t);if(!Br())return T("State not initialized",null);let n=Pe();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(Tr())return T("Project loading",null);let g=ss();return h(g)||g.value!==t?T("Project changed",null):s!==H.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):$e(t)===Zo(t)?T("Log unchanged",null):(st.debug("[watch] event log moved, reloading state"),gr(t))};var Nl=1e3,ls=()=>(Al(()=>Bt(as,Nl),[]),null);function Mo({width:e,height:t}){let o=O(),{autoSync:n,viewMode:s}=Uo(),u=o.filters;if(o.mode===H.HELP)return M.createElement(ce,{flexDirection:"column"},M.createElement($i,{width:e,height:t}));if(o.mode===H.IDENTITY)return M.createElement(ce,{flexDirection:"column"},M.createElement(Fi,{width:e,height:t}));if(o.mode===H.PALETTE)return M.createElement(ce,{flexDirection:"column"},M.createElement(ot,{filters:u}),M.createElement(Si,{width:e,height:t-2}),M.createElement(Qe,{width:e,mode:o.mode,availableHints:o.availableHints}));let{isSetupDone:r}=pt(),f=!r,y=r&&!o.hasProjectDefinition;if(f)return M.createElement(ce,{flexDirection:"column"},M.createElement(ce,{flexDirection:"column"},M.createElement(ot,{hideBreadCrumb:!0,filters:u}),M.createElement(To,{height:t,width:e})),M.createElement(Qe,{width:e,mode:o.mode,availableHints:[]}));if(y)return M.createElement(ce,{flexDirection:"column"},M.createElement(ce,{flexDirection:"column"},M.createElement(ot,{hideBreadCrumb:!0,filters:u}),M.createElement(Hi,{height:t,width:e})),M.createElement(Qe,{width:e,mode:o.mode,availableHints:[]}));let p=Wo(o.breadCrumb??[],"BOARD");if($(p)){let g=p.value.id,l=Fe(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 M.createElement(ce,{flexDirection:"column"},M.createElement(is,{autoSync:n}),M.createElement(ls,null),M.createElement(ce,{flexDirection:"column"},M.createElement(ot,{filters:u}),M.createElement(ns,{width:e,height:t,contextNode:o.contextNode,selectedIndex:o.selectedIndex,breadCrumb:o.breadCrumb,viewMode:s??"dense",mode:o.mode})),M.createElement(Qe,{width:e,mode:o.mode,availableHints:o.availableHints}))}import Ml from"readline";var Jt,Xt,se,Rl=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]),Bl=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]),ms=async e=>{if(e.ctrl&&e.name==="c")return Ce.exit();let{actionIndex:t,mode:o,readOnly:n,timeMode:s}=Q(),u=pr(e,o);if(!u||n&&!Rl.has(u)||s==="replay"&&o===H.DEFAULT&&Bl.has(u))return;let r=t[o]?.[u];if(r?.action)try{await r.action(r,e)}catch(f){logger.error(f)}},Ll=()=>async function(t,o){o.name!=="escape"&&(se&&(clearTimeout(se),se=void 0),await ms(o))},jl=()=>async function(t){if(t.length===1&&t[0]===27){se&&clearTimeout(se),se=setTimeout(()=>{ms({name:"escape",ctrl:!1,meta:!1,shift:!1,sequence:"\x1B"}),se=void 0},25);return}se&&(clearTimeout(se),se=void 0)};function cs(){Jt&&process.stdin.removeListener("keypress",Jt),Xt&&process.stdin.removeListener("data",Xt),Jt=Ll(),Xt=jl(),Ml.emitKeypressEvents(process.stdin),process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.on("data",Xt),process.stdin.on("keypress",Jt)}async function ds(){try{let e=it({});if(h(e))return xt(0,e.message);let t=Ie();$(t)&&Ue(t.value);let o=oe(process.cwd());Ue({gitEmail:await Fr(process.cwd()),gitName:await Hr(process.cwd())});let n=$(o)?await Er(o.value):Pr();if(h(n))return n;let s=Ro();return h(s)?xt(6,s.message):(cs(),$(o)&&Cr(o.value),T("Booted Epiq",void 0))}catch(e){return xt(0,bt(e))}}Ir();var Ul=`${z.bold("Epiq CLI")}
|
|
5
|
-
|
|
6
|
-
${z.dim("Boot in directory:")}
|
|
7
|
-
${z.cyan("$ epiq")}
|
|
8
|
-
|
|
9
|
-
${z.dim("Launch GUI:")}
|
|
10
|
-
${z.cyan("$ epiq gui")}
|
|
11
|
-
${z.cyan("$ epiq gui --no-open")} ${z.dim("no browser")}
|
|
12
|
-
|
|
13
|
-
${z.dim("Act as somebody other than the configured user:")}
|
|
14
|
-
${z.cyan("$ epiq --as claude")}
|
|
15
|
-
`,Zt=Dl(Ul,{importMeta:import.meta,version:F,flags:{init:{type:"boolean",default:!1},as:{type:"string"},open:{type:"boolean",default:!0}}}),zt=Zt.input[0];zt&&zt!=="gui"&&(console.error(z.red(`Unknown command: ${zt}`)),process.exit(1));if(Zt.flags.as!==void 0){let e=jo(Zt.flags.as,"--as");h(e)&&(console.error(z.red(e.message)),process.exit(1))}var us=process.stdout.columns||120,ps=process.stdout.rows||20,Qt=null,Gl=e=>{try{return Qt?(Qt.rerender(e),T("Rerendered app",void 0)):(Qt=_l(e),T("Rendered app",void 0))}catch(t){return G(`Unable to render app: ${bt(t)}`)}},Ro=()=>Gl(Ol.createElement(Mo,{width:us,height:ps}));process.stdout.on("resize",()=>{if(us=process.stdout.columns||120,ps=process.stdout.rows||20,!Qt)return;let e=Ro();h(e)&&logger.info(`[boot:resize] ${e.message}`)});if(zt==="gui"){let e=await xi({repoRoot:process.cwd(),open:Zt.flags.open});h(e)&&(console.error(z.red(`Failed to start Epiq GUI:
|
|
16
|
-
${e.message}`)),process.exitCode=1)}else{console.clear();let e=await ds();h(e)&&(logger.info(e.message),console.error(z.red(`Failed to boot Epiq:
|
|
17
|
-
${e.message}`)),process.exitCode=1)}export{Ro as renderApp};
|
package/dist/chunk-BE2ONDXH.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{$a as w,A as Xt,Aa as Io,B as qt,Ba as vo,C as Vt,Ca as It,Cc as _,D as Re,Dc as Jo,E as O,Ea as ho,Ec as Qo,F as Yt,Fa as vt,G as Jt,Ga as Ue,Gb as ce,H as te,Ha as bo,Hb as Se,I as Qt,Ia as Ro,J as D,Ja as Te,Jb as me,K as Ge,Ka as He,La as yo,M as ye,Ma as Ao,Mb as $o,N as Zt,Na as ht,Nb as Wo,O as eo,Oa as bt,Ob as jo,P as ct,Pa as R,Q as to,Qa as To,R as oo,Ra as A,Rb as Uo,S as so,Sa as So,Sb as Ho,T as F,Tb as zo,Ua as Rt,V as H,Va as de,W as $,Wa as wo,Xa as ue,Ya as oe,Za as Eo,_ as C,_a as xo,b as Me,c as le,ca as no,d as De,e as Fe,eb as Co,ec as Ko,f as Wt,fa as N,fb as Bo,g as Q,ga as ro,ha as io,hb as Lo,i as jt,ib as ze,jb as ko,jc as Xo,k as _e,ka as ao,kb as No,kc as At,la as lo,lb as Po,lc as qo,ma as $e,mb as Oo,n as ee,na as We,nb as Mo,o as Ut,oa as Ae,ob as Do,pa as mt,pb as Fo,pc as Ke,q as ut,qa as pt,qc as Vo,ra as ft,rb as _o,s as Ht,sa as je,ta as uo,tc as Yo,ua as gt,uc as Xe,va as co,vb as yt,vc as Tt,wa as mo,wb as Go,xa as po,xb as M,y as zt,ya as fo,yc as St,z as Kt,za as go,zc as qe}from"./chunk-4BPR3FGA.js";import{g as $t}from"./chunk-WUCQWBQE.js";import{b as d,c,d as l}from"./chunk-5RIQL7P4.js";var an=e=>e.payload??{},wt=e=>{let t=new Map,o={},s=new Set,n=new Set,a=new Set;for(let r of e){let{id:i,name:u}=an(r);if(i)switch(r.action){case"create.contributor":case"create.tag":t.set(i,u??""),s.add(i),n.delete(i);break;case"rename.contributor":u!==void 0&&s.has(i)&&!n.has(i)&&t.set(i,u);break;case"tombstone.contributor":s.has(i)&&(t.set(i,Ge),n.add(i));break;case"restore.contributor":case"restore.tag":u!==void 0&&s.has(i)&&(t.set(i,u),n.delete(i));break;case"add.board":u!==void 0&&(t.set(i,u),a.add(i));break;case"add.swimlane":u!==void 0&&(t.set(i,u),a.add(i),o[i]=u);break;case"edit.title":u!==void 0&&a.has(i)&&(t.set(i,u),i in o&&(o[i]=u));break;default:break}}return{byId:t,lanes:o}};var ln=e=>{let t=new Map,o=new Map;for(let s of e){let n=s.payload;!n?.id||!n.parent||(s.action==="move.node"&&t.set(s.id,o.get(n.id)),o.set(n.id,n.parent))}return t},es=e=>{let t=e.payload;return e.action==="tombstone.tag"||e.action==="restore.tag"?t?.id:t?.tag},dn=e=>{let t=new Set,o=new Map;for(let s of e){let n=s.payload,a=n?.id;a&&(s.action==="add.issue"&&t.add(a),n.parent&&o.set(a,n.parent))}return{issueIds:t,parentById:o}},un=(e,{issueIds:t,parentById:o})=>{let s=e.payload;if(s?.issue)return s.issue;let n=new Set,a=s?.id;for(;a!==void 0&&!n.has(a);){if(t.has(a))return a;n.add(a),a=o.get(a)}return null},cn=new Set(["add.issue.comment","edit.issue.comment","delete.issue.comment"]),mn=e=>cn.has(e.action)?e.payload?.id??null:null,pn=new Set(["add.issue","move.node","close.issue","reopen.issue"]),fn=(e,t)=>{let o=new Map;return e.map((s,n)=>{let a=t[n]??null;if(a===null)return{lane:null,laneBefore:null};let r=s.payload,i=null;if(pn.has(s.action)&&r?.id===a&&r.parent){let u=o.get(a);u!==void 0&&u!==r.parent&&(i=u),o.set(a,r.parent)}return{lane:o.get(a)??null,laneBefore:i}})},gn=e=>{let t=new Map,o=new Map;return e.map(s=>{let{id:n,name:a}=s.payload??{};if(!n)return null;s.action==="add.board"&&t.set(n,"board"),s.action==="add.swimlane"&&t.set(n,"swimlane");let r=t.get(n);if(!r)return null;let i={kind:r,name:o.get(n)??a};return(s.action==="edit.title"||s.action.startsWith("add."))&&a!==void 0&&o.set(n,a),i})},Zo=90,In=e=>{let t=e.trim().split(`
|
|
3
|
-
`)[0]?.trim()??"";return t.length>Zo?`${t.slice(0,Zo).trimEnd()}\u2026`:t},ts=({kind:e,name:t})=>t===void 0?e:`${e} "${t}"`,vn=(e,t,o,s)=>{let{name:n,parent:a}=e.payload??{},r=ts(t);switch(e.action){case"move.node":{if(t.kind==="board"||!a)return`Moved ${r}`;let i=o.get(a);return i?s.get(e.id)===a?`Moved ${r} within ${i}`:`Moved ${r} to ${i}`:`Moved ${r}`}case"edit.title":return n===void 0?`Renamed ${r}`:`Renamed ${r} to "${n}"`;case"delete.node":return`Deleted ${r}`;case"lock.node":return`Locked ${r}`;default:return null}},hn=(e,t,o,s,n)=>{let a=e.payload,r=es(e),i=e.action?Jo(e.action):"";if(a?.md!==void 0){let f=In(a.md),g=e.action==="edit.description"&&!s&&n?`${i} of ${ts(n)}`:i;return f?`${g}: ${f}`:g}if(n&&!s){let f=vn(e,n,t,o);if(f)return f}if(e.action==="move.node"&&a?.parent){let f=t.get(a.parent),g=s?`${A(s)} moved`:"Moved";return f?o.get(e.id)===a.parent?`${g} within ${f}`:`${g} to ${f}`:s?g:i}if((e.action==="close.issue"||e.action==="reopen.issue")&&s)return`${A(s)} ${i.toLowerCase()}`;if(qt(e.action))return[i,Vt(e)].filter(Boolean).join(" ");let u=r!==void 0?t.get(r)??"":a?.assignee!==void 0?t.get(a.assignee)??"":a?.email!==void 0?a.email:a?.name!==void 0?`"${a.name}"`:"";return[i,u].filter(Boolean).join(" ")},Et=(e,t)=>e?D(e,t.get(e)):null,bn=(e,t)=>{let o=e.payload;return{actor:Et(e.userId,t),tag:Et(es(e),t),assignee:Et(o?.assignee,t)}},os=e=>{let t=new Map,o=new Set,s=n=>{let a=new Set,r=n;for(;r&&!a.has(r);){if(o.has(r))return r;a.add(r),r=t.get(r)}return null};return e.map(n=>{let a=n.payload,r=a?.id;if(!r)return null;n.action==="add.board"&&o.add(r);let i=n.action==="close.issue"?s(r):null,u=a.parent??a.issue;return u&&t.set(r,u),i!==null?i:o.has(r)?r:s(r)})},ss=e=>Rn.has(e),Rn=new Set(["create.contributor","rename.contributor","tombstone.contributor","restore.contributor","link.contributor.user","link.contributor.email","unlink.contributor.email","connect.repo","edit.repo","disconnect.repo","create.tag","tombstone.tag","restore.tag"]),ns=(e,t)=>{let o=os(e);return e.filter((s,n)=>o[n]===t)},yn=(e,t=new Map)=>{let o=new Map([...t,...wt(e).byId]),s=ln(e),n=dn(e),a=e.map(m=>un(m,n)),r=gn(e),i=fn(e,a),u=os(e),f=Yt(e.map(m=>te(m)));return e.flatMap((m,I)=>{let v=f[I]??null;return v===null?[]:[{id:m.id,t:v,action:m.action,label:hn(m,o,s,a[I]??null,r[I]??null),issue:a[I]??null,target:mn(m),...i[I],board:u[I]??null,...bn(m,o)}]}).sort((m,I)=>m.t-I.t)},An=e=>{let t=new Map;for(let s of e){if(s.issue===null||s.lane===null)continue;let n=t.get(s.issue)??[],a=n[n.length-1];(a===void 0||a.lane!==s.lane)&&(n.push({t:s.t,lane:s.lane,board:s.board}),t.set(s.issue,n))}let o=new Map;for(let[s,n]of t){let a=n[n.length-1];o.set(s,{changes:n,from:n[0].t,closedFrom:a.lane===N?a.t:null})}return o},Tn=(e,t)=>{let o=0,s=e.length;for(;o<s;){let n=o+s>>1;e[n].t<t?o=n+1:s=n}return e[o-1]},rs=(e,t,o)=>{let s={};for(let[n,a]of e){if(a.from>=t||a.closedFrom!==null&&a.closedFrom<t)continue;let r=Tn(a.changes,t);r===void 0||r.lane===N||o&&r.board!==o||(s[n]=r.lane)}return s},Sn=e=>wt(e).lanes,we=null,is=e=>{let t=He(e);if(we&&we.root===e&&we.signature===t)return c("Timeline entries, cached",we.index);let o=oe(e);if(l(o))return d(o.message);let s=yn(o.value,ue(e)),n={entries:s,lanes:An(s),laneNames:Sn(o.value)};return we={root:e,signature:t,index:n},c("Timeline entries, built",n)};var as=1e5,wn=2e4,Ve=null,ls=Promise.resolve(),us=e=>{let t=ls.then(e,e);return ls=t.then(()=>{},()=>{}),t},Ye=e=>{let t=Te(e);return l(t)?t:Q({repoRoot:t.value})},z=()=>{if(!qe())return{mode:"live",asOfTime:null};let{timeMode:e}=Yo();return e==="live"?{mode:"live",asOfTime:null}:{mode:"scrub",asOfTime:Ve}},ds=(e,t)=>{let o=0,s=e.length;for(;o<s;){let n=o+s>>1;e[n].t<t?o=n+1:s=n}return o},Ji=async(e={})=>{let t=Ye(e.repoRoot);if(l(t))return d(t.message);let o=is(t.value);if(l(o))return d(o.message);let s=o.value.entries,n=Date.now(),a=e.end??n,r=e.start??s[0]?.t??a;if(a<=r)return c("Empty time window",{bucketMs:0,buckets:[],capped:!1,events:[],lanesAtStart:{},laneNames:o.value.laneNames,closedLane:N,earliest:r,latest:a});let i=ds(s,r),u=ds(s,a),f=s.slice(i,u).filter(p=>!e.boardId||p.board===e.boardId||ss(p.action)),g=f.map(p=>p.t),m=Math.max(1,Math.ceil((a-r)/as)),I=new Map;for(let p of g){let b=Math.min(as-1,Math.floor((p-r)/m)),T=r+b*m;I.set(T,(I.get(T)??0)+1)}let v=[...I.entries()].sort(([p],[b])=>p-b).map(([p,b])=>({t:p,count:b})),h=f.length>wn;return c("Computed event timeline",{bucketMs:m,buckets:v,capped:h,events:h?[]:f,lanesAtStart:rs(o.value.lanes,r,e.boardId),laneNames:o.value.laneNames,closedLane:N,earliest:r,latest:a})},cs=e=>{let t=oe(e);if(l(t))return d(t.message);let o=St();if(l(o))return d(o.message);Ve=null;let s=Rt(t.value),{fatal:n,skipped:a}=ht(s);return n.length>0?d(n.map(r=>r.message).join(", ")):(bt(a),Tt({readOnly:!1,readOnlyReason:void 0,timeMode:"live",unappliedEvents:[],replay:null}),c("Restored live state",!0))},En=(e,t)=>{Ve=null;let o=cs(e);return l(o)?d(`${t} (recovery to live also failed: ${o.message})`):d(t)},xn=e=>us(async()=>{let t=Ye(e.repoRoot);if(l(t))return d(t.message);let o=Eo(t.value,e.targetTime);if(l(o))return d(o.message);let{appliedEvents:s,unappliedEvents:n}=o.value,a=St();if(l(a))return a;let r=Rt(s),{fatal:i,skipped:u}=ht(r);return i.length>0?En(t.value,i.map(f=>f.message).join(", ")):(bt(u),Tt({readOnly:!0,timeMode:"peek",unappliedEvents:n,replay:null}),Ve=e.targetTime,c("Checked out historical state",{asOfTime:e.targetTime}))}),Qi=async e=>{let t=Ye(e.repoRoot);if(l(t))return d(t.message);let o=xo(t.value);if(l(o))return d(o.message);let s=o.value.get(e.eventId)??null;return s===null?d("Event not found in the log"):xn({repoRoot:e.repoRoot,targetTime:s+1})},Zi=(e={})=>us(async()=>{let t=Ye(e.repoRoot);if(l(t))return d(t.message);let o=cs(t.value);return l(o)?d(o.message):c("Returned to live state",!0)});import{ulid as kn}from"ulid";import Bn from"node:fs";var ms=new Map,Cn=3e4,ps=async e=>{let t=ms.get(e);if(t&&Date.now()-t.readAt<Cn)return{name:t.name,email:t.email};let o=await Fe({args:["config","--get-regexp","^user\\.(name|email)$"],cwd:e}),s=null,n=null;if(o.exitCode===0)for(let a of(o.stdout??"").split(`
|
|
4
|
-
`)){let r=a.indexOf(" ");if(r===-1)continue;let i=a.slice(0,r),u=a.slice(r+1);i==="user.name"&&(s=u.trim()||null),i==="user.email"&&(n=ye(u)||null)}return ms.set(e,{name:s,email:n,readAt:Date.now()}),{name:s,email:n}},fs=async e=>(await ps(e)).email,pe=async e=>(await ps(e)).name;var se=e=>{let t=_e(e??process.cwd());return l(t)?d(t.message):c("Resolved Epiq repo root",t.value)},Je=null,Ln=async(e,t)=>{let o=se(e);if(l(o))return o;let s=Q({repoRoot:o.value});if(l(s))return d(s.message);let n=le(o.value);if(l(n))return d(n.message);if(!(Je!==null&&Je.repoRoot===o.value&&Je.stateBranchRoot===s.value&&Bn.existsSync(jt(s.value)))){let m=await Uo({repoRoot:o.value,stateBranchName:n.value});if(l(m))return d(m.message);let I=await Ho({repoRoot:o.value,stateBranchRoot:s.value,stateBranchName:n.value});if(l(I))return d(I.message);Je={repoRoot:o.value,stateBranchRoot:s.value}}if(t?.pull??!1){let m=await De({cwd:s.value,args:["pull","--ff-only"]});l(m)&&Me.info(3,m.message)}let r={repoRoot:o.value,stateBranchRoot:s.value},i=ee();l(i)||ut(i.value),ut({gitEmail:await fs(o.value),gitName:await pe(o.value)});let u=He(s.value);if(yo(s.value)===u&&qe()&&z().mode==="live")return c("Booted Epiq state, unchanged",r);let f=de(s.value);if(l(f))return d(f.message);let g=me(f.value.events,f.value.unreadable);return l(g)?d(g.message):(Ao(s.value,u),c("Booted Epiq state",r))},W=()=>{let e=ee();return l(e)?d(e.message):e.value.userId?e.value.userName?c("Resolved actor",{userId:e.value.userId,userName:e.value.userName}):d("Unable to retrieve user name"):d("Unable to retrieve user id")},B=()=>{let e=Xe();return l(e)?d(e.message):e},L=e=>Ln(e,{pull:!1}),y=async e=>{let t=await L(e);if(l(t))return t;let o=W();if(l(o))return o;let s=B();return l(s)?s:c("Booted",{boot:t.value,actor:o.value,state:s.value})};var k=e=>{let t=B();if(l(t))return t;let o=t.value.nodes[e];return!o||o.isDeleted?d("Issue not found"):F(o)?o.readonly?d("Issue is readonly"):c("Found issue",o):d("Target must be an issue")},j=e=>{let t=B();if(l(t))return t;let o=t.value.nodes[e];return!o||o.isDeleted?d("Swimlane not found"):H(o)?o.readonly?d("Swimlane is readonly"):c("Found swimlane",o):d("Target must be a swimlane")},Ee=e=>{let t=B();if(l(t))return t;let o=t.value.nodes[e];return!o||o.isDeleted?d("Board not found"):$(o)?o.readonly?d("Board is readonly"):c("Found board",o):d("Target must be a board")};var xt=e=>{if(!e)return;let t=B();if(l(t))return;let o=t.value.nodes[e];if(!o||!($(o)||H(o)))return;let s=o.props?.description;return s?.trim()?s:void 0},Qe=e=>{let t=xt(e);return t?{laneDescription:t}:{}},xe=e=>{let t=xt(e);return t?{boardDescription:t}:{}},fe=e=>{let t=xt(e);return t?{description:t}:{}},Ze=({node:e,label:t,max:o,description:s,actor:n,stateBranchRoot:a})=>{let r=Go(s),i=M(t,r,o);if(i)return d(i);if(z().mode!=="live")return d(`Cannot edit the ${t.toLowerCase()} while time travelling`);let u={id:e.id,ref:A(e.id),description:r};if((e.props?.description??"")===r)return c("No changes made",u);let f={id:kn(),...R(n),action:"edit.description",payload:{id:e.id,md:r}},g=w([f],a);return l(g)?d(g.message):c(`Edited ${t.toLowerCase()}`,u)},Nn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=Ee(e.boardId);return l(o)?o:Ze({node:o.value,label:"Board description",max:yt("board"),description:e.description,actor:t.value.actor,stateBranchRoot:t.value.boot.stateBranchRoot})},Pn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=j(e.swimlaneId);return l(o)?o:Ze({node:o.value,label:"Swimlane description",max:yt("swimlane"),description:e.description,actor:t.value.actor,stateBranchRoot:t.value.boot.stateBranchRoot})};import{ulid as Ce}from"ulid";var gs=e=>({id:e.id,name:C(e.name),color:co(e)}),Be=e=>{let t=uo(e);return t?{goal:gs(t)}:{}},Ct=e=>({...gs(e),...Io(e.id)}),Is=()=>pt().map(Ct),On=async(e={})=>{let t=await L(e.repoRoot);return l(t)?t:c("Listed goals",pt().map(o=>({...Ct(o),boards:po(o.id).map(s=>({id:s,ref:A(s)}))})))},et=e=>go(e).map(t=>({...Ct(t),members:fo(t.id,e).map(o=>({id:o.id,done:vo(o)}))})),tt=(e,t,o)=>{let s=w(t,e);return l(s)?d(s.message):c("Saved",o)},Mn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;let s=o.value,n={id:s.id,ref:A(s.id)},a;if(e.goal!==null){let u=je(e.goal);if(!u){let f=await vs({repoRoot:e.repoRoot,name:e.goal,issueId:s.id});return l(f)?f:c(`Created goal "${f.value.name}"`,n)}a=u.id}let r=gt(s,a);if(r.length===0)return c("No changes made",n);let i=R(t.value.actor);return tt(t.value.boot.stateBranchRoot,r.map(u=>({id:Ce(),...i,...u})),n)},vs=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=ft(e.name),s=It(o);if(s)return d(s);let n=R(t.value.actor),a=Ce(),r=[{id:a,...n,action:"create.goal",payload:{id:a,name:o}}];if(e.issueId){let i=k(e.issueId);if(l(i))return i;let u=i.value;for(let f of gt(u,a))r.push({id:Ce(),...n,...f})}return tt(t.value.boot.stateBranchRoot,r,{id:a,name:o})},Dn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=mt(e.goalId);if(!o)return d("Goal not found");let s=ft(e.name);if(s===o.name)return c("No changes made",{id:o.id,name:s});let n=It(s,o.id);return n?d(n):tt(t.value.boot.stateBranchRoot,[{id:Ce(),...R(t.value.actor),action:"rename.goal",payload:{id:o.id,name:s}}],{id:o.id,name:s})},Fn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=mt(e.goalId);return o?tt(t.value.boot.stateBranchRoot,[{id:Ce(),...R(t.value.actor),action:"tombstone.goal",payload:{id:o.id}}],{id:o.id,name:o.name}):d("Goal not found")};import{ulid as _n}from"ulid";var ot=e=>{let t=ao(e);return t.length>0?{rules:t}:{}},Gn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=j(e.swimlaneId);if(l(o))return o;let s=o.value,n=lo(s,e.rule,e.on);if(l(n))return n;let a={id:s.id,ref:A(s.id),rule:e.rule};if(!n.value)return c(n.message,a);let r=w([{id:_n(),...R(t.value.actor),...n.value}],t.value.boot.stateBranchRoot);return l(r)?d(r.message):c(e.on?"Added lane rule":"Removed lane rule",a)};import $n from"node:fs";import Wn from"node:path";import{ulid as Bt}from"ulid";var jn=e=>{if(e.filePath)try{return c("Read attachment file",{data:$n.readFileSync(e.filePath),name:e.name??Wn.basename(e.filePath)})}catch(t){return d(`Unable to read ${e.filePath}: ${t instanceof Error?t.message:String(t)}`)}return e.dataBase64?c("Decoded attachment data",{data:Buffer.from(e.dataBase64,"base64"),name:e.name??"image"}):d("Provide either filePath or dataBase64")},st=()=>{let e=ee();return l(e)?vt:e.value.attachmentMaxKb??vt},Un=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;let s=jn(e);if(l(s))return s;let n=bo(t.value.boot.stateBranchRoot,s.value.data,st());if(l(n))return n;let a=C(s.value.name).trim()||"image",r=Bt(),i={id:Bt(),...R(t.value.actor),action:"add.issue.attachment",payload:{id:r,issue:e.issueId,author:t.value.actor.userId,hash:n.value.hash,ext:n.value.ext,name:a,bytes:n.value.bytes}},u=w([i],t.value.boot.stateBranchRoot);if(l(u))return d(u.message);let f=Ue(n.value.hash,n.value.ext);return c("Added issue attachment",{id:r,issueId:e.issueId,fileName:f,bytes:n.value.bytes,markdown:ho(a,f)})},Hn=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.eventLog.find(i=>i.action==="add.issue.attachment"&&i.payload.id===e.attachmentId);if(!o)return d("Unable to resolve attachment");if(o.payload.author!==t.value.actor.userId)return d("You can only delete your own attachments");let s=k(o.payload.issue);if(l(s))return s;if(t.value.state.eventLog.some(i=>i.action==="delete.issue.attachment"&&i.payload.id===e.attachmentId))return c("Attachment already deleted",{id:e.attachmentId,issueId:o.payload.issue});let a={id:Bt(),...R(t.value.actor),action:"delete.issue.attachment",payload:{id:e.attachmentId,issue:o.payload.issue}},r=w([a],t.value.boot.stateBranchRoot);return l(r)?d(r.message):c("Deleted issue attachment",{id:e.attachmentId,issueId:o.payload.issue})},zn=async e=>{let t=await L(e.repoRoot);return l(t)?t:Ro(t.value.stateBranchRoot,e.fileName,st())};var Kn=e=>{switch(e.action){case"add.issue":case"move.node":case"close.issue":case"reopen.issue":return e.payload.parent;default:return null}},Lt=(e,t)=>{let o=[];for(let s of e){let n=Kn(s);if(n===null||n===o.at(-1)?.laneId)continue;let a=te(s);o.push({laneId:n,enteredAt:a===null?t:Re(a)})}return o},hs=(e,t)=>e.reduce((o,s)=>{let n=te(s);return n===null?o:Math.max(o,Re(n))},t),Le=(e,t)=>Lt(e,t).at(-1)?.enteredAt??t;var ne=e=>ro(e).map(t=>D(t.id,t.name)),bs=e=>_.getCommentsByIssue(e).sort((t,o)=>t.id<o.id?-1:t.id>o.id?1:0).map(t=>({id:t.id,author:Qt(t.authorId,_.getContributor(t.authorId)?.name),createdAt:O(t.id),body:t.md})),re=e=>io(e).map(({id:t,name:o})=>D(t,o));var Xn=async(e={})=>{let t=await L(e.repoRoot);if(l(t))return t;let o=B();return l(o)?o:c("Retrieved Epiq state",{root:t.value.repoRoot,stateBranchRoot:t.value.stateBranchRoot,nodes:o.value.nodes,rootNodeId:o.value.rootNodeId,contextNode:o.value.contextNode,selectedIndex:o.value.selectedIndex,eventLog:o.value.eventLog})},qn=365*24*60*60*1e3,Vn=e=>{let t=B();if(l(t))return t;let o=t.value.nodes[e];return c("Issue description",o&&F(o)&&!o.isDeleted?o.props.description??"":"")},kt=()=>{let e=B();if(l(e))return e;let t=z(),o=t.mode!=="live",s=Object.values(e.value.nodes),n=s.filter(p=>$(p)&&!p.isDeleted),a=Date.now()-qn,r=new Map,i=new Map;for(let p of s)if(!p.isDeleted){if(H(p)&&p.parentNodeId){let b=r.get(p.parentNodeId)??[];b.push(p),r.set(p.parentNodeId,b)}if(F(p)&&p.parentNodeId){if(p.parentNodeId===N&&O(p.id)<a)continue;let b=i.get(p.parentNodeId)??[];b.push(p),i.set(p.parentNodeId,b)}}let u=new Set;for(let p of i.values())for(let b of p)u.add(b.id);let f=ee();if(l(f))return f;let g={},m=_.getCommentsGroupedByIssue();for(let p of s.filter(F))p.isDeleted||!u.has(p.id)||(g[p.id]=(m.get(p.id)??[]).map(b=>{let T=_.getContributor(b.authorId);return{id:b.id,issueId:b.issue,body:b.md,author:D(b.authorId,T?.name),createdAt:O(b.id)}}));let I=new Map;for(let p of e.value.eventLog)p.action==="add.issue.attachment"&&I.set(p.payload.id,p.payload.author);let v={},h=_.getAttachmentsGroupedByIssue();for(let p of s.filter(F))p.isDeleted||!u.has(p.id)||(v[p.id]=(h.get(p.id)??[]).map(b=>({id:b.id,issueId:b.issue,name:b.name,fileName:Ue(b.hash,b.ext),bytes:b.bytes,createdAt:O(b.id),canDelete:I.get(b.id)===f.value.userId})));return c("Retrieved Epiq GUI state",{boards:n.sort((p,b)=>p.rank.localeCompare(b.rank)).map(p=>({id:p.id,ref:A(p.id),title:p.title,readonly:!!p.readonly||o,...fe(p.id),goals:et(p.id),swimlanes:(r.get(p.id)??[]).sort((b,T)=>b.rank.localeCompare(T.rank)).map(b=>({id:b.id,title:b.title,readonly:!!b.readonly||o,issues:(i.get(b.id)??[]).sort((T,Y)=>T.rank.localeCompare(Y.rank)).map(T=>({id:T.id,ref:A(T.id),title:C(T.title),description:T.props.description??"",createdAt:O(T.id),enteredLaneAt:Le(T.log??[],O(T.id)),lastEventAt:hs(T.log??[],O(T.id)),readonly:!!T.readonly||o,tags:ne(T),assignees:re(T),...Be(T),parentNodeId:T.parentNodeId,isClosed:T.parentNodeId===N,boardIds:Ae(T)})),parentNodeId:b.parentNodeId,...fe(b.id),...ot(b),countsDone:We(b.id),doneByName:$e(b)}))})),tags:_.getTags().map(p=>({...p,...D(p.id,p.name)})),goals:Is(),contributors:Object.values(e.value.contributors).map(p=>({...p,...D(p.id,p.name)})),user:{id:f.value.userId??"",name:f.value.userName??"",color:Ht(f.value.userName??"")},commentsByIssueId:g,attachmentsByIssueId:v,attachmentMaxKb:st(),timeTravel:t})},Rs=null,Yn=e=>{if(e===Rs)return;let t=no({root:e});if(l(t)){Me.info(t.message);return}Rs=e},Jn=async(e={})=>{if(z().mode!=="live")return kt();let t=await L(e.repoRoot);return l(t)?t:(Yn(t.value.repoRoot),kt())},Qn=async(e={})=>{$o();let t=se(e.repoRoot);if(l(t))return d("Sync failed");let o=W();if(l(o))return o;let s=await zo({cwd:t.value,ownEventFileName:To(o.value)});return l(s)?(jo(s.message),s):(Wo(),c("Synced",s.value))};import{ulid as K}from"ulid";var ke=e=>{let t=[...new Set([...e.issueIds??[],...e.issueId?[e.issueId]:[]])];return t.length?c("Resolved targets",t):d("Provide issueId or issueIds")},ge=(e,t)=>{let o=t.done.length,s=`${e} ${o} issue${o===1?"":"s"}`+(t.failed.length?`, ${t.failed.length} failed`:"");return o?c(s,t):d(`${s}: ${t.failed.map(n=>`${n.ref} ${n.reason}`).join("; ")}`)},Ne=(e,t)=>{let o={done:[],failed:[]};for(let s of e){let n=t(s);l(n)?o.failed.push({id:s,ref:A(s),reason:n.message}):o.done.push({id:s,ref:A(s)})}return o};var Zn=async e=>{let t=await L(e.repoRoot);if(l(t))return t;let o=B();if(l(o))return o;let s=e.idOrRef.trim();if(!s)return d("Provide an issue id or ref");let n=Object.values(o.value.nodes).filter(F).filter(u=>!u.isDeleted),a=n.find(u=>u.id===s),r=a?[a]:n.filter(u=>So(u.id,s));if(r.length===0)return d(`No issue matches "${s}"`);if(r.length>1)return d(`"${s}" matches ${r.length} issues: ${r.map(u=>`${A(u.id)} (${C(u.title)})`).join(", ")}. Use a full ref or id.`);let i=r[0];return c("Found issue",{id:i.id,ref:A(i.id),title:C(i.title),description:i.props.description??"",createdAt:O(i.id),enteredLaneAt:Le(i.log??[],O(i.id)),parentNodeId:i.parentNodeId,isClosed:i.parentNodeId===N,boardIds:Ae(i),readonly:!!i.readonly,tags:ne(i),assignees:re(i),...Be(i),comments:bs(i.id),...Qe(i.parentNodeId)})},Ts=(e,t)=>e.trim().toLowerCase()===t.trim().toLowerCase();async function er(e){let t=await L(e.repoRoot);if(l(t))return t;let o=B();if(l(o))return o;let s=o.value.nodes,n=e.query?.trim().toLowerCase(),a=Object.values(s).filter(F).filter(i=>!i.isDeleted).filter(i=>e.includeClosed||i.parentNodeId!==N).filter(i=>e.boardId?(i.parentNodeId?s[i.parentNodeId]:void 0)?.parentNodeId===e.boardId:!0).filter(i=>!e.swimlaneId||i.parentNodeId===e.swimlaneId).filter(i=>!e.tag||ne(i).some(u=>Ts(u.name,e.tag))).filter(i=>!e.assignee||re(i).some(u=>Ts(u.name,e.assignee))).filter(i=>!n||i.title.toLowerCase().includes(n)||(i.props.description??"").toLowerCase().includes(n)),r=i=>C((i.parentNodeId?s[i.parentNodeId]?.title:void 0)??"");return e.brief?c("Listed issues",a.map(i=>({id:i.id,ref:A(i.id),title:C(i.title),swimlane:r(i),tags:ne(i).map(u=>u.name),assignees:re(i).map(u=>u.name)}))):c("Listed issues",a.map(i=>({id:i.id,ref:A(i.id),title:C(i.title),description:i.props.description??"",createdAt:O(i.id),enteredLaneAt:Le(i.log??[],O(i.id)),parentNodeId:i.parentNodeId,isClosed:i.parentNodeId===N,boardIds:Ae(i),readonly:!!i.readonly,tags:ne(i),assignees:re(i),...Be(i)})))}var tr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=C(e.title);if(!o)return d("Issue title cannot be empty");let s=e.description??"",n=M("Issue title",o,300)??M("Issue description",s,2e4);if(n)return d(n);if((e.tagNames?.length??0)>20)return d(`Cannot set more than ${20} tags at once`);if((e.assigneeNames?.length??0)>20)return d(`Cannot set more than ${20} assignees at once`);let a=j(e.parentId);if(l(a))return a;let r=Se(e.parentId,t.value.actor,t.value.boot.stateBranchRoot);if(l(r))return r;let i=Ko({name:o,parent:e.parentId,user:t.value.actor,rank:r.value});if(l(i))return i;let u=[...i.value],f=u.find(v=>v.action==="add.issue")?.payload.id;if(!f)return d("Unable to determine created issue id");s&&u.push({id:K(),...R(t.value.actor),action:"edit.description",payload:{id:f,md:s}});let g=[];for(let v of e.tagNames??[]){let h=C(v).trim();if(!h||g.some(Y=>Y.name===h))continue;let p=M("Tag name",h,60);if(p)return d(p);let b=_.findTagByName(h),T=b?.id??K();b||u.push({id:K(),...R(t.value.actor),action:"create.tag",payload:{id:T,name:h}}),u.push({id:K(),...R(t.value.actor),action:"add.issue.tag",payload:{id:f,tag:T}}),g.push({id:T,name:h})}let m=[];for(let v of e.assigneeNames??[]){let h=C(v).trim();if(!h||m.some(Y=>Y.name===h))continue;let p=M("Assignee name",h,80);if(p)return d(p);let b=Object.values(t.value.state.contributors).find(Y=>Y.name===h),T=b?.id??K();b||u.push({id:K(),...R(t.value.actor),action:"create.contributor",payload:{id:T,name:h}}),u.push({id:K(),...R(t.value.actor),action:"add.issue.assignee",payload:{id:f,assignee:T}}),m.push({id:T,name:h})}let I=w(u,t.value.boot.stateBranchRoot);return l(I)?d(I.message):c("Created issue",{id:f,ref:A(f),title:o,parentId:e.parentId,description:s,tags:g,assignees:m,...Qe(e.parentId),...xe(t.value.state.nodes[e.parentId]?.parentNodeId)})},or=(e,t,o)=>{let s=k(e);if(l(s))return s;let n=ce(N,e,{at:"end"},t,o);if(l(n))return n;let a={id:K(),...R(t),action:"close.issue",payload:{id:e,parent:N,rank:n.value}},r=w([a],o);return l(r)?d(r.message):c("Closed issue",{id:e,ref:A(e)})};async function sr(e){let t=await L(e.repoRoot);if(l(t))return t;let o=W();if(l(o))return o;let s=ke(e);if(l(s))return s;let n=a=>or(a,o.value,t.value.stateBranchRoot);return e.issueIds?ge("Closed",Ne(s.value,n)):n(s.value[0])}var nr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.nodes[e.issueId];if(!o||o.isDeleted)return d("Issue not found");if(!F(o))return d("Target must be an issue");if(o.parentNodeId!==N)return d("Issue is not closed");let s=Xo(o);if(!s)return d("Unable to resolve previous parent from issue history");if(s===N)return d("Previous parent resolves to closed swimlane");let n=j(s);if(l(n))return n;let a=n.value,r=ce(a.id,o.id,{at:"end"},t.value.actor,t.value.boot.stateBranchRoot);if(l(r))return r;let i={id:K(),...R(t.value.actor),action:"reopen.issue",payload:{id:o.id,parent:a.id,rank:r.value}},u=w([i],t.value.boot.stateBranchRoot);return l(u)?d(u.message):c("Reopened issue",{id:o.id,ref:A(o.id),parentId:a.id})},rr=(e,t,o,s)=>{let n=k(e);if(l(n))return n;let a=j(t.parentId);if(l(a))return a;let r=ce(t.parentId,e,t.position??{at:"end"},o,s);if(l(r))return r;let i={id:K(),...R(o),action:"move.node",payload:{id:e,parent:t.parentId,rank:r.value}},u=w([i],s);return l(u)?d(u.message):c("Moved issue",{id:e,ref:A(e),parentId:t.parentId})};async function ir(e){let t=se(e.repoRoot);if(l(t))return t;let o=W();if(l(o))return o;let s=Q({repoRoot:t.value});if(l(s))return s;let n=de(s.value);if(l(n))return n;let a=me(n.value.events,n.value.unreadable);if(l(a))return a;let r=ke(e);if(l(r))return r;let i=(()=>{let g=B();if(l(g))return()=>({});let{nodes:m}=g.value,I=p=>p?m[p]?.parentNodeId:void 0,v=I(e.parentId),h=r.value.some(p=>I(m[p]?.parentNodeId)!==v);return()=>({...Qe(e.parentId),...h?xe(v):{}})})(),u=g=>rr(g,e,o.value,s.value);if(!e.issueIds){let g=u(r.value[0]);return l(g)?g:c(g.message,{...g.value,...i()})}let f=ge("Moved",Ne(r.value,u));return l(f)?f:c(f.message,{...f.value,...i()})}var ar=e=>{let t=B();if(l(t))return t;let o=t.value.nodes[e];return o?c("Read issue history",(o.log??[]).map(s=>({id:s.id,t:O(s.id),action:s.action,label:Qo(s),...s.action==="move.node"?{parentId:s.payload.parent}:{},actor:D(s.userId,t.value.contributors[s.userId]?.name)}))):d("Issue not found")},lr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);return l(o)?o:Ze({node:o.value,label:"Issue description",max:2e4,description:e.description,actor:t.value.actor,stateBranchRoot:t.value.boot.stateBranchRoot})},dr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;let s=o.value,n=C(e.title);if(!n.trim())return d("Issue title cannot be empty");let a=M("Issue title",n,300);if(a)return d(a);if(s.title===n)return c("No changes made",{id:e.issueId,ref:A(e.issueId),title:n});let r={id:K(),...R(t.value.actor),action:"edit.title",payload:{id:e.issueId,name:n}},i=w([r],t.value.boot.stateBranchRoot);return l(i)?d(i.message):c("Edited issue title",{id:e.issueId,ref:A(e.issueId),title:n})};import{ulid as Z}from"ulid";var ur=async(e={})=>{let t=await L(e.repoRoot);if(l(t))return t;let o=B();if(l(o))return o;let s=Object.values(o.value.nodes).filter(n=>n.context==="BOARD"&&!n.isDeleted).map(n=>({id:n.id,ref:A(n.id),title:n.title,parentId:n.parentNodeId,readonly:!!n.readonly,...fe(n.id),goals:et(n.id)}));return c("Listed boards",s)},cr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.nodes[t.value.state.rootNodeId];if(!o)return d("Workspace not found");if(z().mode!=="live")return d("Cannot add a board while time travelling");let s=C(e.title);if(!s.trim())return d("Board title cannot be empty");let n=M("Board title",s,300);if(n)return d(n);let a=Se(o.id,t.value.actor,t.value.boot.stateBranchRoot);if(l(a))return a;let r=Z(),i={id:Z(),...R(t.value.actor),action:"add.board",payload:{id:r,name:s,parent:o.id,rank:a.value}},u=w([i],t.value.boot.stateBranchRoot);return l(u)?d(u.message):c("Created board",{id:r,ref:A(r),title:s})},mr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.nodes[e.boardId];if(!o||o.isDeleted)return d("Board not found");if(!$(o))return d("Edit target must be a board");if(o.readonly)return d("Cannot edit readonly board");if(z().mode!=="live")return d("Cannot rename a board while time travelling");let s=C(e.title);if(!s.trim())return d("Board title cannot be empty");let n=M("Board title",s,300);if(n)return d(n);if(o.title===s)return c("No changes made",{id:e.boardId,ref:A(e.boardId),title:s});let a={id:Z(),...R(t.value.actor),action:"edit.title",payload:{id:e.boardId,name:s}},r=w([a],t.value.boot.stateBranchRoot);return l(r)?d(r.message):c("Edited board title",{id:e.boardId,ref:A(e.boardId),title:s})},pr=async(e={})=>{let t=await L(e.repoRoot);if(l(t))return t;let o=B();if(l(o))return o;let s=Object.values(o.value.nodes).filter(n=>n.context==="SWIMLANE"&&!n.isDeleted).filter(n=>!e.boardId||n.parentNodeId===e.boardId).map(n=>({id:n.id,title:n.title,boardId:n.parentNodeId,isClosed:n.id===N,readonly:!!n.readonly,...fe(n.id),...H(n)?ot(n):{},countsDone:We(n.id),doneByName:H(n)&&$e(n)}));return c("Listed swimlanes",s)},fr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=Ee(e.boardId);if(l(o))return o;if(z().mode!=="live")return d("Cannot add a swimlane while time travelling");let s=C(e.title);if(!s.trim())return d("Swimlane title cannot be empty");let n=M("Swimlane title",s,300);if(n)return d(n);let a=Se(e.boardId,t.value.actor,t.value.boot.stateBranchRoot);if(l(a))return a;let r=Z(),i={id:Z(),...R(t.value.actor),action:"add.swimlane",payload:{id:r,name:s,parent:e.boardId,rank:a.value}},u=w([i],t.value.boot.stateBranchRoot);return l(u)?d(u.message):c("Created swimlane",{id:r,ref:A(r),title:s,boardId:e.boardId})},gr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=j(e.swimlaneId);if(l(o))return o;let s=o.value,n=C(e.title);if(!n.trim())return d("Swimlane title cannot be empty");let a=M("Swimlane title",n,300);if(a)return d(a);if(s.title===n)return c("No changes made",{id:e.swimlaneId,ref:A(e.swimlaneId),title:n});let r={id:Z(),...R(t.value.actor),action:"edit.title",payload:{id:e.swimlaneId,name:n}},i=w([r],t.value.boot.stateBranchRoot);return l(i)?d(i.message):c("Edited swimlane title",{id:e.swimlaneId,ref:A(e.swimlaneId),title:n})},Ir=async e=>{let t=se(e.repoRoot);if(l(t))return t;let o=W();if(l(o))return o;let s=Q({repoRoot:t.value});if(l(s))return s;let n=de(s.value);if(l(n))return n;let a=me(n.value.events,n.value.unreadable);if(l(a))return a;let r=j(e.swimlaneId);if(l(r))return r;let i=Ee(e.boardId);if(l(i))return i;let u=ce(e.boardId,e.swimlaneId,e.position??{at:"end"},o.value,s.value);if(l(u))return u;let f={id:Z(),...R(o.value),action:"move.node",payload:{id:e.swimlaneId,parent:e.boardId,rank:u.value}},g=w([f],s.value);return l(g)?d(g.message):c("Moved swimlane",{id:e.swimlaneId,ref:A(e.swimlaneId),boardId:e.boardId})},vr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=j(e.swimlaneId);if(l(o))return o;let s={id:Z(),...R(t.value.actor),action:"delete.node",payload:{id:e.swimlaneId}},n=w([s],t.value.boot.stateBranchRoot);return l(n)?d(n.message):c("Deleted swimlane",{id:e.swimlaneId,ref:A(e.swimlaneId)})};var V=e=>({path:e.path,sha:e.shas[e.shas.length-1]??""});var hr=e=>{let t=e.lastIndexOf("/");return t===-1?".":e.slice(0,t)},ws=({commits:e,patch:t})=>{let o=e.map(r=>r.time),n=t.files.map(r=>({...V(r),changed:r.addedCount+r.removed})).reduce((r,i)=>r===null||i.changed>r.changed?i:r,null),a=t.insertions+t.deletions;return{commits:e.length,authors:[...new Set(e.map(r=>r.author))].sort(),firstCommitAt:o.length?Math.min(...o):null,lastCommitAt:o.length?Math.max(...o):null,files:t.files.length,filesAdded:t.files.filter(r=>r.status==="added").length,filesModified:t.files.filter(r=>r.status==="modified").length,filesDeleted:t.files.filter(r=>r.status==="deleted").length,binaryFiles:t.files.filter(r=>r.binary).length,directories:new Set(t.files.map(r=>hr(r.path))).size,insertions:t.insertions,deletions:t.deletions,net:t.insertions-t.deletions,largestFile:n,concentration:n&&a>0?n.changed/a:0,selfChurn:t.selfChurn,truncated:t.truncated}};var P={line:["//"],block:[["/*","*/"]]},U={line:["#"],block:[]},Ot={line:["--"],block:[]},Ie={line:[],block:[["<!--","-->"]]},br={line:[],block:[]},S=(e,t)=>({name:e,comment:t}),nt=S("TypeScript",P),rt=S("JavaScript",P),Es={ts:nt,tsx:nt,mts:nt,cts:nt,js:rt,jsx:rt,mjs:rt,cjs:rt,py:S("Python",{line:["#"],block:[['"""','"""']]}),rb:S("Ruby",{line:["#"],block:[["=begin","=end"]]}),go:S("Go",P),rs:S("Rust",P),java:S("Java",P),kt:S("Kotlin",P),swift:S("Swift",P),c:S("C",P),h:S("C",P),cc:S("C++",P),cpp:S("C++",P),hpp:S("C++",P),cs:S("C#",P),php:S("PHP",P),scala:S("Scala",P),dart:S("Dart",P),lua:S("Lua",Ot),hs:S("Haskell",Ot),sql:S("SQL",Ot),ex:S("Elixir",U),exs:S("Elixir",U),pl:S("Perl",U),r:S("R",U),jl:S("Julia",U),sh:S("Shell",U),bash:S("Shell",U),zsh:S("Shell",U),vue:S("Vue",Ie),svelte:S("Svelte",Ie),html:S("HTML",Ie),xml:S("XML",Ie),md:S("Markdown",Ie),mdx:S("Markdown",Ie),css:S("CSS",{line:[],block:[["/*","*/"]]}),scss:S("CSS",P),less:S("CSS",P),yml:S("YAML",U),yaml:S("YAML",U),toml:S("TOML",U),ini:S("INI",U),json:S("JSON",br)},Rr="Other",xs=e=>{let t=e.slice(e.lastIndexOf("/")+1),o=t.lastIndexOf(".");return o<=0?"":t.slice(o+1).toLowerCase()},ae=e=>Es[xs(e)]?.name??Rr,Pe=e=>Es[xs(e)]?.comment??null,yr=[/\.(test|spec)\.[a-z0-9]+$/i,/(^|\/)test_[^/]+\.py$/,/_test\.[a-z0-9]+$/i,/(^|\/)conftest\.py$/,/Tests?\.(java|kt|cs|scala)$/],Ar=/(^|\/)(tests?|__tests__|spec|specs|e2e|src\/test|features)\//i,ve=e=>Ar.test(e)||yr.some(t=>t.test(e)),Tr=/(^|\/)(package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|go\.sum|poetry\.lock|Gemfile\.lock|composer\.lock)$/,Sr=/(^|\/)(node_modules|dist|build|out|target|vendor|coverage|\.next|__snapshots__)\//,wr=/(\.min\.(js|css)|\.map|\.snap|\.pb\.go|_pb2\.py)$/,X=e=>Tr.test(e)||Sr.test(e)||wr.test(e),Cs=e=>/(^|\/)(package\.json|go\.mod|Cargo\.toml|requirements[^/]*\.txt|pyproject\.toml|Gemfile|composer\.json|pom\.xml|build\.gradle(\.kts)?)$/.test(e),Bs=e=>/(^|\/)\.github\/workflows\//.test(e)||/(^|\/)(Dockerfile|docker-compose[^/]*\.ya?ml|Makefile|Jenkinsfile|\.gitlab-ci\.yml)$/.test(e)||/\.tf$/.test(e),Ls=e=>/\.(md|mdx|rst|txt)$/i.test(e)||/(^|\/)docs?\//i.test(e),Er=/\b(it|test|describe|context|suite)\.skip\b|\bx(it|describe|test)\s*\(|@pytest\.mark\.skip|@unittest\.skip|\bt\.Skip\s*\(|@(Ignore|Disabled)\b/,xr=/\b(it|test|describe|context|suite)\.only\b|\bf(it|describe|test)\s*\(/,ks=e=>Er.test(e),Ns=e=>xr.test(e);var Ps=/\b(TODO|FIXME|HACK|XXX)\b/,Cr=/[;{}]\s*$|^\s*(const|let|var|function|def|class|if|for|while|return|import|export|await|print)\b.*[=(]/,Mt=(e,t)=>{let o=e.trim();return o===""?"blank":t&&(t.line.some(s=>o.startsWith(s))||t.block.some(([s])=>o.startsWith(s))||t.block.some(([s])=>s==="/*")&&(o.startsWith("*")||o.startsWith("*/")))?"comment":"code"},Br=(e,t)=>{let o=e.trim();for(let s of[...t.line,...t.block.flat(),"*"])if(o.startsWith(s)){o=o.slice(s.length).trim();break}return o},Os=({patch:e,repoShareByLanguage:t})=>{let o=new Map,s=0,n=0,a=0,r=0,i=0,u=0;for(let g of e.files){if(g.binary||X(g.path))continue;let m=Pe(g.path);if(!m||m.line.length===0&&m.block.length===0)continue;let I=ae(g.path),v=o.get(I)??{comment:0,code:0};for(let{text:h}of g.added){let p=Mt(h,m);if(Ps.test(h)&&r++,p==="blank"){a++;continue}if(p==="comment"){s++,v.comment++,m&&Cr.test(Br(h,m))&&u++;continue}n++,v.code++}for(let{text:h}of g.removedLines)Ps.test(h)&&i++;o.set(I,v)}let f=s+n;return{byLanguage:[...o.entries()].map(([g,m])=>({name:g,commentLines:m.comment,codeLines:m.code,share:m.comment+m.code===0?0:m.comment/(m.comment+m.code),repoShare:t?.get(g)??null})).sort((g,m)=>m.commentLines+m.codeLines-(g.commentLines+g.codeLines)),commentLines:s,codeLines:n,blankLines:a,share:f===0?0:s/f,todoLinesAdded:r,todoLinesRemoved:i,commentedOutCodeLines:u}};var Lr=/\bconsole\.(log|debug|dir)\s*\(|\bdebugger\b|^\s*print\s*\(|\bfmt\.Print(ln|f)?\s*\(|\bSystem\.out\.print|\bdbg!\s*\(/,it=6,Dt=10,kr=e=>{let t=0;for(let o of e){if(o.trim()===""||o.startsWith(" "))continue;let s=o.length-o.trimStart().length;s>0&&(t===0||s<t)&&(t=s)}return Math.min(Math.max(t,2),8)},Nr=(e,t)=>{let o=e.length-e.trimStart().length;if(o===0)return 0;let s=e.slice(0,o).split(" ").length-1;return s>0?s:Math.floor(o/t)},Pr=e=>{if(e.length<it*2)return 0;let t=new Map,o=new Array(e.length).fill(!1);for(let s=0;s+it<=e.length;s++){let n=e.slice(s,s+it);if(n.some(i=>i.text.length<3))continue;let a=n.map(i=>i.text).join(`
|
|
5
|
-
`),r=t.get(a);if(r===void 0){t.set(a,{...n[0],at:s});continue}if(r.file!==n[0]?.file)for(let i=0;i<it;i++)o[r.at+i]=!0,o[s+i]=!0}return o.filter(Boolean).length},Ms=({patch:e})=>{let t=[],o=[],s=[],n=!1,a=0,r=0,i=null,u=[];for(let[f,g]of e.files.entries()){if(X(g.path)&&t.push(V(g)),Cs(g.path)&&o.push(V(g)),Bs(g.path)&&s.push(V(g)),Ls(g.path)&&(n=!0),g.binary||X(g.path))continue;let m=g.added.map(h=>h.text),I=kr(m),v=g.status!=="deleted";for(let h of m){Lr.test(h)&&a++;let p=Nr(h,I);p>r&&(r=p,i=V(g)),v&&u.push({text:h.trim(),file:f})}u.push({text:" ",file:f})}return{generatedPaths:t.slice(0,Dt),dependencyManifests:o.slice(0,Dt),buildOrCiPaths:s.slice(0,Dt),docsTouched:n,debugPrintLinesAdded:a,maxIndentLevels:r,deepestFile:i,duplicatedLines:Pr(u)}};var Ds=({patch:e,languagesBefore:t})=>{let o=new Map,s=0;for(let r of e.files){if(r.binary)continue;let i=r.addedCount+r.removed;if(X(r.path)){s+=i;continue}let u=ae(r.path),f=o.get(u)??{name:u,added:0,removed:0,addedInTests:0,share:0};f.added+=r.addedCount,f.removed+=r.removed,ve(r.path)&&(f.addedInTests+=r.addedCount),o.set(u,f)}let n=[...o.values()].reduce((r,i)=>r+i.added+i.removed,0),a=[...o.values()].map(r=>({...r,share:n===0?0:(r.added+r.removed)/n})).sort((r,i)=>i.added+i.removed-(r.added+r.removed));return{languages:a,introduced:t===null?[]:a.filter(r=>!t.has(r.name)).map(r=>r.name),generatedLines:s}};var Or=200,Ft=2e5,Mr=5e4,Dr=25,Fs=64*1024*1024,_t="",Fr=/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/,_r=/^diff --git a\/(.+) b\/\1$/,_s=(e,t)=>e==="/dev/null"?null:e.startsWith(t)?e.slice(2):e,Gs=(e,t)=>e===null?"added":t===null?"deleted":"modified",Gr=()=>({byPath:new Map,insertions:0,deletions:0,selfChurn:0,retainedLines:0}),$r=(e,t)=>{let o=e.byPath,s="",n=null,a=null,r=null,i=!1,u=0,f=(m,I)=>I==="modified"&&m==="added"?"added":I,g=(m,I)=>{let v=o.get(m);if(v)return v.entry.status=f(v.entry.status,I),v.entry.shas.includes(s)||v.entry.shas.push(s),v;let p={entry:{path:m,status:I,binary:!1,added:[],addedCount:0,removed:0,removedLines:[],shas:[s]},pendingByText:new Map};return o.set(m,p),p};for(let m of t.split(`
|
|
6
|
-
`)){if(m.startsWith(_t)){s=m.slice(_t.length).trim(),n=null,a=null,r=null,i=!1;continue}if(m.startsWith("diff --git ")){n=null,r=null,i=!0,a=_r.exec(m)?.[1]??null;continue}if(i&&m.startsWith("Binary files ")&&a){let[,v=""]=/^Binary files (.*) differ$/.exec(m)??[],[h="",p=""]=v.split(" and ");n=g(a,Gs(h==="/dev/null"?null:h,p==="/dev/null"?null:p)),n.entry.binary=!0;continue}if(i&&m.startsWith("--- ")){r=_s(m.slice(4),"a/");continue}if(i&&m.startsWith("+++ ")){let v=_s(m.slice(4),"b/"),h=v??r??a;h&&(n=g(h,Gs(r,v)));continue}let I=Fr.exec(m);if(I){u=Number(I[1]),i=!1;continue}if(n){if(m.startsWith("+")){let v=m.slice(1);e.insertions++,n.entry.addedCount++,e.retainedLines<Ft&&(n.entry.added.push({sha:s,line:u,text:v}),e.retainedLines++),n.pendingByText.size<Mr&&n.pendingByText.set(v,(n.pendingByText.get(v)??0)+1),u++;continue}if(m.startsWith("-")){let v=m.slice(1);e.deletions++,n.entry.removed++,e.retainedLines<Ft&&(n.entry.removedLines.push({sha:s,line:0,text:v}),e.retainedLines++);let h=n.pendingByText.get(v)??0;h>0&&v.trim().length>2&&(e.selfChurn++,n.pendingByText.set(v,h-1))}}}},Wr=e=>({files:[...e.byPath.values()].map(t=>t.entry),insertions:e.insertions,deletions:e.deletions,selfChurn:e.selfChurn,retainedLines:e.retainedLines});var $s=async({repoRoot:e,shas:t,cwdOf:o=()=>e})=>{if(t.length===0)return c("No commits to scan",{files:[],insertions:0,deletions:0,selfChurn:0,scannedCommits:0,truncated:!1});let s=t.slice(0,Or).reverse(),n=Gr(),a=0,r=0,i=!1,u=[];for(let g of s){let m=o(g),I=u[u.length-1];I&&I.cwd===m&&I.shas.length<Dr?I.shas.push(g):u.push({cwd:m,shas:[g]})}for(let{cwd:g,shas:m}of u){let I=await De({cwd:g,maxOutput:Math.max(1,Fs-a),keepPartial:!0,args:["-c","core.quotePath=false","show","--unified=0","--no-renames","--no-color",`--format=${_t}%H`,...m]});if(l(I)){if(g!==e)continue;return d(I.message)}if($r(n,I.value.stdout),a+=I.value.stdout.length,r+=m.length,I.value.truncated||a>Fs){i=!0;break}}let f=Wr(n);return c("Scanned ticket patch",{files:f.files,insertions:f.insertions,deletions:f.deletions,selfChurn:f.selfChurn,scannedCommits:r,truncated:i||r<t.length||f.retainedLines>=Ft})};var jr=40,Ur=/^\d{6} blob ([0-9a-f]{40})\t(.+)$/,Ws=async({repoRoot:e,sha:t})=>{let o=await Fe({cwd:e,args:["-c","core.quotePath=false","ls-tree","-r",`${t}~1`]});if(o.exitCode!==0)return null;let s=new Set,n=new Map;for(let g of o.stdout.split(`
|
|
7
|
-
`)){let m=Ur.exec(g);if(!m)continue;let[,I="",v=""]=m;if(X(v))continue;let h=ae(v);if(s.add(h),ve(v)||!Pe(v))continue;let p=n.get(h)??[];p.length<jr&&(p.push({blob:I,path:v}),n.set(h,p))}let a=[...n.values()].flat(),r=await Wt(a.map(g=>g.blob),e);if(l(r))return{languages:s,commentShareByLanguage:new Map};let i=r.value,u=new Map;for(let{blob:g,path:m}of a){let I=i.get(g);if(I===void 0)continue;let v=Pe(m),h=ae(m),p=u.get(h)??{comment:0,code:0};for(let b of I.split(`
|
|
8
|
-
`)){let T=Mt(b,v);T==="comment"&&p.comment++,T==="code"&&p.code++}u.set(h,p)}let f=new Map;for(let[g,m]of u){let I=m.comment+m.code;I>0&&f.set(g,m.comment/I)}return{languages:s,commentShareByLanguage:f}};var js=({patch:e})=>{let t=0,o=0,s=[],n=[],a=0,r=0;for(let i of e.files)if(!(i.binary||X(i.path))&&ve(i.path)){t+=i.addedCount,o+=i.removed,i.status==="added"&&s.push(V(i)),i.status==="deleted"&&n.push(V(i));for(let{text:u}of i.added)ks(u)&&a++,Ns(u)&&r++}return{testLinesAdded:t,testLinesRemoved:o,addedTestFiles:s,deletedTestFiles:n,skippedTestLinesAdded:a,focusedTestLinesAdded:r}};var Hr=e=>e.reduce((t,o)=>t===null||o.time<t.time?o:t,null),Us=async({repoRoot:e,ref:t,commits:o})=>{let s=await Co(e);if(l(s))return d(s.message);let n=Bo(s.value),a=new Map(o.map(m=>[m.sha,m.repo])),r=m=>n(a.get(m))??e,i=await $s({repoRoot:e,shas:o.map(m=>m.sha),cwdOf:r});if(l(i))return d(i.message);let u=i.value,f=Hr(o),g=f?await Ws({repoRoot:r(f.sha),sha:f.sha}):null;return c("Derived issue stats",{ref:t,shape:ws({commits:o,patch:u}),languages:Ds({patch:u,languagesBefore:g?.languages??null}),tests:js({patch:u}),comments:Os({patch:u,repoShareByLanguage:g?.commentShareByLanguage??null}),flags:Ms({patch:u})})};var at=e=>{if(l(e))return e;let t=Xe(),o=l(t)?{}:t.value.emailLinks,s=l(t)?{}:t.value.contributors,n=oo(o),a=e.value.map(r=>({...r,authorIdentity:qo({authorName:r.author,authorEmail:r.authorEmail,owners:n,registry:s})}));return c(e.message,a)};var Kr=32,Oe=new Map;var Xr=(e,t)=>{if(Oe.set(e,t),Oe.size>Kr){let o=Oe.keys().next();o.done||Oe.delete(o.value)}return t},Hs=e=>{let t=at(e);return l(t)?d(t.message):c("Matched commits by ref",t.value.map(o=>({sha:o.sha,...o.repo?{repo:o.repo}:{},time:o.time,author:o.authorIdentity?.resolved?o.authorIdentity.name:o.author,subject:o.subject})))},zs=e=>{let t=_e(e??process.cwd());return l(t)?d(t.message):t},Ks=async(e,t,o)=>{let s=[e,t,o.map(r=>`${r.sha}:${r.author}`).join(",")].join(" "),n=Oe.get(s);if(n)return c("Derived issue stats",n);let a=await Us({repoRoot:e,ref:t,commits:o});return l(a)?d(a.message):c("Derived issue stats",Xr(s,a.value))},yc=async(e={idOrRef:""})=>{let t=e.idOrRef.trim();if(!t)return d("idOrRef must not be empty");let o=t.length>7?A(t):t.toUpperCase(),s=zs(e.repoRoot);if(l(s))return s;let n=Hs(await Lo({repoRoot:s.value,ref:o,end:e.end}));return l(n)?n:Ks(s.value,o,n.value)},Xs=async e=>{let t=zs(e.repoRoot);if(l(t))return t;let o=Hs(await ze({repoRoot:t.value,refs:e.refs,end:e.end}));return l(o)?o:Ks(t.value,e.label,o.value)};var qs=e=>{let t=B();if(l(t))return t;let o=je(e);return o?c("Found goal",{id:o.id,refs:mo(o.id).map(s=>A(s.id))}):d(`No goal called or with the id "${e}"`)},Vs=async e=>{let t=qs(e.goal);return l(t)?t:Xs({repoRoot:e.repoRoot,label:t.value.id,refs:t.value.refs,end:e.end})},qr=async e=>{let t=qs(e.goal);return l(t)?t:_o(e.repoRoot,at(await ze({repoRoot:e.repoRoot,refs:t.value.refs,end:e.end})))},Vr=async e=>{let t=await L(e.repoRoot);return l(t)?t:Vs({repoRoot:t.value.repoRoot,goal:e.goal})};import{ulid as he}from"ulid";async function Yr(e){let t=await L(e.repoRoot);if(l(t))return t;let o=W();if(l(o))return o;let s=ke(e);if(l(s))return s;let n=C(e.tagName).trim();if(!n)return d("Tag name cannot be empty");let a=M("Tag name",n,60);if(a)return d(a);let r=Ne(s.value,k);if(!e.issueIds&&r.failed[0])return d(r.failed[0].reason);if(r.done.length===0)return d(ge("Tagged",r).message);let i=_.findTagByName(n),u=i?.id??he(),f=[...i?[]:[{id:he(),...R(o.value),action:"create.tag",payload:{id:u,name:n}}],...r.done.map(({id:v})=>({id:he(),...R(o.value),action:"add.issue.tag",payload:{id:v,tag:u}}))],g=w(f,t.value.stateBranchRoot);if(l(g))return d(g.message);let m={id:u,name:n};if(!e.issueIds)return c("Added issue tag",{...r.done[0],tag:m});let I=ge("Tagged",r);return l(I)?I:c(I.message,{...I.value,tag:m})}var Jr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.tags[e.tagId];if(!o)return d("Tag not found");if(o.tombstoned)return d("Tag is already deleted");let s=[{id:he(),...R(t.value.actor),action:"tombstone.tag",payload:{id:e.tagId}}],n=w(s,t.value.boot.stateBranchRoot);return l(n)?d(n.message):c("Deleted tag",{id:o.id,name:o.name})},Qr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.tags[e.tagId];if(!o)return d("Tag not found");if(!o.tombstoned)return d("Tag is not deleted");if(_.findTagByName(o.name))return d(`Cannot restore: another tag is already named "${o.name}"`);let s=[{id:he(),...R(t.value.actor),action:"restore.tag",payload:{id:e.tagId,name:o.name}}],n=w(s,t.value.boot.stateBranchRoot);return l(n)?d(n.message):c("Restored tag",{id:o.id,name:o.name})},Zr=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;if(!t.value.state.tags[e.tagId])return d("Tag not found");let s={id:he(),...R(t.value.actor),action:"remove.issue.tag",payload:{id:e.issueId,tag:e.tagId}},n=w([s],t.value.boot.stateBranchRoot);return l(n)?d(n.message):c("Removed issue tag",{id:e.issueId,ref:A(e.issueId),tagId:e.tagId})};import{ulid as J}from"ulid";var ei=async e=>{let t=$t(e.name,"name");if(l(t))return d(t.message);let o=await y(e.repoRoot);if(l(o))return o;let s=o.value.actor,n=!!o.value.state.contributors[s.userId];if(!n){let r=w([{id:J(),...R(s),action:"create.contributor",payload:{id:s.userId,name:s.userName}}],o.value.boot.stateBranchRoot);if(l(r))return d(r.message)}let a=Object.values(o.value.state.nodes).filter(r=>$(r)&&!r.isDeleted).flatMap(r=>{let{boardDescription:i}=xe(r.id);return i?[{id:r.id,title:C(r.title),boardDescription:i}]:[]});return c(`Assumed ${s.userName}`,{...s,registered:!n,...a.length?{boards:a}:{}})},Ys=async(e,t)=>{let o=ue(e).get(t);return o===void 0?void 0:{id:t,name:o}},ti=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;let s=e.self?t.value.actor.userId:e.assigneeId;if(s){let v=t.value.state.contributors[s],h=v?void 0:await Ys(t.value.boot.stateBranchRoot,s);if(!v&&!h)return d("Unknown assignee id");let p=v??h,b=[...v?[]:[{id:J(),...R(t.value.actor),action:"create.contributor",payload:{id:p.id,name:p.name}}],{id:J(),...R(t.value.actor),action:"add.issue.assignee",payload:{id:e.issueId,assignee:p.id}}],T=w(b,t.value.boot.stateBranchRoot);return l(T)?d(T.message):c("Added issue assignee",{id:e.issueId,ref:A(e.issueId),assignee:{id:p.id,name:p.name}})}let n=C(e.assigneeName??"").trim();if(!n)return d("Provide assigneeId, self or assigneeName");let a=M("Assignee name",n,80);if(a)return d(a);let r=At({events:t.value.state.eventLog??[],registry:t.value.state.contributors,logFileNames:ue(t.value.boot.stateBranchRoot)}).filter(v=>v.name===n);if(r.length>1)return d(`"${n}" matches ${r.length} contributors (${r.map(({id:v})=>v).join(", ")}). Assign by assigneeId to choose.`);let i=r[0];if(!i&&!e.createUnlinked)return d(`No contributor named "${n}". Assign by id, or pass createUnlinked to add them as an external assignee.`);let u=i?.id??J(),f=i?.name??n,m=[...!!t.value.state.contributors[u]?[]:[{id:J(),...R(t.value.actor),action:"create.contributor",payload:{id:u,name:f}}],{id:J(),...R(t.value.actor),action:"add.issue.assignee",payload:{id:e.issueId,assignee:u}}],I=w(m,t.value.boot.stateBranchRoot);return l(I)?d(I.message):c("Added issue assignee",{id:e.issueId,ref:A(e.issueId),assignee:{id:u,name:f}})},oi=async e=>{let t=await y(e.repoRoot);if(l(t))return t;if(!t.value.state.contributors[e.contributorId])return d("Contributor not found");if(await Ys(t.value.boot.stateBranchRoot,e.contributorId))return d("Cannot remove a contributor who has authored events \u2014 their name appears throughout the log");let n=[{id:J(),...R(t.value.actor),action:"tombstone.contributor",payload:{id:e.contributorId}}],a=w(n,t.value.boot.stateBranchRoot);return l(a)?d(a.message):c("Tombstoned contributor",{id:e.contributorId,name:Ge})},si=async(e,t)=>{let o=oe(e);if(l(o))return;let s;for(let n of o.value){if(n.action!=="create.contributor")continue;let a=n.payload;a.id===t&&a.name&&(s=a.name)}return s},ni=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.contributors[e.contributorId];if(!o)return d("Contributor not found");if(!o.tombstoned)return d("Contributor is not tombstoned");let s=await si(t.value.boot.stateBranchRoot,e.contributorId);if(!s)return d("Cannot restore this contributor \u2014 no original name found in the event log");let n=[{id:J(),...R(t.value.actor),action:"restore.contributor",payload:{id:e.contributorId,name:s}}],a=w(n,t.value.boot.stateBranchRoot);return l(a)?d(a.message):c("Restored contributor",{id:e.contributorId,name:s})},ri=async(e={})=>{let t=await y(e.repoRoot);if(l(t))return t;let o=oe(t.value.boot.stateBranchRoot);if(l(o))return d(o.message);let s=e.boardId?ns(o.value,e.boardId):o.value,n=new Set,a=wo(t.value.boot.stateBranchRoot);if(l(a))return d(a.message);for(let u of a.value)u.userId&&n.add(u.userId);let r=t.value.state.contributors,i=At({events:s,registry:r,logFileNames:ue(t.value.boot.stateBranchRoot)}).map(({id:u,name:f,isExternal:g})=>({...D(u,f),isSelf:u===t.value.actor.userId,isExternal:g,isRemoved:r[u]?.tombstoned===!0,hasAuthoredAnywhere:n.has(u)}));return c("Listed board contributors",i)},ii=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;if(!t.value.state.contributors[e.assigneeId])return d("Assignee not found");let s={id:J(),...R(t.value.actor),action:"remove.issue.assignee",payload:{id:e.issueId,assignee:e.assigneeId}},n=w([s],t.value.boot.stateBranchRoot);return l(n)?d(n.message):c("Removed issue assignee",{id:e.issueId,ref:A(e.issueId),assigneeId:e.assigneeId})};import{ulid as dt}from"ulid";var ai=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=k(e.issueId);if(l(o))return o;let s=e.body.trim();if(!s)return d("Comment cannot be empty");if(s.length>4e3)return d(`Comment cannot exceed ${4e3} characters (got ${s.length})`);let n=dt(),a={id:dt(),...R(t.value.actor),action:"add.issue.comment",payload:{id:n,issue:e.issueId,md:s,author:t.value.actor.userId}},r=w([a],t.value.boot.stateBranchRoot);return l(r)?d(r.message):c("Added issue comment",{id:n,issueId:e.issueId,body:s})},li=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.eventLog.find(i=>i.action==="add.issue.comment"&&i.payload.id===e.commentId);if(!o)return d("Unable to resolve comment");if(o.payload.author!==t.value.actor.userId)return d("You can only delete your own comments");let s=k(o.payload.issue);if(l(s))return s;if(t.value.state.eventLog.some(i=>i.action==="delete.issue.comment"&&i.payload.id===e.commentId))return c("Comment already deleted",{id:e.commentId,issueId:o.payload.issue});let a={id:dt(),...R(t.value.actor),action:"delete.issue.comment",payload:{id:e.commentId,issue:o.payload.issue}},r=w([a],t.value.boot.stateBranchRoot);return l(r)?d(r.message):c("Deleted issue comment",{id:e.commentId,issueId:o.payload.issue})},di=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=t.value.state.eventLog.find(u=>u.action==="add.issue.comment"&&u.payload.id===e.commentId);if(!o)return d("Unable to resolve comment");if(o.payload.author!==t.value.actor.userId)return d("You can only edit your own comments");let s=k(o.payload.issue);if(l(s))return s;if(t.value.state.eventLog.some(u=>u.action==="delete.issue.comment"&&u.payload.id===e.commentId))return d("Comment was deleted");let a=e.body.trim();if(!a)return d("Comment cannot be empty");if(a.length>4e3)return d(`Comment cannot exceed ${4e3} characters (got ${a.length})`);let r={id:dt(),...R(t.value.actor),action:"edit.issue.comment",payload:{id:e.commentId,issue:o.payload.issue,md:a}},i=w([r],t.value.boot.stateBranchRoot);return l(i)?d(i.message):c("Edited issue comment",{id:e.commentId,issueId:o.payload.issue,body:a})};import{ulid as Js}from"ulid";var ui=async e=>{let t=await y(e.repoRoot);if(l(t))return t;if(!Zt(e.email))return d(`Not an email address: ${e.email}`);let o=ye(e.email),s=e.contributorId??t.value.actor.userId;if(!t.value.state.contributors[s])return d(`Unknown contributor: ${s}`);let n=ct(t.value.state.emailLinks,o);if(n.includes(s))return c(`${o} is already yours`,{contributor:s,email:o,contested:n.filter(r=>r!==s)});let a=w([{id:Js(),action:"link.contributor.email",payload:{contributor:s,email:o},userId:t.value.actor.userId}],t.value.boot.stateBranchRoot);return l(a)?d(a.message):c(n.length>0?`Claimed ${o}, but somebody else claims it too, so it now resolves to neither of you`:`Claimed ${o}`,{contributor:s,email:o,contested:n})},ci=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let o=ye(e.email),s=e.contributorId??t.value.actor.userId,n=t.value.state.emailLinks[eo(o,s)];if(!n||n.tombstoned)return d(`No such link: ${o} to ${s}`);if(!so(t.value.actor.userId,n))return d("Only whoever made a claim, or the contributor it names, may undo it");let a=w([{id:Js(),action:"unlink.contributor.email",payload:{contributor:s,email:o},userId:t.value.actor.userId}],t.value.boot.stateBranchRoot);return l(a)?d(a.message):c(`Unclaimed ${o}`,{contributor:s,email:o})},mi=async(e={})=>{let t=await L(e.repoRoot);if(l(t))return t;let o=B();if(l(o))return o;let{emailLinks:s,contributors:n}=o.value,a=new Map;for(let m of Object.values(s)){if(m.tombstoned)continue;let I=a.get(m.email)??new Set;I.add(m.contributor),a.set(m.email,I)}let r=[...a.entries()].map(([m,I])=>({email:m,contested:I.size>1,claimants:[...I].map(v=>D(v,n[v]?.name))})).sort((m,I)=>m.email.localeCompare(I.email)),i=W(),u=l(i)?[]:to(s,i.value.userId),f=Ut().gitEmail,g=f?ct(s,f).filter(m=>l(i)||m!==i.value.userId):[];return c("Listed contributor emails",{emails:r,mine:u,git:f?{email:f,linkedToMe:u.includes(f),heldByOthers:g.map(m=>D(m,n[m]?.name))}:null})},pi=async(e={})=>{let t=await y(e.repoRoot);if(l(t))return t;let{userId:o,userName:s}=t.value.actor,n=le(t.value.boot.repoRoot),a=await Ke({repoRoot:t.value.boot.repoRoot,stateBranch:l(n)?void 0:n.value,names:[s,await pe(t.value.boot.repoRoot)],links:t.value.state.emailLinks});if(l(a))return a;let r=Vo(a.value),i=r.filter(u=>u.looksLikeYours);return c(r.length===0?"No unclaimed addresses in this history":`${r.length} unclaimed address(es) in this history, ${i.length>0?`${i.length} of which look like yours`:"none obviously yours"}. Show them to the user and link only the ones they confirm; each is a permanent event that replicates to every clone.`,{contributor:o,candidates:r,likely:i.length})};var Gt=e=>{let t=ko(e);return l(t)?d(t.message):c("Listed repos",{repos:t.value,claimedBytes:Do(e),limit:Kt,allowLocal:zt()})},fi=async(e={})=>{let t=Te(e.repoRoot);return l(t)?d(t.message):Gt(t.value)},gi=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let{repoRoot:o}=t.value.boot,s=await Fo({repoRoot:o,actorId:t.value.actor.userId,url:e.url,branches:e.branches,since:e.since,label:e.label,mode:e.previewOnly?"preview":e.confirm?"confirm":"auto"});if(l(s))return d(s.message);let n=Gt(o);return l(n)?d(n.message):c(s.message,{...n.value,...s.value.kind==="preview"?{preview:s.value.preview}:{}})},Ii=async e=>{let t=await y(e.repoRoot);if(l(t))return t;let{repoRoot:o}=t.value.boot,s=No({repoRoot:o,actorId:t.value.actor.userId,repo:e.repo});if(l(s))return d(s.message);let n=Gt(o);return l(n)?d(n.message):c(s.message,n.value)},vi=e=>(Mo("repo"in e?e.repo:Xt(e.url.trim())),c("Cancelled",null)),hi=async(e,t={},o=2e4)=>{if(l(e))return e;let s,n=await Promise.race([Qs(t),new Promise(a=>{s=setTimeout(()=>a(null),o)})]);return clearTimeout(s),n===null?c(`${e.message} \xB7 still fetching other repos; epiq_repo_list shows how they stand`,e.value):l(n)||n.value.length===0?e:c([e.message,Oo(n.value)].filter(Boolean).join(" \xB7 "),{...e.value,repos:n.value})},Qs=async(e={})=>{let t=Te(e.repoRoot);return l(t)?d(t.message):Po({repoRoot:t.value,minIntervalMs:e.minIntervalMs})};var Zs=(e,t)=>{let o=0,s=0,n=null;for(let a of e){if(a.userId!==t)continue;a.action==="add.issue"&&o++,a.action==="add.issue.comment"&&s++;let r=Jt(a.id);if(l(r))continue;let i=r.value.getTime();(n===null||i<n)&&(n=i)}return{tickets:o,comments:s,joinedAt:n}};var bi=async(e={})=>{let t=await y(e.repoRoot);if(l(t))return t;let{userId:o,userName:s}=t.value.actor,n=Zs(t.value.state.eventLog,o),a=le(t.value.boot.repoRoot),r=await Ke({repoRoot:t.value.boot.repoRoot,stateBranch:l(a)?void 0:a.value,names:[s,await pe(t.value.boot.repoRoot)],links:t.value.state.emailLinks}),i=l(r)?[]:r.value.filter(u=>u.claimedBy.length===1&&u.claimedBy[0]===o);return c("Derived personal stats",{...n,scanned:!l(r),commits:i.reduce((u,f)=>u+f.commits,0),claimedEmails:i.length})};var en=e=>{if(e.length===0)return null;let t=Math.floor(e.length/2);return e.length%2===0?(e[t-1]+e[t])/2:e[t]};var Ri=8,yi=(e,t)=>{let o=new Date(e);return o.setHours(0,0,0,0),o.setDate(o.getDate()-(o.getDay()+6)%7),Array.from({length:t},(s,n)=>{let a=new Date(o);return a.setDate(o.getDate()-7*(t-1-n)),a.getTime()})},Ai=e=>en([...e].sort((t,o)=>t-o)),tn=({boardId:e,lanes:t,formerLaneIds:o=[],tickets:s,now:n})=>{let a=new Map(t.map((E,x)=>[E.id,x])),r=new Set(o),i=E=>E!=null&&(a.has(E)||r.has(E)),f=s.map(E=>({ticket:E,visits:Lt(E.log,E.createdAt)})).filter(({visits:E})=>E.some(x=>i(x.laneId))),g=E=>{let x=te(E);return x===null?null:Math.min(Re(x,n),n)},m=E=>{let x=E.flatMap(q=>{let G=a.get(q.laneId);return G===void 0?[]:[G]});return x.some((q,G)=>G>0&&q<x[G-1])},I=f.flatMap(({ticket:E,visits:x})=>{let q=E.log.findLast(be=>be.action==="close.issue");if(!q||i(E.parentNodeId))return[];let G=g(q),sn=x.at(-2)?.laneId;if(G===null||!i(sn))return[];let nn=x.slice(0,-1).flatMap((be,rn)=>i(be.laneId)?[{laneId:be.laneId,ms:x[rn+1].enteredAt-be.enteredAt}]:[]);return[{closedAt:G,leadTime:G-E.createdAt,sentBack:m(x),stays:nn}]}),v=yi(n,Ri),h=v[0],p=I.filter(E=>E.closedAt>=h),b=v.map((E,x)=>{let q=v[x+1]??1/0;return{t:E,closed:p.filter(G=>G.closedAt>=E&&G.closedAt<q).length}}),T=new Map;for(let{stays:E}of p)for(let{laneId:x,ms:q}of E)T.set(x,(T.get(x)??0)+q);let Y=t.reduce((E,x)=>E+(T.get(x.id)??0),0),on=t.flatMap(E=>{let x=T.get(E.id)??0;return x<=0?[]:[{laneId:E.id,title:E.title,meanMs:x/p.length,share:x/Y}]});return{boardId:e,throughput:b,filed:f.filter(({ticket:E,visits:x})=>E.createdAt>=h&&i(x[0]?.laneId)).length,closed:p.length,medianLeadTimeMs:Ai(p.map(E=>E.leadTime)),sentBackShare:p.length===0?null:p.filter(E=>E.sentBack).length/p.length,laneTime:on}};var Ti=e=>{let t=B();if(l(t))return t;let o=Object.values(t.value.nodes),s=o.find(r=>r.id===e.boardId);if(!s||s.isDeleted||!$(s))return d("Board not found");let n=o.filter(r=>H(r)&&r.parentNodeId===s.id),a=n.filter(r=>!r.isDeleted).sort((r,i)=>r.rank.localeCompare(i.rank));return c("Derived board overview",tn({boardId:s.id,lanes:a,formerLaneIds:n.filter(r=>r.isDeleted).map(r=>r.id),tickets:o.filter(r=>!r.isDeleted).filter(F).map(r=>({id:r.id,parentNodeId:r.parentNodeId,log:r.log??[],createdAt:O(r.id)})),now:Date.now()}))};export{Lt as a,us as b,z as c,Ji as d,xn as e,Qi as f,Zi as g,fs as h,pe as i,B as j,Nn as k,Pn as l,On as m,Mn as n,vs as o,Dn as p,Fn as q,Gn as r,Un as s,Hn as t,zn as u,Xn as v,Vn as w,kt as x,Jn as y,Qn as z,Zn as A,er as B,tr as C,sr as D,nr as E,ir as F,ar as G,lr as H,dr as I,ur as J,cr as K,mr as L,pr as M,fr as N,gr as O,Ir as P,vr as Q,at as R,yc as S,Vs as T,qr as U,Vr as V,Yr as W,Jr as X,Qr as Y,Zr as Z,ei as _,ti as $,oi as aa,ni as ba,ri as ca,ii as da,ai as ea,li as fa,di as ga,ui as ha,ci as ia,mi as ja,pi as ka,bi as la,fi as ma,gi as na,Ii as oa,vi as pa,hi as qa,Qs as ra,en as sa,Ti as ta};
|
package/dist/chunk-BGP4XGKD.js
DELETED
package/dist/server-OJXRDAZM.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{$ as ye,A as W,B as V,C as Z,D as ee,E as te,F as ie,H as oe,I as ne,J as se,K as re,L as ae,M as le,N as ce,O as de,P as pe,Q as me,S as he,V as ue,W as ge,X as fe,Y as we,Z as be,_ as _e,aa as ve,b as R,ba as qe,ca as Ie,da as ke,ea as Se,fa as Re,ga as Te,ha as Ee,i as O,ia as je,ja as xe,k as D,ka as Ne,l as $,m as B,ma as Ae,n as F,na as Ce,o as H,oa as Pe,p as z,q as K,qa as Le,r as X,s as J,v as Q,z as Y}from"./chunk-BE2ONDXH.js";import{b as N,ca as M,dc as U,h as A,ja as G,l as C,m as P,vb as S,x as L}from"./chunk-4BPR3FGA.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 Ye}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as We}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as e}from"zod";import{ulid as Ke}from"ulid";var Me=[{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)"}],Ge=t=>t.trim().toLowerCase(),Ue=async(t={})=>{let o=C();if(a(o))return r(o.message);let n=o.value,l=t.userName?.trim(),E=(process.env[x]??"").trim();if(l&&E&&Ge(l)===Ge(E))return r(`userName "${l}" 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:l||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 Me){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 c={};if(p.userName&&!g.userName&&(c.userName=p.userName),p.preferredEditor&&!g.preferredEditor&&(c.preferredEditor=p.preferredEditor),p.autoSync!==void 0&&g.autoSync===void 0&&(c.autoSync=p.autoSync),(c.userName||g.userName)&&!n.userId&&(c.userId=Ke()),Object.keys(c).length>0){let s=P(c);if(a(s))return r(s.message)}let q={...n,...c},I=Me.filter(s=>{let d=q[s.name];return typeof d=="boolean"?!1:!d?.trim()});if(I.length>0){let s=I.map(y=>`${y.name} (${y.question})`).join("; "),d=I.some(y=>y.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:q.userId??"",userName:q.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:et,..._}=k.value,j=M({root:_.repoRoot});a(j)&&N.info(j.message);let ze=_.warnings.length===0?"Project initialized":`Project initialized, with warnings: ${_.warnings.join(" ")}`;return w(ze,{..._,user:b})};import v from"node:fs";import Oe from"node:path";var m=".claude/skills/epiq/SKILL.md",T=`---
|
|
3
|
-
name: epiq
|
|
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
|
-
---
|
|
6
|
-
|
|
7
|
-
# Epiq board workflow
|
|
8
|
-
|
|
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 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.
|
|
16
|
-
- **Read a ticket's comments before starting.**
|
|
17
|
-
- **Board and lane descriptions describe team conventions** (\`boardDescription\`, \`laneDescription\` in responses): follow them unless they conflict with your user's instructions.
|
|
18
|
-
- **Picking up a ticket:** assign yourself and move it to the in-progress lane. Ask before taking one assigned to someone else.
|
|
19
|
-
- **Keep status, tags and description current**; reuse existing tags.
|
|
20
|
-
- **Goals group tickets that serve one outcome, on any board.** Put a ticket in one with \`epiq_issue_goal_set\` (\`goal\`: its name, created if new, or null to take it out). A ticket has at most one goal; \`epiq_goal_list\` shows every goal and its progress.
|
|
21
|
-
- **Comment** on deviations, blockers, and the outcome when done.
|
|
22
|
-
- **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 \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.
|
|
24
|
-
- **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.
|
|
25
|
-
- *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.
|
|
26
|
-
- **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.
|
|
27
|
-
- **Be concise, use clear language.** Titles, descriptions, and comments should be scannable, easy to understand, not essays.
|
|
28
|
-
- **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
|
-
- **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
|
-
- On rebase or merge, make sure Epiq refs survive. Dropping them from commit messages breaks commit linking.
|
|
31
|
-
`;var De=async(t={})=>{let o=await A(t.repoRoot??process.cwd());if(a(o))return r(o.message);let n=Oe.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(Oe.dirname(n),{recursive:!0}),v.writeFileSync(n,T,"utf8")}catch(l){return r(l instanceof Error?`Failed to write ${m}: ${l.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))),Ve="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 Ye({name:"epiq",version:"0.2.30"},{instructions:Ve});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(Q)),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(V)),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(W)),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 he(o))),t.registerTool("epiq_board_list",{description:"List Epiq boards",inputSchema:e.object({repoRoot:e.string().optional()})},i(se)),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(re)),t.registerTool("epiq_swimlane_list",{description:"List Epiq swimlanes",inputSchema:e.object({repoRoot:e.string().optional(),boardId:e.string().optional()})},i(le)),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(ce)),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(de)),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(ae)),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($)),t.registerTool("epiq_swimlane_rule_set",{description:"Turn a swimlane rule on or off. The one rule is `done`: an open ticket in a lane with it counts as done for its goal. A lane named Done always counts.",inputSchema:e.object({repoRoot:e.string().optional(),swimlaneId:e.string().min(1),rule:e.enum(G),on:e.boolean()})},i(X)),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(pe)),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(me)),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(oe)),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(ne)),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(ge)),t.registerTool("epiq_issue_goal_set",{description:"Put an Epiq issue in a goal (a group of tickets serving one outcome, on any board), by the goal's name or id, creating the goal if there is none of that name; null takes it out. One goal per ticket. epiq_goal_list lists every goal with its progress.",inputSchema:e.object({issueId:e.string().min(1),goal:e.string().min(1).nullable(),repoRoot:e.string().optional()})},i(F)),t.registerTool("epiq_goal_list",{description:"List the goals in the project: each a group of tickets serving one outcome, with done/total (done is closed, or in a done lane: see epiq_swimlane_rule_set) and the boards its tickets are on. Put a ticket in one with epiq_issue_goal_set; epiq_goal_stats gives its code stats.",inputSchema:e.object({repoRoot:e.string().optional()})},i(B)),t.registerTool("epiq_goal_stats",{description:"Code stats for a goal, by its name or id: epiq_issue_stats over every commit of every ticket in it, each commit counted once. Its `ref` field holds the goal id, not a ticket ref.",inputSchema:e.object({goal:e.string().min(1),repoRoot:e.string().optional()})},i(ue)),t.registerTool("epiq_goal_create",{description:"Create a goal with no tickets yet. To create one and put a ticket in it at once, use epiq_issue_goal_set with the new name.",inputSchema:e.object({name:e.string().min(1),repoRoot:e.string().optional()})},i(H)),t.registerTool("epiq_goal_rename",{description:"Rename a goal; its colour and tickets stay. Ids are in epiq_goal_list.",inputSchema:e.object({goalId:e.string().min(1),name:e.string().min(1),repoRoot:e.string().optional()})},i(z)),t.registerTool("epiq_goal_remove",{description:"Remove a goal; its tickets stay where they are, in no goal. Ids are in epiq_goal_list.",inputSchema:e.object({goalId:e.string().min(1),repoRoot:e.string().optional()})},i(K)),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(be)),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(Ie)),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(ve)),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(fe)),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(we)),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(qe)),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(ye)),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(ke)),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(Se)),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(J)),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(Re)),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(Te)),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(te)),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(ee)),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(ie)),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(_e)),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(Ee)),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(je)),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(Ne)),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(xe)),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(Ue)),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(De)),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 Le(await R(()=>Y(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 Ae(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 Ce(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 Pe(o))),t},Pt=async()=>{let t=Ze(),o=new We;await t.connect(o)};export{Ve as MCP_INSTRUCTIONS,Ze as createMcpServer,u as resultJson,Pt as startMcpServer};
|