@lovek4d/kickflip 0.7.8 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -681,4 +681,4 @@ moves every Linear board to no ticket source. If the source can't make a ticket,
681
681
  (overnight, snoozed or the weekend). --urgent: a
682
682
  production fault only; it beats those holds. While
683
683
  notifications are off every push is dropped, urgent too
684
- KICKFLIP_PUSH_CMD='["<cmd>","<arg>"]' replaces \`node ../../bin/kickflip.mjs push\`; the flags follow it`;class d extends Error{static{i(this,"UsageError")}}const re=new Set(["new-ticket","done","clear-status","clear-next","urgent","now","clear-eta","held","unheld","idle","wait","hub","clear-install","force","worktree","dispatch","writes"]);function oe(e){const a=Object.create(null),t=[];for(let s=0;s<e.length;s++){const r=e[s];if(!r.startsWith("--")){t.push(r);continue}const o=r.slice(2);if(re.has(o)){if(Object.hasOwn(a,o))throw new d(`--${o} is given twice`);a[o]=!0}else if(s+1<e.length)(a[o]||=[]).push(e[++s]);else throw new d(`--${o} needs a value`)}return{flags:a,rest:t}}i(oe,"parse");function de(e,a,t){const s=new Set(a.filter(l=>l.startsWith("...")).map(l=>l.slice(3))),r=new Set(a.map(l=>l.replace(/^\.\.\./,""))),o=Object.keys(t).filter(l=>!r.has(l));if(o.length)throw new d(`${e} does not take ${o.map(l=>"--"+l).join(", ")}`);return Object.fromEntries(Object.entries(t).map(([l,c])=>{if(c===!0||s.has(l))return[l,c];if(c.length>1)throw new d(`--${l} is given twice`);return[l,c[0]]}))}i(de,"flagsOf");const le=["text","note","notes","heading","summary","title","body","next","progress","install-label","confirmed","asked","task","reason"],he=/^(?:\/|~\/|\.{1,2}\/)\S*\.(?:html?|md|json|txt)$/;function ce(e){const a=e.trim();if(!a||/\s/.test(a))return!1;if(he.test(a))return!0;try{return g.statSync(a).isFile()}catch{return!1}}i(ce,"looksLikePath");function ue(e,a){for(const t of le){if(typeof a[t]!="string"||!ce(a[t]))continue;const s=e.includes("file")?`; for a file use --file ${a[t].trim()}`:"";throw new d(`--${t} takes text, not a file path (${a[t].trim()})${s}`)}if(typeof a.file=="string"&&a.file!=="-"&&!g.existsSync(a.file))throw new d(`--file ${a.file}: no such file`)}i(ue,"checkInputs");const w=i(e=>g.readFileSync(e==="-"?0:e,"utf8"),"readInput");function q(e){if(!e)throw new d("--file <path> is required");try{return JSON.parse(w(e))}catch(a){throw new n.BoardError(`${e}: ${a.message}`)}}i(q,"readJSONInput");function C(e,a){const t=["notes-file","plan"].find(s=>e[s]!==void 0);if(t)throw new d(`--${t} is gone: the board names a card's notes file, <id>-notes.md, and writes it itself; ${a}`)}i(C,"refuseNotesFile");function N(e){if(e.note!==void 0&&e.file!==void 0)throw new d("pass --note or --file, not both");return e.file===void 0?e.note:w(e.file)}i(N,"noteOf");async function pe(e,a,{"owner-step":t,check:s,text:r,...o}){if(t!==void 0&&(!e||o.dir))throw new d("--owner-step goes on a board card: pass --site, not --dir");if(s!==void 0&&t===void 0)throw new d("--check goes with --owner-step: it is the code check that closes the card once the step is done");t!==void 0&&await n.setItem(e,a,{ownerStep:t,check:s});const l=e&&!o.dir,c=l&&await n.handBackCalls(e,a,o);if(c)return c;if(l&&o.next===void 0&&await n.finishesCard(e,a,o)){if(r===void 0)throw new n.BoardError(`builder done finishes ${a}: pass --text "<what you checked>", or --next "<what happens next>" to stop without finishing`);return $(e,a,{text:r,ownerStep:t})}if(l&&await n.isHelper(e,a,o.agent)){if(r===void 0)throw new d('a helper hands back its result: pass --text "<what you did or found>"');return n.stopBuilder(e,a,{...o,note:r})}if(l&&r!==void 0&&await n.isPlanner(e,a,o.agent))return n.stopBuilder(e,a,{...o,note:r,requireNext:!0});if(r!==void 0)throw new d("--text goes on a builder done that finishes the card, the main build with a worktree and no --next, or on a helper's or a planner's");return n.stopBuilder(e,a,{...o,requireNext:!0})}i(pe,"builderDone");const b={pr:[["file/id"],[],async(e,[a])=>({lines:(await n.prReport(e,a)).map(t=>JSON.stringify(t))})],"pr comment":[["pr"],["body"],(e,[a],t)=>{if(t.body===void 0)throw new d('pr comment needs --body "<what Claude says>"');return n.postPR(e,a,{body:t.body})}],"pr reply":[["pr","comment-id"],["body"],(e,[a,t],s)=>{if(s.body===void 0)throw new d('pr reply needs --body "<what Claude says>"');return n.postPR(e,a,{replyTo:t,body:s.body})}],reply:[["eventId"],["text","file","title"],(e,[a],t)=>{if(t.text===void 0==(t.file===void 0))throw new d("reply takes --text or --file");const s=t.text??w(t.file);return a.includes("/")?n.answerCard(e,a,s,t.title):n.writeReply(e,a,s,t.title)}],thread:[["file/id"],["text","link","who","via"],(e,[a],t)=>n.appendMessage(e,a,t)],"visual add":[["file/id"],["file","title"],(e,[a],t)=>n.addVisual(e,a,t)],"topic add":[["id"],["title","summary"],(e,[a],t)=>n.addTopic(e,{id:a,...t})],"question add":[[],["file"],async(e,a,t)=>{const s=q(t.file);return{...await n.addQuestions(e,s,process.env.KICKFLIP_RENDER_CHECK==="off"?void 0:se),asked:[s].flat()}}],"question resolve":[["id"],["note"],(e,[a],t)=>n.resolveQuestion(e,a,t.note)],"question settle":[["id"],["note"],(e,[a],t)=>n.settleQuestion(e,a,t.note)],"question publish":[["key"],[],async(e,[a])=>({ids:await n.publishScreened(e,a)})],"question move":[["ids"],["to","block"],(e,[a],t)=>n.moveQuestions(e,a.split(",").filter(Boolean),t.to,(t.block||"").split(",").filter(Boolean))],"prototype add":[["topic"],["title","...take","card","served","...state"],(e,[a],t)=>n.addPrototype(e,{topic:a,title:t.title,card:t.card,takes:t.take,served:t.served,states:t.state})],"prototype base":[[],[],e=>ne(e)],"prototype list":[[],[],e=>n.listPrototypes(e)],"prototype rm":[["topic"],[],(e,[a])=>n.removePrototype(e,a)],"item set":[["file/id"],["done","split-into","status","clear-status","next","clear-next","...pr","pushed","gh-since","from-ask","phase","state","held","unheld","pick-up-at","notes-file","plan","deps","blocked-until","block-reason","parent","related","relate","unrelate","install","install-sha","install-label","clear-install","title","size","model","force","ticket","new-ticket","text","check"],async(e,[a],t,s)=>(C(t,`add to its notes with item notes ${a} --heading "<heading>" --file <draft.md>`),t.done&&e&&await n.checkNotReopened(e,a),n.setItem(e,a,{done:t.done,splitInto:t["split-into"],status:t.status,clearStatus:t["clear-status"],next:t.next,clearNext:t["clear-next"],pr:t.pr,pushed:t.pushed,ghSince:t["gh-since"],fromAsk:t["from-ask"],phase:t.phase,state:t.state,held:t.held,unheld:t.unheld,pickUpAt:t["pick-up-at"],deps:t.deps,blockedUntil:t["blocked-until"],blockReason:t["block-reason"],parent:t.parent,related:t.related,relate:t.relate,unrelate:t.unrelate,install:t.install,installSha:t["install-sha"],installLabel:t["install-label"],clearInstall:t["clear-install"],title:t.title,size:t.size,model:t.model,force:t.force,ticket:t.ticket,newTicket:t["new-ticket"],text:t.text,check:t.check},s))],"item add":[["file[/id]"],["title","notes","notes-from","deps","notes-file","plan","ticket","new-ticket","pick-up-at","held","parent","size","model","phase","state","relate","from-ask","text"],(e,[a],t,s)=>{if(C(t,"seed a new card's notes with item add --notes-from <draft.md>"),t.notes!==void 0&&t["notes-from"]!==void 0)throw new d("pass --notes or --notes-from, not both");return n.addItem(e,a,{title:t.title,notes:t.notes,notesFrom:t["notes-from"],deps:t.deps,ticket:t.ticket,newTicket:t["new-ticket"],pickUpAt:t["pick-up-at"],held:t.held,parent:t.parent,size:t.size,model:t.model,phase:t.phase,state:t.state,relate:t.relate,fromAsk:t["from-ask"],text:t.text,intake:!0},s)}],"item notes":[["file/id"],["heading","file","from"],(e,[a],t)=>{if(t.heading===void 0&&t.from===void 0)throw new d(`item notes needs --heading "<the section's title>"`);if(t.file===void 0==(t.from===void 0))throw new d("item notes takes --file <draft.md> or --from <file>/<id>");return n.addNotes(e,a,t)}],"item relate-ask":[["eventId","file/id"],["summary","title"],(e,[a,t],s)=>n.relateAsk(e,a,t,s.summary,s.title)],"ask unfold":[["eventId"],[],(e,[a])=>n.unfoldAsk(e,a)],"ask move":[["eventId"],["to"],(e,[a],t)=>n.moveAsk(e,a,t.to)],"wave create":[["slug"],["title","goal","...card","note","file"],(e,[a],t)=>n.createWave(e,a,{title:t.title,goal:t.goal,cards:t.card,note:N(t)})],"wave add":[["slug","file/id"],["after"],(e,[a,t],s)=>n.changeWave(e,a,{add:t,after:s.after})],"wave remove":[["slug","file/id"],[],(e,[a,t])=>n.changeWave(e,a,{remove:t})],"wave set":[["slug","...file/id?"],["after","title","goal","note","file"],(e,[a,...t],s)=>{if(t.length>1)throw new d("wave set takes <slug> [<file/id>]");return n.changeWave(e,a,{card:t[0],after:s.after,title:s.title,goal:s.goal,note:N(s)})}],"wave finish":[["slug"],[],(e,[a])=>n.finishWave(e,a)],slack:[[],[],()=>({lines:[JSON.stringify(D())]})],"slack set":[[],["self-dm","user","domain","timezone"],async(e,a,t)=>{const s={"self-dm":"self_dm",user:"owner_slack_user",domain:"slack_domain",timezone:"timezone"};try{return{lines:[JSON.stringify(await M(Object.fromEntries(Object.entries(t).map(([r,o])=>[s[r],o]))))]}}catch(r){throw new n.BoardError(r.message)}}],integrations:[[],[],async()=>({lines:[JSON.stringify(await H.rows())]})],"review updated":[["file/id"],["text"],(e,[a],t)=>n.reviewUpdated(e,a,t.text)],"review record":[["pr"],["state","text","file"],(e,[a],t)=>{if(t.text===void 0==(t.file===void 0))throw new d("review record takes --text or --file");return n.recordReview(e,a,{state:t.state,text:t.text??w(t.file)})}],"review post":[["pr"],["file","read-at"],(e,[a],t)=>{if(t.file===void 0)throw new d("review post needs --file <review.md>");if(t["read-at"]===void 0)throw new d("review post needs --read-at <time>, when you read the PR, so a review that landed since is caught");return n.postIncomingReview(e,a,{words:w(t.file),readAt:t["read-at"]})}],"review digest":[[],[],async(e,a,t,s)=>({lines:[JSON.stringify(await n.reviewDigest(e,s))]})],"review due":[[],[],async(e,a,t,s)=>({lines:[JSON.stringify(await n.reviewDue(e,s))]})],"reviewers set":[[],["file"],(e,a,t)=>n.setReviewers(e,q(t.file))],"reviewers add":[[],["file"],(e,a,t)=>n.addReviewers(e,q(t.file))],"reviewers remove":[["...name"],[],(e,a)=>n.removeReviewers(e,a)],"rules list":[[],[],e=>n.listRules(e)],"rules add":[[],["text","hub","by"],(e,a,t)=>n.addRuleTo(e,t)],"rules edit":[["id"],["text","hub"],(e,[a],t)=>n.editRuleIn(e,a,t)],"rules remove":[["id"],["hub"],(e,[a],t)=>n.removeRuleFrom(e,a,t)],settings:[[],[],async e=>({lines:[JSON.stringify(await n.readBoardSettings(e))]})],build:[["file/id"],["asked"],async(e,[a],t)=>{if(!e)throw new n.BoardError("build needs --site <route>");n.parseKey(a);const s=await n.askedGate(e,a,t.asked);try{const r=await fetch(`http://127.0.0.1:${process.env.KICKFLIP_HUB_PORT||4500}/_hub/build`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({route:x.basename(e),key:a}),signal:AbortSignal.timeout(1e4)}),o=await r.json();if(!r.ok)throw new n.BoardError(o.error||"The hub refused the build.");return{lines:["started",...(await n.appendMessage(e,a,{text:s})).lines]}}catch(r){throw r instanceof n.BoardError?r:new n.BoardError(`Could not start the build: ${r.message}`)}}],"main set":[[],["install","install-sha"],(e,a,t)=>n.setMainInstall(e,{install:t.install,installSha:t["install-sha"]})],"settings set":[["name","value"],[],(e,[a,t])=>n.setBoardSetting(e,a,t)],"builder start":[["file/id"],["label","phase","progress","dir","agent","kind","model","eta","worktree","repo","dispatch"],(e,[a],{worktree:t,repo:s,dispatch:r,...o})=>{if(s!==void 0&&!t)throw new d("--repo goes with --worktree");const l=i(p=>z(e,a.split("/")[1],{repo:s,...p}),"make"),c=e&&o.dir===void 0&&ae(e);return n.startBuilder(e,a,{...o,dispatch:r?"session":void 0,worktree:t?l:void 0,ownWorktree:c?l:void 0})}],"builder progress":[["file/id","...text?"],["phase","text","dir","agent","eta","clear-eta"],(e,[a,...t],s)=>{if(t.length&&s.text!==void 0)throw new d("builder progress takes its text once: as words or as --text");if(!t.length&&s.text===void 0)throw new d("builder progress needs its text, as words or as --text");return n.builderProgress(e,a,s.text??t.join(" "),{...s,clearEta:s["clear-eta"]})}],"builder done":[["file/id"],["dir","agent","next","owner-step","check","text","updated"],async(e,[a],{updated:t,...s})=>{const r=e&&!s.dir;if(r&&t===void 0&&await n.cardLinked(e,a))throw new n.BoardError(`a reviewer has ${a}'s PR link: pass --updated "<what changed>" for its thread, or --updated none for a change only to comments, names, docs or tests`);const o=await pe(e,a,s);return r&&t!==void 0&&t.trim().toLowerCase()!=="none"&&await n.reviewUpdated(e,a,t),o}],"builder pick":[["file/id"],[],(e,[a])=>n.pickBuilder(e,a)],"agent launch":[["file/id"],["name","task","writes","model"],(e,[a],t)=>n.requestHelper(e,a,t)],"agent wait":[["file/id"],["name","agent","timeout"],(e,[a],t)=>n.waitHelper(e,a,{...t,alive:Q})],"agent merge":[["file/id"],["name"],async(e,[a],t)=>{const{record:s,card:r}=await n.helperOf(e,a,t.name);if(!s.done)throw new n.BoardError(`helper ${t.name} is still open; run agent wait ${a} --name ${t.name} first`);if(!s.writes||!s.worktree)throw new n.BoardError(`helper ${t.name} writes no code, so there is nothing to merge`);if(!r)throw new n.BoardError(`${a} has no worktree to merge helper ${t.name} into`);return G(r,s.worktree)}],audit:[["...file/id?"],[],(e,[a,...t])=>{if(t.length)throw new d("audit takes one <file/id> at most");return n.auditLog(e,a)}],"builder call":[["file/id","...text"],["dir","agent"],(e,[a,...t],s)=>n.recordCall(e,a,t.join(" "),s)],"builder calls":[["file/id"],["dir","agent"],(e,[a],t)=>n.listCalls(e,a,t)],"builder ask":[["file/id","...text"],["agent"],(e,[a,...t],s)=>n.askOrchestrator(e,a,t.join(" "),s)],"builder answer":[["file/id","ask"],["text"],(e,[a,t],s)=>n.answerBuilder(e,a,t,s.text)],"builder defer":[["file/id","ask"],["text"],(e,[a,t],s)=>n.answerBuilder(e,a,t,s.text,{deferred:!0})],"builder asks":[["file/id"],["wait","timeout"],(e,[a],t)=>n.listAsks(e,a,t)],"builder verified":[["file/id"],["dir","agent","note"],async(e,[a],t)=>{await n.verifyCalls(e,a,t);const s=e&&!t.dir?await n.verifiedFinish(e,a):null;if(!s)return{};if(s.waits.length)return{lines:[`${await n.cardName(e,a)} finishes once the owner answers ${s.waits.join(", ")}`]};try{return await $(e,a,{text:t.note??"Judgment calls verified."})}catch(r){throw r instanceof n.BoardError?Object.assign(new n.BoardError(`judgment calls verified, but ${await n.cardName(e,a)} didn't finish: ${r.message}`),{exitCode:r.exitCode}):r}}],land:[["file/id"],["repo","dir","text","owner-step","check"],async(e,[a],t)=>{const s=a.split("/")[1];if(e&&t.text===void 0)throw new d(`land needs --text "<what was checked>", which closes ${a} as done once it lands`);if(!e&&t.text!==void 0)throw new d("--text closes the card, which needs --site");if(!e&&t["owner-step"]!==void 0)throw new d("--owner-step keeps a board card open, which needs --site");if(t.check!==void 0&&t["owner-step"]===void 0)throw new d("--check goes with --owner-step: it is the code check that closes the card once the step is done");if(e&&t.dir===void 0)return $(e,a,{text:t.text,ownerStep:t["owner-step"],check:t.check,repo:t.repo});const r=e?await n.cardName(e,a):void 0,o=await U(r??a,async()=>{e&&await n.checkClose(e,a,t.text,t["owner-step"],t.check),await n.checkCallsVerified(e,a,{dir:t.dir});const l=await n.recordedWorktree(e,a,{dir:t.dir}),{repo:c,base:p}=J(e,{repo:t.repo??l?.repo});return await F({path:l?.path??x.join(K(),s),branch:l?.branch??s,repo:x.resolve(c),base:p,ref:r}),e?n.setItem(e,a,{done:!0,text:t.text,ownerStep:t["owner-step"],check:t.check}):{lines:[]}});return o.joined?{lines:[`joined the land already running for ${r??a}`]}:o}],"builder stop":[["file/id"],[],(e,[a])=>ee(m(e,"builder stop"),a)],"item stall":[["file/id"],["reason"],(e,[a],t)=>Y(m(e,"item stall"),a,t.reason)],"land stop":[["file/id"],[],(e,[a])=>te(m(e,"land stop"),a)],"land queue":[[],[],()=>Z()],"item bump":[["file/id"],[],(e,[a])=>S(m(e,"item bump"),a,!0)],"item unbump":[["file/id"],[],(e,[a])=>S(m(e,"item unbump"),a,!1)],lander:[["file/id"],[],async(e,[a])=>{if(!e)throw new d("lander needs --site <route>");return await n.relaunchLander(e,a),{lines:[`${await n.cardName(e,a)} is handed back again; the server launches a lander for it within a minute`]}}],merge:[["file/id"],["after-approval","confirmed"],async(e,[a],t)=>e&&await n.heldMerge(e,a)?X(e,a):n.mergeCard(e,a,{afterApproval:t["after-approval"],confirmed:t.confirmed})],"arch file":[["file/id"],[],(e,[a])=>e?V(e,a):Promise.reject(new n.BoardError("arch file needs --site <route>"))],push:[[],["kind","title","body","url","tag","urgent","now"],(e,a,t)=>{if(t.kind!=="fault"&&t.kind!=="reminder")throw new d(`a session pushes only --kind fault or reminder${t.kind===void 0||t.kind===!0?"":`, not "${t.kind}"`}: the board server pushes Action needed, and news goes on the board`);if(t.title===void 0)throw new d("push needs --title");return n.sendPush(e,t)}]};b.install=b.build;function m(e,a){if(!e)throw new d(`${a} needs --site <route>`);return e}i(m,"needSite");const h=i((e,a)=>n.cardName(e,a),"card"),R=i((e,a)=>`${a}${e.length===1?"":"s"} ${e.join(", ")}`,"plural"),T=i(e=>e.agent===void 0||e.agent==="main"?"builder":`builder ${e.agent}`,"builderOf");function we(e){const a=e["pick-up-at"];return[e.done&&(e["split-into"]?`done, split into ${e["split-into"].split(",").join(", ")}`:"done"),e.next!==void 0&&(e.next.trim()?"next line set":"next line cleared"),e["clear-next"]&&"next line cleared",e.pr!==void 0&&`PR #${e.pr}`,e.pushed!==void 0&&`pushed ${e.pushed}`,e["gh-since"]&&`GitHub read to ${e["gh-since"]}`,e["from-ask"]&&`from task ${e["from-ask"]}`,e.phase,e.held&&"held",e.unheld&&"resumed",a!==void 0&&(a?`held until ${a}`:"resumed"),e.deps!==void 0&&(e.deps?`blocked by ${e.deps}`:"deps cleared"),e.parent!==void 0&&(e.parent?`parent ${e.parent}`:"parent cleared"),e.related!==void 0&&(e.related?`related to ${e.related.split(",").join(", ")}`:"related cleared"),e.relate!==void 0&&`related to ${e.relate.split(",").join(", ")} added`,e.unrelate!==void 0&&`unrelated from ${e.unrelate.split(",").join(", ")}`,e.install!==void 0&&"install published",e["clear-install"]&&"install cleared",e.title!==void 0&&"renamed",e.ticket!==void 0&&`ticket ${e.ticket}`,e["new-ticket"]&&"ticket made",e.check!==void 0&&(e.check.trim()?`check ${e.check.trim().split(/\s+/).join(" ")}`:"check removed")].filter(Boolean).join(", ")}i(we,"itemChanges");const me={reply:i(async(e,[a])=>a.includes("/")?`answered ${await h(e,a)}: it waits in In Review for the owner's Done`:`reply written to ${await n.eventCard(e,a)}`,"reply"),thread:i(async(e,[a])=>`thread line on ${await h(e,a)}`,"thread"),"topic add":i((e,[a])=>`topic ${a} added`,"topic add"),"question add":i(async(e,a,t,{asked:s,staged:r})=>{const o=[...new Set(s.map(c=>c.topic))],l=o.length!==1?"":o[0].startsWith("item:")?` on ${await h(e,o[0].slice(5))}`:` on topic ${o[0]}`;return`${R(s.map(c=>c.id),"question")} ${r===s.length?"staged":"added"}${l}`},"question add"),"question resolve":i((e,[a])=>`question ${a} resolved`,"question resolve"),"question settle":i((e,[a])=>`question ${a} settled`,"question settle"),"question publish":i(async(e,[a],t,{ids:s})=>`${R(s,"question")} on ${await h(e,a)} passed to the owner`,"question publish"),"question move":i((e,[a],t)=>`questions ${a} merged onto ${t.to}`,"question move"),"prototype add":i(async(e,[a],t)=>`prototype ${a} recorded${t.card?` for ${await h(e,t.card)}`:""}`,"prototype add"),"prototype rm":i((e,[a])=>`prototype ${a} removed`,"prototype rm"),"item set":i(async(e,[a],t)=>`${await h(e,a)}: ${we(t)}`,"item set"),"item add":i(async(e,a,t,{key:s})=>`${await h(e,s)} added as ${s}`,"item add"),"item notes":i(async(e,[a],t,{file:s,heading:r})=>`${await h(e,a)}: notes section "${r}" added to ${s}`,"item notes"),"item relate-ask":i(async(e,[a,t])=>`task ${a} folded into ${await h(e,t)}`,"item relate-ask"),"ask unfold":i((e,[a])=>`task ${a} back on a card of its own`,"ask unfold"),"ask move":i((e,[a],t)=>`task ${a} moved to /${t.to}`,"ask move"),"wave create":i((e,[a])=>`wave ${a} created`,"wave create"),"wave add":i(async(e,[a,t])=>`${await h(e,t)} added to wave ${a}`,"wave add"),"wave remove":i(async(e,[a,t])=>`${await h(e,t)} taken out of wave ${a}`,"wave remove"),"wave set":i((e,[a])=>`wave ${a} updated`,"wave set"),"wave finish":i((e,[a])=>`wave ${a} finished`,"wave finish"),"review record":i((e,[a],t)=>`review of PR #${a} recorded: ${t.state==="needs"?"needs you":"posted"}`,"review record"),"reviewers set":i(()=>"reviewers replaced","reviewers set"),"reviewers add":i(()=>"reviewers added","reviewers add"),"reviewers remove":i((e,a)=>`${R(a,"reviewer")} removed`,"reviewers remove"),"rules add":i((e,a,t)=>`${t.hub?"hub":"board"} rule added`,"rules add"),"rules edit":i((e,[a],t)=>`${t.hub?"hub":"board"} rule ${a} reworded`,"rules edit"),"rules remove":i((e,[a],t)=>`${t.hub?"hub":"board"} rule ${a} removed`,"rules remove"),"builder start":i(async(e,[a],t,s)=>`${await h(e,a)}: ${s.alreadyOpen?"already open: the Implement tap opened its record; launch the agent, whose own builder start takes it up":`${T(t)} started`}`,"builder start"),"builder progress":i(async(e,[a])=>`progress line on ${await h(e,a)}`,"builder progress"),"builder done":i(async(e,[a],t,s)=>`${await h(e,a)}: ${s?.said??`${T(t)} done${t["owner-step"]===void 0?"":`; owner step "${t["owner-step"].trim()}"`}`}`,"builder done"),"builder call":i(async(e,[a])=>`judgment call recorded on ${await h(e,a)}`,"builder call"),"builder ask":i(async(e,[a],t,{id:s})=>`${await h(e,a)}: asked the orchestrator, ${s}`,"builder ask"),"builder answer":i(async(e,[a,t])=>`${await h(e,a)}: ${t} answered`,"builder answer"),"builder defer":i(async(e,[a,t])=>`${await h(e,a)}: ${t} deferred to the owner`,"builder defer"),"builder verified":i(async(e,[a],t,s)=>`${await h(e,a)}: judgment calls verified${s?.said?`; ${s.said}`:""}`,"builder verified"),land:i(async(e,[a],t,s)=>e?s?.said?`${await h(e,a)}: ${s.said}`:t["owner-step"]===void 0?`${await h(e,a)}: landed and done`:`${await h(e,a)}: landed; waits on the owner step "${t["owner-step"].trim()}"`:null,"land"),merge:i(async(e,[a],t,s)=>`${await h(e,a)}: ${s?.said??"merged"}`,"merge"),"arch file":i(async(e,[a])=>`findings of ${await h(e,a)} filed`,"arch file")};async function fe(e,a={}){try{const{flags:t,rest:s}=oe(e),r=[3,2,1].map(u=>s.slice(0,u).join(" ")).find(u=>y(b,u)),o=y(b,r);if(!o)throw new d(s.length?`unknown command "${s.slice(0,2).join(" ")}"`:"no command given");const[l,c,p]=o,f=s.slice(r.split(" ").length),_=l.at(-1)?.startsWith("..."),B=l.at(-1)?.endsWith("?")?l.length-1:l.length;if(_?f.length<B:f.length!==l.length)throw new d(`${r} takes ${l.map(u=>`<${u.replace(/^\.\.\.|\?$/g,"")}>`).join(" ")||"no arguments"}`);const{site:A,...E}=t;if(A?.length>1)throw new d("--site is given twice");const I=A?.[0],k=de(r,c,E);ue(c,k);const P=I===void 0?null:await n.siteDir(I),v=await p(P,f,k,a),O=y(me,r),j=O&&await O(P,f,k,v);j&&console.log(j);for(const u of typeof v=="object"&&v?.lines||[])console.log(u);return 0}catch(t){if(t instanceof d)return console.error(`${t.message} (node board.mjs --help lists the commands)`),2;if(t instanceof n.BoardError)return console.error(t.message),t.exitCode??1;throw t}}if(i(fe,"main"),process.argv[1]&&import.meta.url===L(g.realpathSync(process.argv[1])).href){const e=process.argv.slice(2);!e.length||e.includes("--help")||e[0]==="help"?console.log(ie):process.exitCode=await fe(e)}export{ie as USAGE,fe as main};
684
+ KICKFLIP_PUSH_CMD='["<cmd>","<arg>"]' replaces \`node ../../bin/kickflip.mjs push\`; the flags follow it`;class d extends Error{static{i(this,"UsageError")}}const re=new Set(["new-ticket","done","clear-status","clear-next","urgent","now","clear-eta","held","unheld","idle","wait","hub","clear-install","force","worktree","dispatch","writes"]);function oe(e){const a=Object.create(null),t=[];for(let s=0;s<e.length;s++){const r=e[s];if(!r.startsWith("--")){t.push(r);continue}const o=r.slice(2);if(re.has(o)){if(Object.hasOwn(a,o))throw new d(`--${o} is given twice`);a[o]=!0}else if(s+1<e.length)(a[o]||=[]).push(e[++s]);else throw new d(`--${o} needs a value`)}return{flags:a,rest:t}}i(oe,"parse");function de(e,a,t){const s=new Set(a.filter(l=>l.startsWith("...")).map(l=>l.slice(3))),r=new Set(a.map(l=>l.replace(/^\.\.\./,""))),o=Object.keys(t).filter(l=>!r.has(l));if(o.length)throw new d(`${e} does not take ${o.map(l=>"--"+l).join(", ")}`);return Object.fromEntries(Object.entries(t).map(([l,c])=>{if(c===!0||s.has(l))return[l,c];if(c.length>1)throw new d(`--${l} is given twice`);return[l,c[0]]}))}i(de,"flagsOf");const le=["text","note","notes","heading","summary","title","body","next","progress","install-label","confirmed","asked","task","reason"],he=/^(?:\/|~\/|\.{1,2}\/)\S*\.(?:html?|md|json|txt)$/;function ce(e){const a=e.trim();if(!a||/\s/.test(a))return!1;if(he.test(a))return!0;try{return g.statSync(a).isFile()}catch{return!1}}i(ce,"looksLikePath");function ue(e,a){for(const t of le){if(typeof a[t]!="string"||!ce(a[t]))continue;const s=e.includes("file")?`; for a file use --file ${a[t].trim()}`:"";throw new d(`--${t} takes text, not a file path (${a[t].trim()})${s}`)}if(typeof a.file=="string"&&a.file!=="-"&&!g.existsSync(a.file))throw new d(`--file ${a.file}: no such file`)}i(ue,"checkInputs");const w=i(e=>g.readFileSync(e==="-"?0:e,"utf8"),"readInput");function q(e){if(!e)throw new d("--file <path> is required");try{return JSON.parse(w(e))}catch(a){throw new n.BoardError(`${e}: ${a.message}`)}}i(q,"readJSONInput");function C(e,a){const t=["notes-file","plan"].find(s=>e[s]!==void 0);if(t)throw new d(`--${t} is gone: the board names a card's notes file, <id>-notes.md, and writes it itself; ${a}`)}i(C,"refuseNotesFile");function N(e){if(e.note!==void 0&&e.file!==void 0)throw new d("pass --note or --file, not both");return e.file===void 0?e.note:w(e.file)}i(N,"noteOf");async function pe(e,a,{"owner-step":t,check:s,text:r,...o}){if(t!==void 0&&(!e||o.dir))throw new d("--owner-step goes on a board card: pass --site, not --dir");if(s!==void 0&&t===void 0)throw new d("--check goes with --owner-step: it is the code check that closes the card once the step is done");t!==void 0&&await n.setItem(e,a,{ownerStep:t,check:s});const l=e&&!o.dir,c=l&&await n.handBackCalls(e,a,o);if(c)return c;if(l&&o.next===void 0&&await n.finishesCard(e,a,o)){if(r===void 0)throw new n.BoardError(`builder done finishes ${a}: pass --text "<what you checked>", or --next "<what happens next>" to stop without finishing`);return $(e,a,{text:r,ownerStep:t})}if(l&&await n.isHelper(e,a,o.agent)){if(r===void 0)throw new d('a helper hands back its result: pass --text "<what you did or found>"');return n.stopBuilder(e,a,{...o,note:r})}if(l&&r!==void 0&&await n.isPlanner(e,a,o.agent))return n.stopBuilder(e,a,{...o,note:r,requireNext:!0});if(r!==void 0)throw new d("--text goes on a builder done that finishes the card, the main build with a worktree and no --next, or on a helper's or a planner's");return n.stopBuilder(e,a,{...o,requireNext:!0})}i(pe,"builderDone");const b={pr:[["file/id"],[],async(e,[a])=>({lines:(await n.prReport(e,a)).map(t=>JSON.stringify(t))})],"pr comment":[["pr"],["body"],(e,[a],t)=>{if(t.body===void 0)throw new d('pr comment needs --body "<what Claude says>"');return n.postPR(e,a,{body:t.body})}],"pr reply":[["pr","comment-id"],["body"],(e,[a,t],s)=>{if(s.body===void 0)throw new d('pr reply needs --body "<what Claude says>"');return n.postPR(e,a,{replyTo:t,body:s.body})}],reply:[["eventId"],["text","file","title"],(e,[a],t)=>{if(t.text===void 0==(t.file===void 0))throw new d("reply takes --text or --file");const s=t.text??w(t.file);return a.includes("/")?n.answerCard(e,a,s,t.title):n.writeReply(e,a,s,t.title)}],thread:[["file/id"],["text","link","who","via"],(e,[a],t)=>n.appendMessage(e,a,t)],"visual add":[["file/id"],["file","title"],(e,[a],t)=>n.addVisual(e,a,t)],"topic add":[["id"],["title","summary"],(e,[a],t)=>n.addTopic(e,{id:a,...t})],"question add":[[],["file"],async(e,a,t)=>{const s=q(t.file);return{...await n.addQuestions(e,s,process.env.KICKFLIP_RENDER_CHECK==="off"?void 0:se),asked:[s].flat()}}],"question resolve":[["id"],["note"],(e,[a],t)=>n.resolveQuestion(e,a,t.note)],"question settle":[["id"],["note"],(e,[a],t)=>n.settleQuestion(e,a,t.note)],"question publish":[["key"],[],async(e,[a])=>({ids:await n.publishScreened(e,a)})],"question move":[["ids"],["to","block"],(e,[a],t)=>n.moveQuestions(e,a.split(",").filter(Boolean),t.to,(t.block||"").split(",").filter(Boolean))],"prototype add":[["topic"],["title","...take","card","served","...state"],(e,[a],t)=>n.addPrototype(e,{topic:a,title:t.title,card:t.card,takes:t.take,served:t.served,states:t.state})],"prototype base":[[],[],e=>ne(e)],"prototype list":[[],[],e=>n.listPrototypes(e)],"prototype rm":[["topic"],[],(e,[a])=>n.removePrototype(e,a)],"item set":[["file/id"],["done","split-into","status","clear-status","next","clear-next","...pr","pushed","gh-since","from-ask","phase","state","held","unheld","pick-up-at","notes-file","plan","deps","blocked-until","block-reason","parent","related","relate","unrelate","install","install-sha","install-label","clear-install","title","size","model","force","ticket","new-ticket","text","check"],async(e,[a],t,s)=>(C(t,`add to its notes with item notes ${a} --heading "<heading>" --file <draft.md>`),t.done&&e&&await n.checkNotReopened(e,a),n.setItem(e,a,{done:t.done,splitInto:t["split-into"],status:t.status,clearStatus:t["clear-status"],next:t.next,clearNext:t["clear-next"],pr:t.pr,pushed:t.pushed,ghSince:t["gh-since"],fromAsk:t["from-ask"],phase:t.phase,state:t.state,held:t.held,unheld:t.unheld,pickUpAt:t["pick-up-at"],deps:t.deps,blockedUntil:t["blocked-until"],blockReason:t["block-reason"],parent:t.parent,related:t.related,relate:t.relate,unrelate:t.unrelate,install:t.install,installSha:t["install-sha"],installLabel:t["install-label"],clearInstall:t["clear-install"],title:t.title,size:t.size,model:t.model,force:t.force,ticket:t.ticket,newTicket:t["new-ticket"],text:t.text,check:t.check},s))],"item add":[["file[/id]"],["title","notes","notes-from","deps","notes-file","plan","ticket","new-ticket","pick-up-at","held","parent","size","model","phase","state","relate","from-ask","text"],(e,[a],t,s)=>{if(C(t,"seed a new card's notes with item add --notes-from <draft.md>"),t.notes!==void 0&&t["notes-from"]!==void 0)throw new d("pass --notes or --notes-from, not both");return n.addItem(e,a,{title:t.title,notes:t.notes,notesFrom:t["notes-from"],deps:t.deps,ticket:t.ticket,newTicket:t["new-ticket"],pickUpAt:t["pick-up-at"],held:t.held,parent:t.parent,size:t.size,model:t.model,phase:t.phase,state:t.state,relate:t.relate,fromAsk:t["from-ask"],text:t.text,intake:!0},s)}],"item notes":[["file/id"],["heading","file","from"],(e,[a],t)=>{if(t.heading===void 0&&t.from===void 0)throw new d(`item notes needs --heading "<the section's title>"`);if(t.file===void 0==(t.from===void 0))throw new d("item notes takes --file <draft.md> or --from <file>/<id>");return n.addNotes(e,a,t)}],"item relate-ask":[["eventId","file/id"],["summary","title"],(e,[a,t],s)=>n.relateAsk(e,a,t,s.summary,s.title)],"ask unfold":[["eventId"],[],(e,[a])=>n.unfoldAsk(e,a)],"ask move":[["eventId"],["to"],(e,[a],t)=>n.moveAsk(e,a,t.to)],"wave create":[["slug"],["title","goal","...card","note","file"],(e,[a],t)=>n.createWave(e,a,{title:t.title,goal:t.goal,cards:t.card,note:N(t)})],"wave add":[["slug","file/id"],["after"],(e,[a,t],s)=>n.changeWave(e,a,{add:t,after:s.after})],"wave remove":[["slug","file/id"],[],(e,[a,t])=>n.changeWave(e,a,{remove:t})],"wave set":[["slug","...file/id?"],["after","title","goal","note","file"],(e,[a,...t],s)=>{if(t.length>1)throw new d("wave set takes <slug> [<file/id>]");return n.changeWave(e,a,{card:t[0],after:s.after,title:s.title,goal:s.goal,note:N(s)})}],"wave finish":[["slug"],[],(e,[a])=>n.finishWave(e,a)],slack:[[],[],()=>({lines:[JSON.stringify(D())]})],"slack set":[[],["self-dm","user","domain","timezone"],async(e,a,t)=>{const s={"self-dm":"self_dm",user:"owner_slack_user",domain:"slack_domain",timezone:"timezone"};try{return{lines:[JSON.stringify(await M(Object.fromEntries(Object.entries(t).map(([r,o])=>[s[r],o]))))]}}catch(r){throw new n.BoardError(r.message)}}],integrations:[[],[],async()=>({lines:[JSON.stringify(await H.rows())]})],"review updated":[["file/id"],["text"],(e,[a],t)=>n.reviewUpdated(e,a,t.text)],"review record":[["pr"],["state","text","file"],(e,[a],t)=>{if(t.text===void 0==(t.file===void 0))throw new d("review record takes --text or --file");return n.recordReview(e,a,{state:t.state,text:t.text??w(t.file)})}],"review post":[["pr"],["file","read-at"],(e,[a],t)=>{if(t.file===void 0)throw new d("review post needs --file <review.md>");if(t["read-at"]===void 0)throw new d("review post needs --read-at <time>, when you read the PR, so a review that landed since is caught");return n.postIncomingReview(e,a,{words:w(t.file),readAt:t["read-at"]})}],"review digest":[[],[],async(e,a,t,s)=>({lines:[JSON.stringify(await n.reviewDigest(e,s))]})],"review due":[[],[],async(e,a,t,s)=>({lines:[JSON.stringify(await n.reviewDue(e,s))]})],"reviewers set":[[],["file"],(e,a,t)=>n.setReviewers(e,q(t.file))],"reviewers add":[[],["file"],(e,a,t)=>n.addReviewers(e,q(t.file))],"reviewers remove":[["...name"],[],(e,a)=>n.removeReviewers(e,a)],"rules list":[[],[],e=>n.listRules(e)],"rules add":[[],["text","hub","by"],(e,a,t)=>n.addRuleTo(e,t)],"rules edit":[["id"],["text","hub"],(e,[a],t)=>n.editRuleIn(e,a,t)],"rules remove":[["id"],["hub"],(e,[a],t)=>n.removeRuleFrom(e,a,t)],settings:[[],[],async e=>({lines:[JSON.stringify(await n.readBoardSettings(e))]})],build:[["file/id"],["asked"],async(e,[a],t)=>{if(!e)throw new n.BoardError("build needs --site <route>");n.parseKey(a);const s=await n.askedGate(e,a,t.asked);try{const r=await fetch(`http://127.0.0.1:${process.env.KICKFLIP_HUB_PORT||4500}/_hub/build`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({route:x.basename(e),key:a}),signal:AbortSignal.timeout(1e4)}),o=await r.json();if(!r.ok)throw new n.BoardError(o.error||"The hub refused the build.");return{lines:["started",...(await n.appendMessage(e,a,{text:s})).lines]}}catch(r){throw r instanceof n.BoardError?r:new n.BoardError(`Could not start the build: ${r.message}`)}}],"main set":[[],["install","install-sha"],(e,a,t)=>n.setMainInstall(e,{install:t.install,installSha:t["install-sha"]})],"settings set":[["name","value"],[],(e,[a,t])=>n.setBoardSetting(e,a,t)],"builder start":[["file/id"],["label","phase","progress","dir","agent","kind","model","eta","worktree","repo","dispatch"],(e,[a],{worktree:t,repo:s,dispatch:r,...o})=>{if(s!==void 0&&!t)throw new d("--repo goes with --worktree");const l=i(p=>z(e,a.split("/")[1],{repo:s,...p}),"make"),c=e&&o.dir===void 0&&ae(e);return n.startBuilder(e,a,{...o,dispatch:r?"session":void 0,worktree:t?l:void 0,ownWorktree:c?l:void 0})}],"builder progress":[["file/id","...text?"],["phase","text","dir","agent","eta","clear-eta"],(e,[a,...t],s)=>{if(t.length&&s.text!==void 0)throw new d("builder progress takes its text once: as words or as --text");if(!t.length&&s.text===void 0)throw new d("builder progress needs its text, as words or as --text");return n.builderProgress(e,a,s.text??t.join(" "),{...s,clearEta:s["clear-eta"]})}],"builder done":[["file/id"],["dir","agent","next","owner-step","check","text","updated"],async(e,[a],{updated:t,...s})=>{const r=e&&!s.dir;if(r&&t===void 0&&await n.cardLinked(e,a))throw new n.BoardError(`a reviewer has ${a}'s PR link: pass --updated "<what changed>" for its thread, or --updated none for a change only to comments, names, docs or tests`);const o=await pe(e,a,s);return r&&t!==void 0&&t.trim().toLowerCase()!=="none"&&await n.reviewUpdated(e,a,t),o}],"builder pick":[["file/id"],[],(e,[a])=>n.pickBuilder(e,a)],"agent launch":[["file/id"],["name","task","writes","model"],(e,[a],t)=>n.requestHelper(e,a,t)],"agent wait":[["file/id"],["name","agent","timeout"],(e,[a],t)=>n.waitHelper(e,a,{...t,alive:Q})],"agent merge":[["file/id"],["name"],async(e,[a],t)=>{const{record:s,card:r}=await n.helperOf(e,a,t.name);if(!s.done)throw new n.BoardError(`helper ${t.name} is still open; run agent wait ${a} --name ${t.name} first`);if(!s.writes||!s.worktree)throw new n.BoardError(`helper ${t.name} writes no code, so there is nothing to merge`);if(!r)throw new n.BoardError(`${a} has no worktree to merge helper ${t.name} into`);return G(r,s.worktree)}],audit:[["...file/id?"],[],(e,[a,...t])=>{if(t.length)throw new d("audit takes one <file/id> at most");return n.auditLog(e,a)}],"builder call":[["file/id","...text"],["dir","agent"],(e,[a,...t],s)=>n.recordCall(e,a,t.join(" "),s)],"builder calls":[["file/id"],["dir","agent"],(e,[a],t)=>n.listCalls(e,a,t)],"builder ask":[["file/id","...text"],["agent"],(e,[a,...t],s)=>n.askOrchestrator(e,a,t.join(" "),s)],"builder answer":[["file/id","ask"],["text"],(e,[a,t],s)=>n.answerBuilder(e,a,t,s.text)],"builder defer":[["file/id","ask"],["text"],(e,[a,t],s)=>n.answerBuilder(e,a,t,s.text,{deferred:!0})],"builder asks":[["file/id"],["wait","timeout"],(e,[a],t)=>n.listAsks(e,a,t)],"builder verified":[["file/id"],["dir","agent","note"],async(e,[a],t)=>{await n.verifyCalls(e,a,t);const s=e&&!t.dir?await n.verifiedFinish(e,a):null;if(!s)return{};if(s.held)return{said:`${await n.cardName(e,a)} didn't land: ${s.held}`};if(s.waits.length)return{lines:[`${await n.cardName(e,a)} finishes once the owner answers ${s.waits.join(", ")}`]};try{return await $(e,a,{text:t.note??"Judgment calls verified."})}catch(r){throw r instanceof n.BoardError?Object.assign(new n.BoardError(`judgment calls verified, but ${await n.cardName(e,a)} didn't finish: ${r.message}`),{exitCode:r.exitCode}):r}}],land:[["file/id"],["repo","dir","text","owner-step","check"],async(e,[a],t)=>{const s=a.split("/")[1];if(e&&t.text===void 0)throw new d(`land needs --text "<what was checked>", which closes ${a} as done once it lands`);if(!e&&t.text!==void 0)throw new d("--text closes the card, which needs --site");if(!e&&t["owner-step"]!==void 0)throw new d("--owner-step keeps a board card open, which needs --site");if(t.check!==void 0&&t["owner-step"]===void 0)throw new d("--check goes with --owner-step: it is the code check that closes the card once the step is done");if(e&&t.dir===void 0)return $(e,a,{text:t.text,ownerStep:t["owner-step"],check:t.check,repo:t.repo});const r=e?await n.cardName(e,a):void 0,o=await U(r??a,async()=>{e&&await n.checkClose(e,a,t.text,t["owner-step"],t.check),await n.checkCallsVerified(e,a,{dir:t.dir});const l=await n.recordedWorktree(e,a,{dir:t.dir}),{repo:c,base:p}=J(e,{repo:t.repo??l?.repo});return await F({path:l?.path??x.join(K(),s),branch:l?.branch??s,repo:x.resolve(c),base:p,ref:r}),e?n.setItem(e,a,{done:!0,text:t.text,ownerStep:t["owner-step"],check:t.check}):{lines:[]}});return o.joined?{lines:[`joined the land already running for ${r??a}`]}:o}],"builder stop":[["file/id"],[],(e,[a])=>ee(m(e,"builder stop"),a)],"item stall":[["file/id"],["reason"],(e,[a],t)=>Y(m(e,"item stall"),a,t.reason)],"land stop":[["file/id"],[],(e,[a])=>te(m(e,"land stop"),a)],"land queue":[[],[],()=>Z()],"item bump":[["file/id"],[],(e,[a])=>S(m(e,"item bump"),a,!0)],"item unbump":[["file/id"],[],(e,[a])=>S(m(e,"item unbump"),a,!1)],lander:[["file/id"],[],async(e,[a])=>{if(!e)throw new d("lander needs --site <route>");return await n.relaunchLander(e,a),{lines:[`${await n.cardName(e,a)} is handed back again; the server launches a lander for it within a minute`]}}],merge:[["file/id"],["after-approval","confirmed"],async(e,[a],t)=>e&&await n.heldMerge(e,a)?X(e,a):n.mergeCard(e,a,{afterApproval:t["after-approval"],confirmed:t.confirmed})],"arch file":[["file/id"],[],(e,[a])=>e?V(e,a):Promise.reject(new n.BoardError("arch file needs --site <route>"))],push:[[],["kind","title","body","url","tag","urgent","now"],(e,a,t)=>{if(t.kind!=="fault"&&t.kind!=="reminder")throw new d(`a session pushes only --kind fault or reminder${t.kind===void 0||t.kind===!0?"":`, not "${t.kind}"`}: the board server pushes Action needed, and news goes on the board`);if(t.title===void 0)throw new d("push needs --title");return n.sendPush(e,t)}]};b.install=b.build;function m(e,a){if(!e)throw new d(`${a} needs --site <route>`);return e}i(m,"needSite");const h=i((e,a)=>n.cardName(e,a),"card"),R=i((e,a)=>`${a}${e.length===1?"":"s"} ${e.join(", ")}`,"plural"),T=i(e=>e.agent===void 0||e.agent==="main"?"builder":`builder ${e.agent}`,"builderOf");function we(e){const a=e["pick-up-at"];return[e.done&&(e["split-into"]?`done, split into ${e["split-into"].split(",").join(", ")}`:"done"),e.next!==void 0&&(e.next.trim()?"next line set":"next line cleared"),e["clear-next"]&&"next line cleared",e.pr!==void 0&&`PR #${e.pr}`,e.pushed!==void 0&&`pushed ${e.pushed}`,e["gh-since"]&&`GitHub read to ${e["gh-since"]}`,e["from-ask"]&&`from task ${e["from-ask"]}`,e.phase,e.held&&"held",e.unheld&&"resumed",a!==void 0&&(a?`held until ${a}`:"resumed"),e.deps!==void 0&&(e.deps?`blocked by ${e.deps}`:"deps cleared"),e.parent!==void 0&&(e.parent?`parent ${e.parent}`:"parent cleared"),e.related!==void 0&&(e.related?`related to ${e.related.split(",").join(", ")}`:"related cleared"),e.relate!==void 0&&`related to ${e.relate.split(",").join(", ")} added`,e.unrelate!==void 0&&`unrelated from ${e.unrelate.split(",").join(", ")}`,e.install!==void 0&&"install published",e["clear-install"]&&"install cleared",e.title!==void 0&&"renamed",e.ticket!==void 0&&`ticket ${e.ticket}`,e["new-ticket"]&&"ticket made",e.check!==void 0&&(e.check.trim()?`check ${e.check.trim().split(/\s+/).join(" ")}`:"check removed")].filter(Boolean).join(", ")}i(we,"itemChanges");const me={reply:i(async(e,[a])=>a.includes("/")?`answered ${await h(e,a)}: it waits in In Review for the owner's Done`:`reply written to ${await n.eventCard(e,a)}`,"reply"),thread:i(async(e,[a])=>`thread line on ${await h(e,a)}`,"thread"),"topic add":i((e,[a])=>`topic ${a} added`,"topic add"),"question add":i(async(e,a,t,{asked:s,staged:r})=>{const o=[...new Set(s.map(c=>c.topic))],l=o.length!==1?"":o[0].startsWith("item:")?` on ${await h(e,o[0].slice(5))}`:` on topic ${o[0]}`;return`${R(s.map(c=>c.id),"question")} ${r===s.length?"staged":"added"}${l}`},"question add"),"question resolve":i((e,[a])=>`question ${a} resolved`,"question resolve"),"question settle":i((e,[a])=>`question ${a} settled`,"question settle"),"question publish":i(async(e,[a],t,{ids:s})=>`${R(s,"question")} on ${await h(e,a)} passed to the owner`,"question publish"),"question move":i((e,[a],t)=>`questions ${a} merged onto ${t.to}`,"question move"),"prototype add":i(async(e,[a],t)=>`prototype ${a} recorded${t.card?` for ${await h(e,t.card)}`:""}`,"prototype add"),"prototype rm":i((e,[a])=>`prototype ${a} removed`,"prototype rm"),"item set":i(async(e,[a],t)=>`${await h(e,a)}: ${we(t)}`,"item set"),"item add":i(async(e,a,t,{key:s})=>`${await h(e,s)} added as ${s}`,"item add"),"item notes":i(async(e,[a],t,{file:s,heading:r})=>`${await h(e,a)}: notes section "${r}" added to ${s}`,"item notes"),"item relate-ask":i(async(e,[a,t])=>`task ${a} folded into ${await h(e,t)}`,"item relate-ask"),"ask unfold":i((e,[a])=>`task ${a} back on a card of its own`,"ask unfold"),"ask move":i((e,[a],t)=>`task ${a} moved to /${t.to}`,"ask move"),"wave create":i((e,[a])=>`wave ${a} created`,"wave create"),"wave add":i(async(e,[a,t])=>`${await h(e,t)} added to wave ${a}`,"wave add"),"wave remove":i(async(e,[a,t])=>`${await h(e,t)} taken out of wave ${a}`,"wave remove"),"wave set":i((e,[a])=>`wave ${a} updated`,"wave set"),"wave finish":i((e,[a])=>`wave ${a} finished`,"wave finish"),"review record":i((e,[a],t)=>`review of PR #${a} recorded: ${t.state==="needs"?"needs you":"posted"}`,"review record"),"reviewers set":i(()=>"reviewers replaced","reviewers set"),"reviewers add":i(()=>"reviewers added","reviewers add"),"reviewers remove":i((e,a)=>`${R(a,"reviewer")} removed`,"reviewers remove"),"rules add":i((e,a,t)=>`${t.hub?"hub":"board"} rule added`,"rules add"),"rules edit":i((e,[a],t)=>`${t.hub?"hub":"board"} rule ${a} reworded`,"rules edit"),"rules remove":i((e,[a],t)=>`${t.hub?"hub":"board"} rule ${a} removed`,"rules remove"),"builder start":i(async(e,[a],t,s)=>`${await h(e,a)}: ${s.alreadyOpen?"already open: the Implement tap opened its record; launch the agent, whose own builder start takes it up":`${T(t)} started`}`,"builder start"),"builder progress":i(async(e,[a])=>`progress line on ${await h(e,a)}`,"builder progress"),"builder done":i(async(e,[a],t,s)=>`${await h(e,a)}: ${s?.said??`${T(t)} done${t["owner-step"]===void 0?"":`; owner step "${t["owner-step"].trim()}"`}`}`,"builder done"),"builder call":i(async(e,[a])=>`judgment call recorded on ${await h(e,a)}`,"builder call"),"builder ask":i(async(e,[a],t,{id:s})=>`${await h(e,a)}: asked the orchestrator, ${s}`,"builder ask"),"builder answer":i(async(e,[a,t])=>`${await h(e,a)}: ${t} answered`,"builder answer"),"builder defer":i(async(e,[a,t])=>`${await h(e,a)}: ${t} deferred to the owner`,"builder defer"),"builder verified":i(async(e,[a],t,s)=>`${await h(e,a)}: judgment calls verified${s?.said?`; ${s.said}`:""}`,"builder verified"),land:i(async(e,[a],t,s)=>e?s?.said?`${await h(e,a)}: ${s.said}`:t["owner-step"]===void 0?`${await h(e,a)}: landed and done`:`${await h(e,a)}: landed; waits on the owner step "${t["owner-step"].trim()}"`:null,"land"),merge:i(async(e,[a],t,s)=>`${await h(e,a)}: ${s?.said??"merged"}`,"merge"),"arch file":i(async(e,[a])=>`findings of ${await h(e,a)} filed`,"arch file")};async function fe(e,a={}){try{const{flags:t,rest:s}=oe(e),r=[3,2,1].map(u=>s.slice(0,u).join(" ")).find(u=>y(b,u)),o=y(b,r);if(!o)throw new d(s.length?`unknown command "${s.slice(0,2).join(" ")}"`:"no command given");const[l,c,p]=o,f=s.slice(r.split(" ").length),_=l.at(-1)?.startsWith("..."),B=l.at(-1)?.endsWith("?")?l.length-1:l.length;if(_?f.length<B:f.length!==l.length)throw new d(`${r} takes ${l.map(u=>`<${u.replace(/^\.\.\.|\?$/g,"")}>`).join(" ")||"no arguments"}`);const{site:A,...E}=t;if(A?.length>1)throw new d("--site is given twice");const I=A?.[0],k=de(r,c,E);ue(c,k);const P=I===void 0?null:await n.siteDir(I),v=await p(P,f,k,a),O=y(me,r),j=O&&await O(P,f,k,v);j&&console.log(j);for(const u of typeof v=="object"&&v?.lines||[])console.log(u);return 0}catch(t){if(t instanceof d)return console.error(`${t.message} (node board.mjs --help lists the commands)`),2;if(t instanceof n.BoardError)return console.error(t.message),t.exitCode??1;throw t}}if(i(fe,"main"),process.argv[1]&&import.meta.url===L(g.realpathSync(process.argv[1])).href){const e=process.argv.slice(2);!e.length||e.includes("--help")||e[0]==="help"?console.log(ie):process.exitCode=await fe(e)}export{ie as USAGE,fe as main};
package/board/domain.mjs CHANGED
@@ -1,10 +1,10 @@
1
- var Vt=Object.defineProperty;var d=(e,t)=>Vt(e,"name",{value:t,configurable:!0});import{routeRecord as R}from"../hub/routes.mjs";import Xt from"node:fs";import{ticketBadge as pt,ticketIn as Yt}from"./tickets.mjs";import{prLinks as zt,reviewLinks as Jt,reviewTime as Zt,reviewersOf as en}from"./review.mjs";import{remoteFromInput as tn}from"../hub/repos.mjs";import{reviewsOf as nn,reviewNeeds as sn,reviewActions as on}from"./auto-review.mjs";import{cardPRs as rn,hasPR as et,leastReady as an,prKeyOf as ln,prURL as dn}from"../shared/card-prs.mjs";import ft from"node:vm";import{checkWords as cn,parseCheck as un}from"../shared/owner-check.mjs";import{buildScriptOf as pn}from"./build-script.mjs";import{HUB as Qe,hubLineOf as gt}from"./hub-lines.mjs";const fn="card-merged",tt=ft.createContext({});for(const e of["ui-enums.js","ui-order.js"])ft.runInContext(Xt.readFileSync(new URL(`./public/${e}`,import.meta.url),"utf8"),tt);const{BUTTON:ce,ACTION_KIND:q,BUILDER_KIND:ue,PR_STATE:V,PHASES:kt}=tt.BoardUI,{laneOrder:gn}=tt.BoardUI,kn=["item-message","mark-ready","grill-more","prototype-request","visual-request","reask-request"],mt="question-reopen",bo=Object.freeze({todo:"Todo",progress:"In Progress",review:"In Review",done:"Done"}),Ee="move",mn=10*6e4,wn=5*6e4,wt="build-refused",Ne=Object.freeze({ask:"builder-ask",answer:"builder-answer"}),hn=864e5,pe=d(e=>e.lane==="done","closedLane"),yn=d(e=>`file:${e}`,"fileFold"),ht=7*hn,yt=d((e,t)=>({id:e,url:t?.workspace?`https://linear.app/${t.workspace}/issue/${e}`:null}),"linearRef"),bn=d(e=>String(e).replace(/^S(\d+)$/,"INT-$1"),"internalRef"),nt=d((e,t,n)=>Yt(n,t.ticket)?t.ticket:e.internal===!0?bn(t.id):t.id,"refOf"),Sn=d((e,t,n)=>pt(e,t,n)||(t?{id:String(t),url:null,source:null}:null),"ticketOf");function vn(e,t,n,s,r,a,c,l,u){return!a&&(e.lane==="done"||t?.state==="MERGED"||t?.state==="CLOSED")?"done":(n||s)&&!l?"progress":r?"review":t?.state==="OPEN"?t.checks?.state==="fail"&&(!t.isDraft||c)?"progress":"review":t||u?"progress":"todo"}d(vn,"laneOf");const He="Lander",bt=d(e=>e.kind!==ue.install&&e.label!==He,"changesCode");function xn(e,t){return e?.state==="MERGED"||t?V.merged:e?.state==="CLOSED"?V.closed:e?.state==="OPEN"?e.isDraft?V.draft:V.open:null}d(xn,"prStateOf");const St=d(e=>e.pr?.status===V.closed,"unlanded"),On=d(e=>e.some(t=>t.kind==="work")&&e.every(t=>t.lane==="done"),"finishedOf");function st(e){const t=vt(e);return t?.done&&t.handed_back?t.handed_back:null}d(st,"handedBackAt");const vt=d(e=>e.filter(t=>t?.started&&Q(t)&&t.kind!==ue.install).sort((t,n)=>String(t.started).localeCompare(String(n.started))).at(-1),"newestBuild");function En(e,t,n){return Object.fromEntries(e.map(s=>{const r=R(t?.reviews,s.github),a=r==="APPROVED"?"approved":r==="CHANGES_REQUESTED"?"changes":Object.hasOwn(n,s.name)?"sent":"unsent";return[s.name,{state:a,since:a==="sent"?R(n,s.name):null,github:s.github||null}]}))}d(En,"reviewOf");function $n(e,t,n,s,r,a,{held:c,needsApproval:l}){return n?.kind===ue.install?"builder":s?"checking":n?"builder":c&&e==="review"?"merge":r&&e==="review"?"owner":e==="review"&&t?.state==="OPEN"&&t.isDraft?a?"ci":"ready":e==="review"?xt(t,l)?"merge":"reviewers":null}d($n,"waitsOnOf");const xt=d((e,t)=>e?.reviewDecision==="APPROVED"||!t&&!["REVIEW_REQUIRED","CHANGES_REQUESTED"].includes(e?.reviewDecision),"reviewed"),De=/(^|\/)prototype-[\w-]+\.html/,An={reviewers:"Waiting for PR reviewers",merge:"Approved, merges once CI and the merge state allow",ci:"Marked ready for review once CI passes"},Ve={waiting:"Approved, Merge shows once CI and the merge state allow",ready:"Approved and green: tap Merge",merging:"Merging"},ot={auto:"Ready, merges once CI and the merge state allow",waiting:"Ready, Merge shows once CI and the merge state allow",ready:"Ready and green: tap Merge"},Bn=d(e=>`Verified: tap Merge to land it on ${e}`,"heldNext"),_n="Fix the failing CI",Rn="Your reply waits on the orchestrator",Mn="Tap Done",In=["status","agent","ask-link","command",Ee,Ne.answer],qn=d(e=>(e.who==="claude"||e.via==="github")&&!In.includes(e.kind)&&(e.kind!==Qe||gt(e).fault),"countsUnread"),Cn=["lander-handoff","land-waiting"];function Nn({slug:e,itemFile:t,it:n,order:s,prs:r,repo:a,remote:c,base:l,builder:u,reachedPhase:m,agents:f,worktree:p,eta:w,thread:v,events:_,working:x,said:P,askedAt:C,topicItems:L,prSlack:T,boardReviewers:W,now:h,bumpedAt:b,holdAsk:i,closedAt:S,mergeAt:oe,autoMerge:ke,skipDraft:me,tickets:K}){const F=r.map(k=>({repo:k.repo,number:k.number,...k.gh||k.kept||{},url:(k.gh||k.kept)?.url||dn(k),status:xn(k.gh,k.merged_at)})),ee=an(r.map(k=>k.gh)),I=r[ee]?.gh||null,G=F[ee]?.status??null,ze=n.lane||null,U=!!S&&String(S)>String(n.lane_at||"");U&&(n={...n,lane:"done",closed_at:S,reopened_at:void 0});const N=[n.closed_at,...r.flatMap(k=>[k.merged_at,k.gh?.mergedAt])].filter(Boolean).map(String).sort().pop()||null,we=String(N||""),he=F.length>0&&F.every(k=>k.status===V.closed),ye=(n.lane==="done"||n.reopened_at||G===V.merged)&&!he&&([...P.filter(k=>k.kind==="item-message").map(k=>k.ts),...C].map(String).filter(k=>k>we).sort().pop()||n.reopened_at)||void 0,Le=n.answered_at&&!n.phase&&!n.closed_at&&!ye?String(n.answered_at):void 0,j=ye||Le,Re=n.owner_step&&!U?String(n.owner_step):null,Je=(n.lane==="done"||G===V.merged)&&!he,H=!!j&&!!n.next&&String(n.next_at||"")>String(n.reopened_at||N||"");j&&!H&&(n={...n,next:void 0});const X=st(f),Te=j&&P.filter(k=>String(k.ts)>we&&(k.state==="waiting"||k.state==="working")).map(k=>String(k.ts)).sort()[0]||null,be=!!Te,Se=`${e}/${n.id}`,ve=en(t,W),Pe=Object.fromEntries(Object.entries(Jt(t,n,Se,L,zt(T,r))).map(([k,de])=>[k,Zt(de.ts)])),te=Object.values(Pe).filter(Boolean).sort()[0]||null,Ue=[...v.map(k=>k.ts),..._.map(k=>k.ts)].sort().pop()||null,je=[...v.filter(k=>qn({...k,who:k.who||"claude"})).map(k=>k.ts),..._.map(k=>k.reply?.at)].filter(Boolean).sort(),Y=!et(n)&&n.pushed?.branch?{branch:n.pushed.branch,at:n.pushed.at||null,host:c?.host||null}:null,z=!et(n)&&n.merge_ready?.branch?{branch:n.merge_ready.branch,at:n.merge_ready.at||null,base:l}:null,Me=!!n.rebase_run&&I?.state==="OPEN",Ie=(n.rebased||[]).at(-1),re=f.filter(k=>k.started&&!k.done&&Q(k)),Ze=!!X&&bt(vt(f));let A=vn(n,I,re.some(bt),Ze,Y||z,!!j,me,Me,re.length>0||!!X);j&&A==="todo"&&(A="progress");const We=A==="review"&&!!te&&h-Date.parse(te)>ht,ae=!!Re&&Je&&A==="done";ae&&(A="review");let D=$n(A,I,u,!!X&&A!=="done",Y,me,{held:z,needsApproval:ve.length>0});const Fe=D==="builder"&&I?.state==="OPEN"&&!I.isDraft,qe=A==="progress"&&!D&&I?.state==="OPEN"&&(!I.isDraft||me),xe=ae||!!j&&A==="progress"&&!D&&!qe&&!be&&!H;xe&&(D="owner");const o=!!j&&f.some(k=>Q(k)&&String(k.started||"")>String(j)),g=A==="progress"&&!D&&(qe||!!j&&!o);g&&(A="review");const E=i&&String(i.ts)>String(n.held_at||""),$=A==="todo"&&(E?!!i.data.hold:!!n.held),y=$&&(E?i.data.until:n.pick_up_at)||null,M=A!=="done",B=!!b&&!(we&&String(b)<=we),Ke=v.filter(k=>(k.who||"claude")==="claude"&&!["status","command",Ee].includes(k.kind)&&!Cn.includes(k.line)).map(k=>String(k.ts)).sort().pop()||"",le=[oe,z&&n.merge_ready.tapped].filter(Boolean).map(String).sort().pop(),Ce=D==="merge"&&!!le&&le>Ke,Oe=v.filter(k=>(k.kind==="status"||k.kind===Qe)&&String(k.ts)>String(le)).sort((k,de)=>String(k.ts).localeCompare(String(de.ts))).at(-1),ne=Oe?.line==="land-waiting"?`${Ve.merging} \xB7 ${Oe.text[0].toLowerCase()}${Oe.text.slice(1)}`:Ve.merging,J=v.filter(k=>!["status",Ee].includes(k.kind)).sort((k,de)=>String(k.ts).localeCompare(String(de.ts))).at(-1),O=A==="todo"&&J?.line===wt?J.text:null,ie=j||f.filter(Q).map(k=>k.started).filter(Boolean).map(String).sort().pop()||null,Ge=I?.reviewDecision==="APPROVED",Kt=Y&&D==="owner"?`merge ${Y.branch} into ${l}`:z&&D==="merge"?Ce?ne:Bn(l):D==="merge"&&!ke?Ce?ne:(Ge?Ve:ot).waiting:D==="merge"&&!Ge?ot.auto:An[D],Gt=G===V.draft?`Review draft PR #${F[ee].number}`:null,Qt=!Me&&Ie?.to&&Ie.to===I?.headRefOid?`Rebased onto ${Ie.base||l}, pushed${I.mergeable==="MERGEABLE"?" \xB7 PR is clean again":""}`:null,Ht=Me&&D==="checking"?f.flatMap(k=>k.calls).sort((k,de)=>String(k.at).localeCompare(String(de.at))).at(-1)?.text??null:null;return{key:Se,kind:"work",order:s,file:e,fileTitle:t.title||e,id:n.id,ref:nt(t,n,K),title:n.title,storedLane:ze,created:n.created||null,reviewSince:g&&j||n.review_since||te||n.merge_ready?.at||n.pushed?.at||n.created||null,progressSince:ie,closedAt:A==="done"?N:null,internal:t.internal===!0,repo:t.internal===!0&&!t.repo?null:a,lane:A,waitsOn:D,builder:D==="checking"?null:u,reachedPhase:m,agents:f,worktree:p??null,eta:w,working:x,reopened:!!ye,answered:!!Le,awaitsDone:xe,ownerStep:xe?Re:null,ownerCheck:xe&&Re&&n.owner_check?{words:cn(un(n.owner_check.check)),broken:n.owner_check.broken||null}:null,stagedAt:A==="todo"&&n.phase==="staging"&&n.staged_at||null,roundAt:n.round_at||null,deps:n.deps||[],blockedUntil:n.blocked_until||null,blockReason:n.block_reason||null,held:$,heldUntil:y,risky:!!n.risky,bumpable:M,bumpedAt:M&&B?b:null,holdable:A!=="done",hasNotes:!!(n.plan||String(n.notes||"").trim()),finishable:A!=="done",merging:Ce,refusal:O,manualSteps:n.manual_steps||[],fromAsk:n.from_ask||null,unfiled:!!n.unfiled,filedHeld:!!n.filed_held,next:Fe||A==="done"||D==="checking"?null:g&&be?Rn:qe?_n:Qt||Kt||n.next||Gt||null,rebaseFailed:Ht,branch:n.branch||I?.headRefName||Y?.branch||null,pushed:A==="done"||ae?null:Y,mergeReady:A==="review"?z:null,stale:A!=="done"&&(We||!!u?.stale),stalled:n.stalled?.reason||null,landStopped:A==="review"&&z&&n.merge_ready.stopped&&String(n.merge_ready.stopped)>String(n.merge_ready.tapped||"")?{words:At("land"),at:n.merge_ready.stopped}:null,ticket:K?.source==="linear"&&!n.ticket&&n.linear?.length?null:Sn(K,n.ticket,{repo:a}),ticketSource:K?.source||null,linear:(n.linear||[]).map(k=>K?.source==="linear"&&pt(K,k,{repo:a})||yt(k,K)),pr:F[ee]||null,prs:F,reviewers:ve.map(k=>k.name),review:En(ve,I||r[ee]?.kept,Pe),inReviewSince:te,threadCount:v.length+_.length,lastTs:Ue,othersAt:je,grilling:Bt("grill",_,f,C),prototyping:Bt("prototype",_,f,C),storedPhase:n.phase||null,phase:null,recheckAt:n.recheck_at||null,updatedAt:I?.mergedAt||I?.updatedAt||r[ee]?.merged_at||u?.at||Ue||null,ask:null,fold:null,action:null,install:A==="done"?null:Ln(n.install,I),waitFacts:Dn(n,{agents:f,thread:v,events:_,refusedAt:O?J.ts:null,replyAt:g?Te:null})}}d(Nn,"workItem");function Dn(e,{agents:t,thread:n,events:s,refusedAt:r,replyAt:a}){const c=new Set(n.filter(f=>f.kind===Ne.answer).map(f=>f.ask)),l=n.filter(f=>f.kind===Ne.ask&&!c.has(f.ask)).sort((f,p)=>String(f.ts).localeCompare(String(p.ts)))[0],u=d(f=>s.filter(p=>at(p,f)).pop()?.ts||null,"requestAt"),m=n.filter(f=>(f.who||"claude")==="claude"&&!["status","agent","command",Ee].includes(f.kind)&&f.line!==wt).map(f=>f.ts);return{handedBackAt:st(t),next:e.next||null,ask:l?{at:l.ts,text:l.text}:null,grillAt:u("grill"),prototypeAt:u("prototype"),refusedAt:r,replyAt:a,unblockedAt:e.unblocked_at||null,unverified:t.some(f=>f.calls.some(p=>!f.verified||String(p.at)>String(f.verified.at))),writes:[...m,...t.flatMap(f=>[f.verified?.at,f.started])].filter(Boolean).map(String).sort()}}d(Dn,"waitFactsOf");function Ln(e,t){if(!e?.url)return null;const n=e.sha?String(e.sha).toLowerCase():null,s=t?.headRefOid?String(t.headRefOid).toLowerCase():null;return{url:e.url,label:e.label||null,builtAt:e.built_at||null,sha:n,older:!!(n&&s&&!s.startsWith(n))}}d(Ln,"installOf");function Tn(e,{needsApproval:t=!0}={}){if(e?.state!=="OPEN")return[`PR is ${String(e?.state||"unknown").toLowerCase()}`];const{state:n,pending:s,failing:r}=e.checks||{};return[e.isDraft&&"it is a draft",!xt(e,t)&&`review: ${String(e.reviewDecision||"none").toLowerCase().replace(/_/g," ")}`,n==="fail"&&`failing: ${r?.length?r.join(", "):"a check"}`,n==="pending"&&`pending: ${s?se(s,"check"):"checks"}`,e.mergeStateStatus!=="CLEAN"&&`merge state: ${String(e.mergeStateStatus||"unknown").toLowerCase()}`].filter(Boolean)}d(Tn,"mergeBlockers");const Pn=d((e,t)=>!Tn(e,{needsApproval:t}).length,"mergeable");function Un(e,t,n){if(pe(e))return null;const s=`#selectedCard=${encodeURIComponent(e.key)}`;if(e.stalled)return{kind:q.stalled,url:s,label:`stalled: ${e.stalled}`};if(jn(e)){const r=t.get(e.questions.first);return De.test(r?.url||"")?{kind:q.pick,url:`questions.html#${r.id}`,label:"Prototypes ready: pick a take"}:{kind:q.questions,url:`questions.html#${e.questions.first}`,label:`Answer ${se(e.questions.open,"question")}`}}return e.waitsOn==="ready"?{kind:q.ready,url:e.pr.url,label:`Review draft PR #${e.pr.number}`}:e.waitsOn==="merge"&&e.manualSteps.length&&!e.mergeReady?{kind:q.steps,url:s,label:"Run the manual steps, then merge"}:e.waitsOn==="merge"&&(!n||e.mergeReady)&&!e.merging&&e.prs.every(r=>["MERGED","CLOSED"].includes(r.state)||Pn(r,e.reviewers.length>0))?{kind:q.merge,url:s,label:"Merge"}:null}d(Un,"actionOf");const jn=d(e=>!!(e.questions&&e.questions.state!=="resolved"&&e.questions.open>0),"asking"),rt=new Set([q.pick,q.questions]);function Ot(e){return e.questions?ce.openQuestions:null}d(Ot,"actionButtonOf");const Wn=d(e=>e.kind==="work"&&e.lane==="todo"&&!e.action&&!e.unpicked,"buildableOf"),Fn=d((e,t)=>/^item:/.test(e.topic||"")&&De.test(e.url||"")&&!(e.options||[]).some(n=>n.id===t),"picksNoTake");function Kn(e,t){const n=e.filter(a=>a.topic===`item:${t}`),r=[...n.filter(a=>De.test(a.url||"")).flatMap(a=>a.answers.map(c=>({q:a,a:c,again:Fn(a,c.choice)}))),...n.filter(a=>a.request).map(a=>({q:a,a:a.request,again:!0}))].sort((a,c)=>String(a.a.ts).localeCompare(String(c.a.ts))).at(-1);return r?.again?{id:r.q.id,note:r.a.note.replace(/\s+/g," ").trim()}:null}d(Kn,"noTakePicked");const Gn="Prototype again",Qn=Object.freeze({[q.pick]:ce.openQuestions,[q.questions]:ce.openQuestions,[q.ready]:ce.github,[q.steps]:ce.github,[q.merge]:ce.merge,[q.stalled]:ce.reply}),Hn="Merges once unblocked",Vn=d(e=>`Blocked ${[e.blockedBy.length&&`by ${e.blockedBy.map(t=>t.ref).join(", ")}`,e.blockedUntil&&`until ${e.blockedUntil}`].filter(Boolean).join(" and ")}`,"mergeBlockedWords");function Xn(e,t,n){if(e.action=Un(e,t,n),e.mergeBlocked=e.action?.kind===q.merge&&e.blocked?Vn(e):null,e.mergeBlocked&&Object.assign(e,{action:null,next:Hn}),e.action?.kind===q.questions&&e.questions.fromAsks){Object.assign(e,{action:null,waitsOn:"owner",next:e.action.label,actionButton:Ot(e),resolvedBy:null});return}e.awaitsDone&&=!e.action,e.awaitsDone||Object.assign(e,{ownerStep:null,ownerCheck:null}),e.actionButton=Ot(e),e.resolvedBy=Qn[e.action?.kind]||null,e.action?.kind===q.merge&&!e.mergeReady&&(e.next=(e.pr?.reviewDecision==="APPROVED"?Ve:ot).ready),e.awaitsDone&&Object.assign(e,{lane:"review",next:e.ownerStep||Mn,bumpable:!1,bumpedAt:null});const s=e.lane==="todo"||e.waitsOn==="ready"||e.lane==="progress"&&e.waitsOn==="owner";if(!e.action||!s||e.stalled)return;const r=e.lane==="todo"&&rt.has(e.action.kind)?"todo":"review";Object.assign(e,{lane:r,waitsOn:e.waitsOn==="ready"?"ready":"owner",next:e.action.label})}d(Xn,"placeOwnerWait");const Et=d((e,t)=>e?e!=="todo":t.some(Q),"started"),$t="none set yet";function So(e,t){const n=t.filter(s=>s?.started);return e.next||et(e)||e.pushed||e.held||e.lane==="done"||st(n)?!1:!n.some(s=>!s.done)&&Et(e.lane,n)}d(So,"owesNext");const fe="visual",$e="helper",Yn=new Set(["grill","prototype",fe]),Z=d(e=>Yn.has(e.kind),"plans"),Q=d(e=>!Z(e),"builds"),zn={grill:"grilling",prototype:"prototyping"},Jn=d((e,t)=>`${e} ${t} by orchestrator`,"orchestratorDid"),At=d(e=>Jn(e,"stopped"),"stoppedWords"),Zn={grill:"grill-more",prototype:"prototype-request"},at=d((e,t)=>e.kind===Zn[t]&&!e.data?.question,"isRequest");function Bt(e,t,n,s){if(n.some(a=>a.kind===e&&a.started&&!a.done))return!0;const r=t.filter(a=>at(a,e)).pop();return!!(r&&!r.reply&&!s.some(a=>String(a)>String(r.ts))&&!n.some(a=>a.kind===e&&a.done&&String(a.started)>=String(r.ts)))}d(Bt,"planningOf");const vo=30*6e4;function xo(e,t){const n=[];for(const s of e.items){if(pe(s)||(s.agents||[]).some(a=>a.kind==="prototype"&&a.started&&!a.done))continue;const r=s.prototyping&&t.filter(a=>a.data?.key===s.key&&at(a,"prototype")).pop();r&&n.push({key:s.key,request:r.id,since:r.ts});for(const a of e.owner.filter(c=>c.topic===`item:${s.key}`&&c.state==="requested"))n.push({key:s.key,request:a.request.id,question:a.id,since:a.request.ts})}return n}d(xo,"prototypeWaits");function lt(e={},t=!1){return Object.entries(e).filter(([n,s])=>s&&typeof s=="object"&&(t||!n.startsWith("past-"))).map(([n,s])=>({name:n,kind:_t(s.kind)||null,model:s.model||(s.kind==="opus"||s.kind==="sonnet"?s.kind:null),label:s.label||null,started:s.started||null,eta:s.done?null:s.eta||null,done:s.done||null,log:s.session?.log||null,pid:s.session?.pid??null,calls:Array.isArray(s.calls)?s.calls:[],verified:s.verified||null,stopped:s.stopped||null,handed_back:s.handed_back||null,...s.pause?{pause:s.pause}:{},...s.kind===$e?{writes:!!s.writes,requested:s.requested||null}:{},...s.waits?{waits:s.waits}:{}})).sort((n,s)=>String(n.started||"").localeCompare(String(s.started||""))||n.name.localeCompare(s.name))}d(lt,"agentsOf");function it(e={}){return Object.values(e).filter(t=>t?.worktree?.path).sort((t,n)=>String(t.started||"").localeCompare(String(n.started||""))).at(-1)?.worktree.path??null}d(it,"worktreeOf");function es(e,t=[]){const n=e.filter(Q).map(s=>String(s.started||"")).filter(Boolean).sort().pop();return n===void 0?null:t.filter(s=>s.kind==="status"&&s.phase&&!s.planner&&String(s.ts)>=n).sort((s,r)=>String(s.ts).localeCompare(String(r.ts))).pop()?.phase||null}d(es,"reachedPhaseOf");function ts(e,t=[],n,s=null,r=null,a=!1){const c=e.filter(b=>b.started&&!b.done&&b.kind!==fe),l=c.every(Z),u=l?c:c.filter(Q),m=u.map(b=>String(b.started||"")).sort()[0];if(m===void 0)return null;const f=t.filter(b=>b.kind==="status"&&String(b.ts)>=m&&(l||!b.planner)).sort((b,i)=>String(b.ts).localeCompare(String(i.ts))).pop(),p=u.filter(b=>b.kind!==$e).at(-1),w=u.some(b=>b.kind===ue.install)?ue.install:p?_t(p.kind):"claude",v=l?null:u.find(b=>b.stopped&&String(b.stopped.at)>=String(b.started))?.stopped,_=f?.ts||m,x=v?v.at:s!==null&&s>Date.parse(_)?new Date(s).toISOString():_,P=f?f.phase||f.planner?f.text.replace(": "," \xB7 "):f.text||null:l?zn[w]:null,C=n-Date.parse(x),L=l?null:u.find(b=>b.pause)?.pause??null,T=!l&&!v&&(r==="held"||!!L?.paused),W=l||T?null:v?!1:r,h=T?!1:W===null?C>=mn:!W;return{progress:P,phase:f?.phase||null,at:_,kind:w,planner:l,silentSince:x,stale:h,alive:W,held:T,quiet:!!L||W===!0&&!a&&C>=wn,stopped:v?At(v.run):null,...L?{pause:{cause:L.cause,words:L.words,paused:!!L.paused}}:{}}}d(ts,"builderOf");const Oo={blocked:["nothing blocks it","nothing blocks it"],held:["you unhold it","unheld"],usage:["the usage pause lifts","the usage pause lifted"],bumped:["a slot frees","a slot freed"]},ns=15*6e4,ss=d(e=>(e.agents||[]).find(t=>t.name==="main"&&t.started&&!t.done&&Q(t))??null,"mainBuild"),os=d((e,t,n,{now:s,usageHeld:r})=>e.blocked||e.held||r(n??"claude")||!!(t.until&&s<Date.parse(t.until)),"stillPaused");function Eo(e,{now:t=Date.now(),usageHeld:n}){const s={ask:[],drop:[],stop:[],resume:[]},r=[];for(const a of e){if(a.kind!=="work"||a.lane!=="progress")continue;const c=ss(a);if(!c)continue;const{pause:l}=c;if(!l){a.builder?.phase!=="landing"&&n(c.kind??"claude")&&s.ask.push(a.key);continue}const u=os(a,l,c.kind,{now:t,usageHeld:n});if(l.paused){u||r.push({key:a.key,at:l.paused});continue}!u&&l.cause!=="bumped"?s.drop.push(a.key):t-Date.parse(l.at)>=ns&&s.stop.push(a.key)}return s.resume=r.sort((a,c)=>String(a.at).localeCompare(String(c.at))).map(a=>a.key),s}d(Eo,"pauseWork");const dt={opus:"Claude Opus",sonnet:"Claude Sonnet",codex:"Codex"},rs=d(({model:e,kind:t})=>dt[e]||dt[t]||(t==="claude"?dt.opus:null),"modelName"),_t=d(e=>e==="opus"||e==="sonnet"?"claude":e,"providerOf");function Ae(e){const t=rs(e),{kind:n}=e,s=e.label?.replace(/\bbuilder\b/,"implementer").replace(/\bBuilder\b/,"Implementer"),r=d(c=>c[0].toLowerCase()+c.slice(1),"lower");if(t&&Z(e))return`${t} ${n}`;if(t)return`${t} ${r(s?.replace(/^(?:claude\s+)?(?:opus|sonnet|codex)\b\s*/i,"")||"implementer")}`;const a=n?n[0].toUpperCase()+n.slice(1):"";return a?s?s.toLowerCase().includes(n.toLowerCase())?s:`${a} ${r(s)}`:a:s||"Implementer"}d(Ae,"agentName");const Rt=d((e,t)=>!!e.resolved&&(!e.resolved_at||String(e.resolved_at)>=String(t)),"resolvedSince");function as(e,t,n=[],s=[],r=[]){const a=t.filter(x=>x.data?.id===e.id),c=a[a.length-1]||null,l=r.filter(x=>x.data?.question===e.id).at(-1),u=d((x,...P)=>!!x&&P.every(C=>String(x.ts)>String(C||"")),"after"),m=!!(e.resolved&&e.resolved_at&&c&&String(c.ts)>e.resolved_at),f=n.filter(x=>x.data?.question===e.id&&u(x,c?.ts,l?.ts)).at(-1),p=u(l,c?.ts,f?.ts,e.resolved_at),w=e.resolved&&!m&&!p,v=w?s.filter(x=>x.data?.question===e.id&&String(x.ts)>String(e.resolved_at||"")).at(-1):null,_=p?"open":w?"resolved":f?"requested":c?c.reply?"replied":"answered":"open";return{...e,state:_,reopened:p,request:f?{id:f.id,ts:f.ts,note:f.data.note||"",choice:f.data.choice||null}:null,reask:v?{id:v.id,ts:v.ts}:null,answers:a.map(x=>({ts:x.ts,choice:x.data.choice||null,note:x.data.note||"",files:x.data.files||[],reply:x.reply,replies:x.replies,acted:Rt(e,x.ts)}))}}d(as,"ownerQuestion");const ge=d(e=>e.round??(De.test(e.url||"")?1:0),"roundOf");function ls(e,t){const n=d((s,r)=>s.confirm_of||(s.options||[]).some(a=>a.id===r.choice),"settles");return e.filter(s=>ge(s)===t&&s.answers.length).map(s=>[s,s.answers.at(-1)]).filter(([s,r])=>n(s,r)).map(([,s])=>s).sort((s,r)=>String(s.ts).localeCompare(String(r.ts))).at(-1)}d(ls,"roundSettledBy");function is(e){const t=e.find(r=>r.request&&!e.some(a=>ge(a)>ge(r)));if(t)return{n:ge(t)+1,state:"making"};const n=Math.max(0,...e.map(ge));if(!n)return null;const s=ls(e,n);return s?{n,state:"closed",take:s.choice}:e.some(r=>ge(r)===n&&r.state!=="resolved")?{n,state:"back"}:null}d(is,"roundState");function ds(e){const t=e.filter(n=>De.test(n.url||"")).map(n=>({n:ge(n),q:n.id,url:n.url,confirm:!!n.confirm_of,state:n.state})).sort((n,s)=>n.n-s.n);return t.length?{open:t.some(n=>n.state==="open"),rounds:t}:null}d(ds,"prototypesOf");const Be=d((e,t,n)=>{const s=e.get(t);s?s.push(n):e.set(t,[n])},"add"),_e=d((e,t)=>{const n=new Map;for(const s of e)Be(n,t(s),s);return n},"groupBy");function cs(e,t,n=new Set){const s=new Set(e.map(c=>c.id)),r=[...e];t.some(c=>!s.has(c.topic))&&r.push({id:"",title:"Other"});const a=_e(t,c=>s.has(c.topic)?c.topic:"");return r.map(c=>{const l=a.get(c.id)||[],u=d(p=>l.filter(w=>w.state===p).length,"count"),m=l.every(p=>p.state==="resolved")||n.has(c.id)&&!u("open"),f=l.length&&m?"resolved":"open";return{...c,state:f,questions:l.map(p=>p.id),open:u("open"),answered:u("answered"),replied:u("replied"),resolved:u("resolved"),round:is(l)}}).filter(c=>c.questions.length)}d(cs,"ownerTopics");const Xe={implement:"Implementation requested",prototype:"Prototype requested",grill:"Grill requested",visual:"Visual requested",reask:"Re-ask requested",hold:"Held",resume:"Resumed",done:"Marked done",staged:"Marked as staging",readied:"Marked as ready",related:"Related to",unrelated:"Unrelated from",followup:"Follow-up","followup-of":"Follow-up of"},Mt={"grill-more":"grill","prototype-request":"prototype","visual-request":"visual","reask-request":"reask"},It={"mark-ready":"Mark ready",...Object.fromEntries(Object.entries(Mt).map(([e,t])=>[e,Xe[t]]))},us=["grill-more","prototype-request","visual-request"],ps="answers submitted",qt={reply:"Reply",build:"Implement"},fs=d(e=>qt[e.data.intent],"intentLabel"),gs=d((e,t)=>{if(e.kind!=="prototype-request"||!t.has(e.data.question))return e.data.text||(e.data.files?.length?"":R(It,e.kind))||"";const n=t.get(e.data.question),s=(n.options||[]).find(r=>r.id===e.data.choice);return[Nt(t,n),s&&`${s.id}. ${s.label}`,e.data.note].filter(Boolean).join(`
2
- \u2192 `)},"actionText"),Ct=d((e,t)=>[...e.keys()].indexOf(t)+1,"numberOf"),Nt=d((e,t)=>`Question ${Ct(e,t.id)} \xB7 ${t.question}`,"numbered"),ks="question reopened",Ye=d(e=>e.data?.shared_by?.login?{by:e.data.shared_by.name||e.data.shared_by.login}:{},"byOf"),ms=d((e,t)=>{const n=t.get(e.card);return{...e,text:`${Xe[e.command]} ${n?`${n.ref}: ${n.title}`:e.card}`,link:`#selectedCard=${encodeURIComponent(e.card)}`}},"linkLine"),Dt=d(e=>({kind:"command",command:e,request:!0,mark:Xe[e]}),"commandLine"),ws=d((e,t)=>{if(e.kind==="item-message")return qt[e.data.intent]?{status:fs(e)}:{};const n={request:!0,command:Mt[e.kind]};return us.includes(e.kind)?(e.data.question?t.has(e.data.question):String(e.data.text||"").trim()||e.data.files?.length)?{status:It[e.kind]}:n:e.kind==="reask-request"?n:{}},"requestOf"),Lt=d(e=>[...e.filter(t=>t.who==="claude"&&!["status","agent","command",Ee,Ne.answer].includes(t.kind)).map(t=>t.ts),...e.filter(t=>t.kind==="ask").map(t=>t.reply?.at)].filter(Boolean).map(String).sort().pop()||"","claudeAtOf");function Tt(e,t={}){const n=new Map,s=new Map;for(const p of t.items||[])Be(n,p.topic,p),s.set(p.id,p.topic);const r=new Map,a=new Map,c=new Map,l=new Map,u=new Map,m=new Map,f=new Map;e.forEach((p,w)=>{f.set(p,w),p.data?.key&&kn.includes(p.kind)&&Be(r,p.data.key,p),p.kind==="owner-answer"&&s.has(p.data?.id)&&Be(a,s.get(p.data.id),p),p.kind===mt&&s.has(p.data?.question)&&Be(c,s.get(p.data.question),p),p.kind==="ask"&&l.set(p.id,p)});for(const p of e.filter(w=>w.kind==="ask-edited").sort((w,v)=>String(w.ts).localeCompare(String(v.ts)))){u.set(p.data?.id,p.data?.text);for(const w of p.data?.files||[])Be(m,p.data?.id,w)}return{byKey:r,answers:a,reopens:c,asks:l,edits:u,editFiles:m,questions:n,order:f}}d(Tt,"threadIndex");const ct=d((e,t)=>{const n=t.filter(s=>s?.length);return n.length>1?n.flat().sort((s,r)=>e.order.get(s)-e.order.get(r)):[...n[0]||[]]},"inLogOrder"),hs=/; its log is \S*\/\.claude\/kickflip\/logs\/([^/\s]+\.log)\.$/,ys=d(e=>{const t=!e.log&&typeof e.text=="string"?hs.exec(e.text):null;return t?{...e,text:`${e.text.slice(0,t.index)}.`,log:t[1]}:e},"withLog");function bs(e,t){const n=t.run?e.find(s=>s.started===t.run):e.filter(s=>Z(s)===!!t.planner&&s.started&&String(s.started)<=String(t.ts)&&(!s.done||String(t.ts)<=String(s.done))).pop();return n?{agent:Ae(n),run:ut(e,n),running:!n.done}:{}}d(bs,"agentOfLine");function ut(e,t){return t.label!==He?t.started:e.filter(n=>Q(n)&&n.label!==He&&n.started&&String(n.started)<String(t.started)).pop()?.started??t.started}d(ut,"sectionOf");function Ss(e,{lines:t=[],events:n=[],owner:s={},working:r={},fromAsk:a=null,links:c=[],agents:l={},moved:u=[],cards:m=new Map,index:f=Tt(n,s)}){const p=e.startsWith("ask:")?[e.slice(4)]:[a,...u].filter(Boolean),w=[...new Set([e,...p.map(i=>`ask:${i}`)])],v=new Map((f.questions.get(`item:${e}`)||[]).map(i=>[i.id,i])),_=f.answers.get(`item:${e}`)||[],x=new Set([...v.values()].map(i=>i.round_of).filter(Boolean)),P=lt(l,!0).filter(Q).map(i=>String(i.started||"")).filter(Boolean),C=new Set(_.filter(i=>Rt(v.get(i.data.id),i.ts)||x.has(i.data.id)||P.some(S=>S>String(i.ts))).map(i=>i.id)),L=lt(l,!0),T=[...L.flatMap(i=>[...i.started?[{ts:i.started,who:"claude",kind:"agent",text:`${Ae(i)} started`,agent:Ae(i),run:ut(L,i),finished:!1,eta:i.done?null:i.eta,...i.log?{log:i.log}:{},...Z(i)?{planner:!0}:{}}]:[],...i.done?[{ts:i.done,who:"claude",kind:"agent",text:`${Ae(i)} finished`,agent:Ae(i),run:ut(L,i),finished:!0,eta:null,...Z(i)?{planner:!0}:{}}]:[],...i.calls.length?[{ts:i.done||i.calls.at(-1).at,who:"claude",kind:"calls",text:Ae(i),calls:i.calls.map(S=>S.text),verified:i.verified}]:[]]),...t.map(ys).map(i=>i.card?ms(i,m):i).map(i=>({ts:i.ts,who:i.who||"claude",...i.log?{log:i.log}:{},...i.kind==="status"?{kind:"status",...i.planner?{planner:!0}:{},...bs(L,i)}:{},...i.kind===fe||i.kind===Ee?{kind:i.kind}:{},...i.kind===Qe?{kind:Qe,line:i.line,...gt(i)}:{},...i.command?Dt(i.command):{},...i.card?{card:i.card}:{},...Object.values(Ne).includes(i.kind)?{kind:i.kind,ask:i.ask}:{},text:i.text||"",html:i.html||null,link:i.link||null,via:i.via||null,...i.by?{by:i.by}:{}})),...ct(f,w.map(i=>f.byKey.get(i))).map(i=>({ts:i.ts,who:"love",via:"site",kind:i.kind,text:gs(i,v),files:i.data.files||[],eventId:i.id,reply:i.reply,replies:i.replies,...ws(i,v),...Ye(i)})),..._.map(i=>{const S=[i.data.label||i.data.choice,i.data.note].filter(Boolean).join(" \xB7 ");return{ts:i.ts,who:"love",via:"questions",kind:i.kind,text:`${Nt(v,v.get(i.data.id))}
3
- \u2192 ${S}`,files:i.data.files||[],eventId:i.id,reply:i.reply,replies:i.replies,status:ps,...Ye(i)}}),...(f.reopens.get(`item:${e}`)||[]).map(i=>({ts:i.ts,who:"love",kind:i.kind,request:!0,mark:ks,text:`Question ${Ct(v,i.data.question)} was reopened`,...Ye(i)})),...ct(f,[...new Set(p)].map(i=>f.asks.has(i)?[f.asks.get(i)]:[])).flatMap(i=>[{ts:i.ts,who:"love",via:"ask",kind:i.kind,text:i.data?.text||"",files:i.data?.files||[],eventId:i.id,reply:i.reply,replies:i.replies,...u.includes(i.id)?{moved:!0}:{},...Ye(i),...typeof i.data?.from?.title=="string"?{from:i.data.from.title}:{}},...i.data?.quick===!0?[{ts:i.ts,who:"love",...Dt("implement"),text:Xe.implement}]:[],...c.map(S=>({ts:i.ts,who:"claude",kind:"ask-link",text:S.folded?`Moved to ${S.ref}: ${S.title}`:`${S.became?"Became":"Added to"} ${S.ref}`,link:`#selectedCard=${encodeURIComponent(S.key)}`,html:null,via:null}))])].sort((i,S)=>String(i.ts).localeCompare(String(S.ts))),W=Lt(T),{edits:h,editFiles:b}=f;for(const i of T){if(!i.eventId)continue;(i.kind==="ask"||i.kind==="item-message")&&typeof h.get(i.eventId)=="string"&&Object.assign(i,{text:h.get(i.eventId),edited:!0,files:[...i.files,...b.get(i.eventId)||[]]});const S=i.kind==="ask"&&(c.length>0||!!i.moved);i.state=i.reply?"replied":S||C.has(i.eventId)||W>String(i.ts)?"answered":R(r,i.eventId)?"working":"waiting",i.canDelete=i.kind==="item-message"&&(i.state==="working"||i.state==="waiting"),i.canEdit=i.canDelete}return vs(T)}d(Ss,"threadOf");const Pt=["waiting","working","answered","replied"];function vs(e){const t=new Map;for(const n of e)n.kind==="owner-answer"&&t.set(n.ts,[...t.get(n.ts)||[],n]);return e.flatMap(n=>{if(n.kind!=="owner-answer")return[n];const s=t.get(n.ts);return s.length===1?[n]:s[0]!==n?[]:[{...n,text:s.map(r=>r.text).join(`
1
+ var Vt=Object.defineProperty;var d=(e,t)=>Vt(e,"name",{value:t,configurable:!0});import{routeRecord as R}from"../hub/routes.mjs";import Xt from"node:fs";import{ticketBadge as pt,ticketIn as Yt}from"./tickets.mjs";import{prLinks as zt,reviewLinks as Jt,reviewTime as Zt,reviewersOf as en}from"./review.mjs";import{remoteFromInput as tn}from"../hub/repos.mjs";import{reviewsOf as nn,reviewNeeds as sn,reviewActions as on}from"./auto-review.mjs";import{cardPRs as rn,hasPR as et,leastReady as an,prKeyOf as ln,prURL as dn}from"../shared/card-prs.mjs";import ft from"node:vm";import{checkWords as cn,parseCheck as un}from"../shared/owner-check.mjs";import{buildScriptOf as pn}from"./build-script.mjs";import{HUB as Qe,hubLineOf as gt}from"./hub-lines.mjs";const fn="card-merged",tt=ft.createContext({});for(const e of["ui-enums.js","ui-order.js"])ft.runInContext(Xt.readFileSync(new URL(`./public/${e}`,import.meta.url),"utf8"),tt);const{BUTTON:ce,ACTION_KIND:q,BUILDER_KIND:ue,PR_STATE:V,PHASES:kt}=tt.BoardUI,{laneOrder:gn}=tt.BoardUI,kn=["item-message","mark-ready","grill-more","prototype-request","visual-request","reask-request"],mt="question-reopen",So=Object.freeze({todo:"Todo",progress:"In Progress",review:"In Review",done:"Done"}),$e="move",mn=10*6e4,wn=5*6e4,wt="build-refused",De=Object.freeze({ask:"builder-ask",answer:"builder-answer"}),hn=864e5,pe=d(e=>e.lane==="done","closedLane"),yn=d(e=>`file:${e}`,"fileFold"),ht=7*hn,yt=d((e,t)=>({id:e,url:t?.workspace?`https://linear.app/${t.workspace}/issue/${e}`:null}),"linearRef"),bn=d(e=>String(e).replace(/^S(\d+)$/,"INT-$1"),"internalRef"),nt=d((e,t,n)=>Yt(n,t.ticket)?t.ticket:e.internal===!0?bn(t.id):t.id,"refOf"),Sn=d((e,t,n)=>pt(e,t,n)||(t?{id:String(t),url:null,source:null}:null),"ticketOf");function vn(e,t,n,s,r,a,c,l,u){return!a&&(e.lane==="done"||t?.state==="MERGED"||t?.state==="CLOSED")?"done":(n||s)&&!l?"progress":r?"review":t?.state==="OPEN"?t.checks?.state==="fail"&&(!t.isDraft||c)?"progress":"review":t||u?"progress":"todo"}d(vn,"laneOf");const He="Lander",bt=d(e=>e.kind!==ue.install&&e.label!==He,"changesCode");function xn(e,t){return e?.state==="MERGED"||t?V.merged:e?.state==="CLOSED"?V.closed:e?.state==="OPEN"?e.isDraft?V.draft:V.open:null}d(xn,"prStateOf");const St=d(e=>e.pr?.status===V.closed,"unlanded"),On=d(e=>e.some(t=>t.kind==="work")&&e.every(t=>t.lane==="done"),"finishedOf");function st(e){const t=vt(e);return t?.done&&t.handed_back?t.handed_back:null}d(st,"handedBackAt");const vt=d(e=>e.filter(t=>t?.started&&Q(t)&&t.kind!==ue.install&&t.kind!==ge).sort((t,n)=>String(t.started).localeCompare(String(n.started))).at(-1),"newestBuild");function En(e,t,n){return Object.fromEntries(e.map(s=>{const r=R(t?.reviews,s.github),a=r==="APPROVED"?"approved":r==="CHANGES_REQUESTED"?"changes":Object.hasOwn(n,s.name)?"sent":"unsent";return[s.name,{state:a,since:a==="sent"?R(n,s.name):null,github:s.github||null}]}))}d(En,"reviewOf");function $n(e,t,n,s,r,a,{held:c,needsApproval:l}){return n?.kind===ue.install?"builder":s?"checking":n?"builder":c&&e==="review"?"merge":r&&e==="review"?"owner":e==="review"&&t?.state==="OPEN"&&t.isDraft?a?"ci":"ready":e==="review"?xt(t,l)?"merge":"reviewers":null}d($n,"waitsOnOf");const xt=d((e,t)=>e?.reviewDecision==="APPROVED"||!t&&!["REVIEW_REQUIRED","CHANGES_REQUESTED"].includes(e?.reviewDecision),"reviewed"),Ne=/(^|\/)prototype-[\w-]+\.html/,An={reviewers:"Waiting for PR reviewers",merge:"Approved, merges once CI and the merge state allow",ci:"Marked ready for review once CI passes"},Ve={waiting:"Approved, Merge shows once CI and the merge state allow",ready:"Approved and green: tap Merge",merging:"Merging"},ot={auto:"Ready, merges once CI and the merge state allow",waiting:"Ready, Merge shows once CI and the merge state allow",ready:"Ready and green: tap Merge"},Bn=d(e=>`Verified: tap Merge to land it on ${e}`,"heldNext"),_n="Fix the failing CI",Rn="Your reply waits on the orchestrator",Mn="Tap Done",In=["status","agent","ask-link","command",$e,De.answer],qn=d(e=>(e.who==="claude"||e.via==="github")&&!In.includes(e.kind)&&(e.kind!==Qe||gt(e).fault),"countsUnread"),Cn=["lander-handoff","land-waiting"];function Dn({slug:e,itemFile:t,it:n,order:s,prs:r,repo:a,remote:c,base:l,builder:u,reachedPhase:m,agents:f,worktree:p,eta:w,thread:v,events:_,working:x,said:P,askedAt:C,topicItems:L,prSlack:T,boardReviewers:W,now:h,bumpedAt:b,holdAsk:i,closedAt:S,mergeAt:oe,autoMerge:me,skipDraft:we,tickets:K}){const F=r.map(k=>({repo:k.repo,number:k.number,...k.gh||k.kept||{},url:(k.gh||k.kept)?.url||dn(k),status:xn(k.gh,k.merged_at)})),ee=an(r.map(k=>k.gh)),I=r[ee]?.gh||null,G=F[ee]?.status??null,ze=n.lane||null,U=!!S&&String(S)>String(n.lane_at||"");U&&(n={...n,lane:"done",closed_at:S,reopened_at:void 0});const D=[n.closed_at,...r.flatMap(k=>[k.merged_at,k.gh?.mergedAt])].filter(Boolean).map(String).sort().pop()||null,he=String(D||""),ye=F.length>0&&F.every(k=>k.status===V.closed),be=(n.lane==="done"||n.reopened_at||G===V.merged)&&!ye&&([...P.filter(k=>k.kind==="item-message").map(k=>k.ts),...C].map(String).filter(k=>k>he).sort().pop()||n.reopened_at)||void 0,Le=n.answered_at&&!n.phase&&!n.closed_at&&!be?String(n.answered_at):void 0,j=be||Le,Re=n.owner_step&&!U?String(n.owner_step):null,Je=(n.lane==="done"||G===V.merged)&&!ye,H=!!j&&!!n.next&&String(n.next_at||"")>String(n.reopened_at||D||"");j&&!H&&(n={...n,next:void 0});const X=st(f),Te=j&&P.filter(k=>String(k.ts)>he&&(k.state==="waiting"||k.state==="working")).map(k=>String(k.ts)).sort()[0]||null,Se=!!Te,ve=`${e}/${n.id}`,xe=en(t,W),Pe=Object.fromEntries(Object.entries(Jt(t,n,ve,L,zt(T,r))).map(([k,de])=>[k,Zt(de.ts)])),te=Object.values(Pe).filter(Boolean).sort()[0]||null,Ue=[...v.map(k=>k.ts),..._.map(k=>k.ts)].sort().pop()||null,je=[...v.filter(k=>qn({...k,who:k.who||"claude"})).map(k=>k.ts),..._.map(k=>k.reply?.at)].filter(Boolean).sort(),Y=!et(n)&&n.pushed?.branch?{branch:n.pushed.branch,at:n.pushed.at||null,host:c?.host||null}:null,z=!et(n)&&n.merge_ready?.branch?{branch:n.merge_ready.branch,at:n.merge_ready.at||null,base:l}:null,Me=!!n.rebase_run&&I?.state==="OPEN",Ie=(n.rebased||[]).at(-1),re=f.filter(k=>k.started&&!k.done&&Q(k)),Ze=!!X&&bt(vt(f));let A=vn(n,I,re.some(bt),Ze,Y||z,!!j,we,Me,re.length>0||!!X);j&&A==="todo"&&(A="progress");const We=A==="review"&&!!te&&h-Date.parse(te)>ht,ae=!!Re&&Je&&A==="done";ae&&(A="review");let N=$n(A,I,u,!!X&&A!=="done",Y,we,{held:z,needsApproval:xe.length>0});const Fe=N==="builder"&&I?.state==="OPEN"&&!I.isDraft,qe=A==="progress"&&!N&&I?.state==="OPEN"&&(!I.isDraft||we),Oe=ae||!!j&&A==="progress"&&!N&&!qe&&!Se&&!H;Oe&&(N="owner");const o=!!j&&f.some(k=>Q(k)&&String(k.started||"")>String(j)),g=A==="progress"&&!N&&(qe||!!j&&!o);g&&(A="review");const E=i&&String(i.ts)>String(n.held_at||""),$=A==="todo"&&(E?!!i.data.hold:!!n.held),y=$&&(E?i.data.until:n.pick_up_at)||null,M=A!=="done",B=!!b&&!(he&&String(b)<=he),Ke=v.filter(k=>(k.who||"claude")==="claude"&&!["status","command",$e].includes(k.kind)&&!Cn.includes(k.line)).map(k=>String(k.ts)).sort().pop()||"",le=[oe,z&&n.merge_ready.tapped].filter(Boolean).map(String).sort().pop(),Ce=N==="merge"&&!!le&&le>Ke,Ee=v.filter(k=>(k.kind==="status"||k.kind===Qe)&&String(k.ts)>String(le)).sort((k,de)=>String(k.ts).localeCompare(String(de.ts))).at(-1),ne=Ee?.line==="land-waiting"?`${Ve.merging} \xB7 ${Ee.text[0].toLowerCase()}${Ee.text.slice(1)}`:Ve.merging,J=v.filter(k=>!["status",$e].includes(k.kind)).sort((k,de)=>String(k.ts).localeCompare(String(de.ts))).at(-1),O=A==="todo"&&J?.line===wt?J.text:null,ie=j||f.filter(Q).map(k=>k.started).filter(Boolean).map(String).sort().pop()||null,Ge=I?.reviewDecision==="APPROVED",Kt=Y&&N==="owner"?`merge ${Y.branch} into ${l}`:z&&N==="merge"?Ce?ne:Bn(l):N==="merge"&&!me?Ce?ne:(Ge?Ve:ot).waiting:N==="merge"&&!Ge?ot.auto:An[N],Gt=G===V.draft?`Review draft PR #${F[ee].number}`:null,Qt=!Me&&Ie?.to&&Ie.to===I?.headRefOid?`Rebased onto ${Ie.base||l}, pushed${I.mergeable==="MERGEABLE"?" \xB7 PR is clean again":""}`:null,Ht=Me&&N==="checking"?f.flatMap(k=>k.calls).sort((k,de)=>String(k.at).localeCompare(String(de.at))).at(-1)?.text??null:null;return{key:ve,kind:"work",order:s,file:e,fileTitle:t.title||e,id:n.id,ref:nt(t,n,K),title:n.title,storedLane:ze,created:n.created||null,reviewSince:g&&j||n.review_since||te||n.merge_ready?.at||n.pushed?.at||n.created||null,progressSince:ie,closedAt:A==="done"?D:null,internal:t.internal===!0,repo:t.internal===!0&&!t.repo?null:a,lane:A,waitsOn:N,builder:N==="checking"?null:u,reachedPhase:m,agents:f,worktree:p??null,eta:w,working:x,reopened:!!be,answered:!!Le,awaitsDone:Oe,ownerStep:Oe?Re:null,ownerCheck:Oe&&Re&&n.owner_check?{words:cn(un(n.owner_check.check)),broken:n.owner_check.broken||null}:null,stagedAt:A==="todo"&&n.phase==="staging"&&n.staged_at||null,roundAt:n.round_at||null,deps:n.deps||[],blockedUntil:n.blocked_until||null,blockReason:n.block_reason||null,held:$,heldUntil:y,risky:!!n.risky,bumpable:M,bumpedAt:M&&B?b:null,holdable:A!=="done",hasNotes:!!(n.plan||String(n.notes||"").trim()),finishable:A!=="done",merging:Ce,refusal:O,manualSteps:n.manual_steps||[],fromAsk:n.from_ask||null,unfiled:!!n.unfiled,filedHeld:!!n.filed_held,next:Fe||A==="done"||N==="checking"?null:g&&Se?Rn:qe?_n:Qt||Kt||n.next||Gt||null,rebaseFailed:Ht,branch:n.branch||I?.headRefName||Y?.branch||null,pushed:A==="done"||ae?null:Y,mergeReady:A==="review"?z:null,stale:A!=="done"&&(We||!!u?.stale),stalled:n.stalled?.reason||null,landStopped:A==="review"&&z&&n.merge_ready.stopped&&String(n.merge_ready.stopped)>String(n.merge_ready.tapped||"")?{words:At("land"),at:n.merge_ready.stopped}:null,ticket:K?.source==="linear"&&!n.ticket&&n.linear?.length?null:Sn(K,n.ticket,{repo:a}),ticketSource:K?.source||null,linear:(n.linear||[]).map(k=>K?.source==="linear"&&pt(K,k,{repo:a})||yt(k,K)),pr:F[ee]||null,prs:F,reviewers:xe.map(k=>k.name),review:En(xe,I||r[ee]?.kept,Pe),inReviewSince:te,threadCount:v.length+_.length,lastTs:Ue,othersAt:je,grilling:Bt("grill",_,f,C),prototyping:Bt("prototype",_,f,C),storedPhase:n.phase||null,phase:null,recheckAt:n.recheck_at||null,updatedAt:I?.mergedAt||I?.updatedAt||r[ee]?.merged_at||u?.at||Ue||null,ask:null,fold:null,action:null,install:A==="done"?null:Ln(n.install,I),waitFacts:Nn(n,{agents:f,thread:v,events:_,refusedAt:O?J.ts:null,replyAt:g?Te:null})}}d(Dn,"workItem");function Nn(e,{agents:t,thread:n,events:s,refusedAt:r,replyAt:a}){const c=new Set(n.filter(f=>f.kind===De.answer).map(f=>f.ask)),l=n.filter(f=>f.kind===De.ask&&!c.has(f.ask)).sort((f,p)=>String(f.ts).localeCompare(String(p.ts)))[0],u=d(f=>s.filter(p=>at(p,f)).pop()?.ts||null,"requestAt"),m=n.filter(f=>(f.who||"claude")==="claude"&&!["status","agent","command",$e].includes(f.kind)&&f.line!==wt).map(f=>f.ts);return{handedBackAt:st(t),next:e.next||null,ask:l?{at:l.ts,text:l.text}:null,grillAt:u("grill"),prototypeAt:u("prototype"),refusedAt:r,replyAt:a,unblockedAt:e.unblocked_at||null,unverified:t.some(f=>f.calls.some(p=>!f.verified||String(p.at)>String(f.verified.at))),writes:[...m,...t.flatMap(f=>[f.verified?.at,f.started])].filter(Boolean).map(String).sort()}}d(Nn,"waitFactsOf");function Ln(e,t){if(!e?.url)return null;const n=e.sha?String(e.sha).toLowerCase():null,s=t?.headRefOid?String(t.headRefOid).toLowerCase():null;return{url:e.url,label:e.label||null,builtAt:e.built_at||null,sha:n,older:!!(n&&s&&!s.startsWith(n))}}d(Ln,"installOf");function Tn(e,{needsApproval:t=!0}={}){if(e?.state!=="OPEN")return[`PR is ${String(e?.state||"unknown").toLowerCase()}`];const{state:n,pending:s,failing:r}=e.checks||{};return[e.isDraft&&"it is a draft",!xt(e,t)&&`review: ${String(e.reviewDecision||"none").toLowerCase().replace(/_/g," ")}`,n==="fail"&&`failing: ${r?.length?r.join(", "):"a check"}`,n==="pending"&&`pending: ${s?se(s,"check"):"checks"}`,e.mergeStateStatus!=="CLEAN"&&`merge state: ${String(e.mergeStateStatus||"unknown").toLowerCase()}`].filter(Boolean)}d(Tn,"mergeBlockers");const Pn=d((e,t)=>!Tn(e,{needsApproval:t}).length,"mergeable");function Un(e,t,n){if(pe(e))return null;const s=`#selectedCard=${encodeURIComponent(e.key)}`;if(e.stalled)return{kind:q.stalled,url:s,label:`stalled: ${e.stalled}`};if(jn(e)){const r=t.get(e.questions.first);return Ne.test(r?.url||"")?{kind:q.pick,url:`questions.html#${r.id}`,label:"Prototypes ready: pick a take"}:{kind:q.questions,url:`questions.html#${e.questions.first}`,label:`Answer ${se(e.questions.open,"question")}`}}return e.waitsOn==="ready"?{kind:q.ready,url:e.pr.url,label:`Review draft PR #${e.pr.number}`}:e.waitsOn==="merge"&&e.manualSteps.length&&!e.mergeReady?{kind:q.steps,url:s,label:"Run the manual steps, then merge"}:e.waitsOn==="merge"&&(!n||e.mergeReady)&&!e.merging&&e.prs.every(r=>["MERGED","CLOSED"].includes(r.state)||Pn(r,e.reviewers.length>0))?{kind:q.merge,url:s,label:"Merge"}:null}d(Un,"actionOf");const jn=d(e=>!!(e.questions&&e.questions.state!=="resolved"&&e.questions.open>0),"asking"),rt=new Set([q.pick,q.questions]);function Ot(e){return e.questions?ce.openQuestions:null}d(Ot,"actionButtonOf");const Wn=d(e=>e.kind==="work"&&e.lane==="todo"&&!e.action&&!e.unpicked,"buildableOf"),Fn=d((e,t)=>/^item:/.test(e.topic||"")&&Ne.test(e.url||"")&&!(e.options||[]).some(n=>n.id===t),"picksNoTake");function Kn(e,t){const n=e.filter(a=>a.topic===`item:${t}`),r=[...n.filter(a=>Ne.test(a.url||"")).flatMap(a=>a.answers.map(c=>({q:a,a:c,again:Fn(a,c.choice)}))),...n.filter(a=>a.request).map(a=>({q:a,a:a.request,again:!0}))].sort((a,c)=>String(a.a.ts).localeCompare(String(c.a.ts))).at(-1);return r?.again?{id:r.q.id,note:r.a.note.replace(/\s+/g," ").trim()}:null}d(Kn,"noTakePicked");const Gn="Prototype again",Qn=Object.freeze({[q.pick]:ce.openQuestions,[q.questions]:ce.openQuestions,[q.ready]:ce.github,[q.steps]:ce.github,[q.merge]:ce.merge,[q.stalled]:ce.reply}),Hn="Merges once unblocked",Vn=d(e=>`Blocked ${[e.blockedBy.length&&`by ${e.blockedBy.map(t=>t.ref).join(", ")}`,e.blockedUntil&&`until ${e.blockedUntil}`].filter(Boolean).join(" and ")}`,"mergeBlockedWords");function Xn(e,t,n){if(e.action=Un(e,t,n),e.mergeBlocked=e.action?.kind===q.merge&&e.blocked?Vn(e):null,e.mergeBlocked&&Object.assign(e,{action:null,next:Hn}),e.action?.kind===q.questions&&e.questions.fromAsks){Object.assign(e,{action:null,waitsOn:"owner",next:e.action.label,actionButton:Ot(e),resolvedBy:null});return}e.awaitsDone&&=!e.action,e.awaitsDone||Object.assign(e,{ownerStep:null,ownerCheck:null}),e.actionButton=Ot(e),e.resolvedBy=Qn[e.action?.kind]||null,e.action?.kind===q.merge&&!e.mergeReady&&(e.next=(e.pr?.reviewDecision==="APPROVED"?Ve:ot).ready),e.awaitsDone&&Object.assign(e,{lane:"review",next:e.ownerStep||Mn,bumpable:!1,bumpedAt:null});const s=e.lane==="todo"||e.waitsOn==="ready"||e.lane==="progress"&&e.waitsOn==="owner";if(!e.action||!s||e.stalled)return;const r=e.lane==="todo"&&rt.has(e.action.kind)?"todo":"review";Object.assign(e,{lane:r,waitsOn:e.waitsOn==="ready"?"ready":"owner",next:e.action.label})}d(Xn,"placeOwnerWait");const Et=d((e,t)=>e?e!=="todo":t.some(Q),"started"),$t="none set yet";function vo(e,t){const n=t.filter(s=>s?.started);return e.next||et(e)||e.pushed||e.held||e.lane==="done"||st(n)?!1:!n.some(s=>!s.done)&&Et(e.lane,n)}d(vo,"owesNext");const fe="visual",ge="helper",Yn=new Set(["grill","prototype",fe]),Z=d(e=>Yn.has(e.kind),"plans"),Q=d(e=>!Z(e),"builds"),zn={grill:"grilling",prototype:"prototyping"},Jn=d((e,t)=>`${e} ${t} by orchestrator`,"orchestratorDid"),At=d(e=>Jn(e,"stopped"),"stoppedWords"),Zn={grill:"grill-more",prototype:"prototype-request"},at=d((e,t)=>e.kind===Zn[t]&&!e.data?.question,"isRequest");function Bt(e,t,n,s){if(n.some(a=>a.kind===e&&a.started&&!a.done))return!0;const r=t.filter(a=>at(a,e)).pop();return!!(r&&!r.reply&&!s.some(a=>String(a)>String(r.ts))&&!n.some(a=>a.kind===e&&a.done&&String(a.started)>=String(r.ts)))}d(Bt,"planningOf");const xo=30*6e4;function Oo(e,t){const n=[];for(const s of e.items){if(pe(s)||(s.agents||[]).some(a=>a.kind==="prototype"&&a.started&&!a.done))continue;const r=s.prototyping&&t.filter(a=>a.data?.key===s.key&&at(a,"prototype")).pop();r&&n.push({key:s.key,request:r.id,since:r.ts});for(const a of e.owner.filter(c=>c.topic===`item:${s.key}`&&c.state==="requested"))n.push({key:s.key,request:a.request.id,question:a.id,since:a.request.ts})}return n}d(Oo,"prototypeWaits");function lt(e={},t=!1){return Object.entries(e).filter(([n,s])=>s&&typeof s=="object"&&(t||!n.startsWith("past-"))).map(([n,s])=>({name:n,kind:_t(s.kind)||null,model:s.model||(s.kind==="opus"||s.kind==="sonnet"?s.kind:null),label:s.label||null,started:s.started||null,eta:s.done?null:s.eta||null,done:s.done||null,log:s.session?.log||null,pid:s.session?.pid??null,calls:Array.isArray(s.calls)?s.calls:[],verified:s.verified||null,stopped:s.stopped||null,handed_back:s.handed_back||null,...s.pause?{pause:s.pause}:{},...s.kind===ge?{writes:!!s.writes,requested:s.requested||null}:{},...s.waits?{waits:s.waits}:{}})).sort((n,s)=>String(n.started||"").localeCompare(String(s.started||""))||n.name.localeCompare(s.name))}d(lt,"agentsOf");function it(e={}){return Object.values(e).filter(t=>t?.worktree?.path).sort((t,n)=>String(t.started||"").localeCompare(String(n.started||""))).at(-1)?.worktree.path??null}d(it,"worktreeOf");function es(e,t=[]){const n=e.filter(Q).map(s=>String(s.started||"")).filter(Boolean).sort().pop();return n===void 0?null:t.filter(s=>s.kind==="status"&&s.phase&&!s.planner&&String(s.ts)>=n).sort((s,r)=>String(s.ts).localeCompare(String(r.ts))).pop()?.phase||null}d(es,"reachedPhaseOf");function ts(e,t=[],n,s=null,r=null,a=!1){const c=e.filter(b=>b.started&&!b.done&&b.kind!==fe),l=c.every(Z),u=l?c:c.filter(Q),m=u.map(b=>String(b.started||"")).sort()[0];if(m===void 0)return null;const f=t.filter(b=>b.kind==="status"&&String(b.ts)>=m&&(l||!b.planner)).sort((b,i)=>String(b.ts).localeCompare(String(i.ts))).pop(),p=u.filter(b=>b.kind!==ge).at(-1),w=u.some(b=>b.kind===ue.install)?ue.install:p?_t(p.kind):"claude",v=l?null:u.find(b=>b.stopped&&String(b.stopped.at)>=String(b.started))?.stopped,_=f?.ts||m,x=v?v.at:s!==null&&s>Date.parse(_)?new Date(s).toISOString():_,P=f?f.phase||f.planner?f.text.replace(": "," \xB7 "):f.text||null:l?zn[w]:null,C=n-Date.parse(x),L=l?null:u.find(b=>b.pause)?.pause??null,T=!l&&!v&&(r==="held"||!!L?.paused),W=l||T?null:v?!1:r,h=T?!1:W===null?C>=mn:!W;return{progress:P,phase:f?.phase||null,at:_,kind:w,planner:l,silentSince:x,stale:h,alive:W,held:T,quiet:!!L||W===!0&&!a&&C>=wn,stopped:v?At(v.run):null,...L?{pause:{cause:L.cause,words:L.words,paused:!!L.paused}}:{}}}d(ts,"builderOf");const Eo={blocked:["nothing blocks it","nothing blocks it"],held:["you unhold it","unheld"],usage:["the usage pause lifts","the usage pause lifted"],bumped:["a slot frees","a slot freed"]},ns=15*6e4,ss=d(e=>(e.agents||[]).find(t=>t.name==="main"&&t.started&&!t.done&&Q(t))??null,"mainBuild"),os=d((e,t,n,{now:s,usageHeld:r})=>e.blocked||e.held||r(n??"claude")||!!(t.until&&s<Date.parse(t.until)),"stillPaused");function rs(e,{now:t=Date.now(),usageHeld:n}){const s={ask:[],drop:[],stop:[],resume:[]},r=[];for(const a of e){if(a.kind!=="work"||a.lane!=="progress")continue;const c=ss(a);if(!c)continue;const{pause:l}=c;if(!l){a.builder?.phase!=="landing"&&n(c.kind??"claude")&&s.ask.push(a.key);continue}const u=os(a,l,c.kind,{now:t,usageHeld:n});if(l.paused){u||r.push({key:a.key,at:l.paused});continue}!u&&l.cause!=="bumped"?s.drop.push(a.key):t-Date.parse(l.at)>=ns&&s.stop.push(a.key)}return s.resume=r.sort((a,c)=>String(a.at).localeCompare(String(c.at))).map(a=>a.key),s}d(rs,"pauseWork");function $o(e,t,n){const s=rs(t,n).drop;return e.filter(r=>s.includes(r))}d($o,"confirmedDrops");const dt={opus:"Claude Opus",sonnet:"Claude Sonnet",codex:"Codex"},as=d(({model:e,kind:t})=>dt[e]||dt[t]||(t==="claude"?dt.opus:null),"modelName"),_t=d(e=>e==="opus"||e==="sonnet"?"claude":e,"providerOf");function Ae(e){const t=as(e),{kind:n}=e,s=e.label?.replace(/\bbuilder\b/,"implementer").replace(/\bBuilder\b/,"Implementer"),r=d(c=>c[0].toLowerCase()+c.slice(1),"lower");if(t&&Z(e))return`${t} ${n}`;if(t)return`${t} ${r(s?.replace(/^(?:claude\s+)?(?:opus|sonnet|codex)\b\s*/i,"")||"implementer")}`;const a=n?n[0].toUpperCase()+n.slice(1):"";return a?s?s.toLowerCase().includes(n.toLowerCase())?s:`${a} ${r(s)}`:a:s||"Implementer"}d(Ae,"agentName");const Rt=d((e,t)=>!!e.resolved&&(!e.resolved_at||String(e.resolved_at)>=String(t)),"resolvedSince");function ls(e,t,n=[],s=[],r=[]){const a=t.filter(x=>x.data?.id===e.id),c=a[a.length-1]||null,l=r.filter(x=>x.data?.question===e.id).at(-1),u=d((x,...P)=>!!x&&P.every(C=>String(x.ts)>String(C||"")),"after"),m=!!(e.resolved&&e.resolved_at&&c&&String(c.ts)>e.resolved_at),f=n.filter(x=>x.data?.question===e.id&&u(x,c?.ts,l?.ts)).at(-1),p=u(l,c?.ts,f?.ts,e.resolved_at),w=e.resolved&&!m&&!p,v=w?s.filter(x=>x.data?.question===e.id&&String(x.ts)>String(e.resolved_at||"")).at(-1):null,_=p?"open":w?"resolved":f?"requested":c?c.reply?"replied":"answered":"open";return{...e,state:_,reopened:p,request:f?{id:f.id,ts:f.ts,note:f.data.note||"",choice:f.data.choice||null}:null,reask:v?{id:v.id,ts:v.ts}:null,answers:a.map(x=>({ts:x.ts,choice:x.data.choice||null,note:x.data.note||"",files:x.data.files||[],reply:x.reply,replies:x.replies,acted:Rt(e,x.ts)}))}}d(ls,"ownerQuestion");const ke=d(e=>e.round??(Ne.test(e.url||"")?1:0),"roundOf");function is(e,t){const n=d((s,r)=>s.confirm_of||(s.options||[]).some(a=>a.id===r.choice),"settles");return e.filter(s=>ke(s)===t&&s.answers.length).map(s=>[s,s.answers.at(-1)]).filter(([s,r])=>n(s,r)).map(([,s])=>s).sort((s,r)=>String(s.ts).localeCompare(String(r.ts))).at(-1)}d(is,"roundSettledBy");function ds(e){const t=e.find(r=>r.request&&!e.some(a=>ke(a)>ke(r)));if(t)return{n:ke(t)+1,state:"making"};const n=Math.max(0,...e.map(ke));if(!n)return null;const s=is(e,n);return s?{n,state:"closed",take:s.choice}:e.some(r=>ke(r)===n&&r.state!=="resolved")?{n,state:"back"}:null}d(ds,"roundState");function cs(e){const t=e.filter(n=>Ne.test(n.url||"")).map(n=>({n:ke(n),q:n.id,url:n.url,confirm:!!n.confirm_of,state:n.state})).sort((n,s)=>n.n-s.n);return t.length?{open:t.some(n=>n.state==="open"),rounds:t}:null}d(cs,"prototypesOf");const Be=d((e,t,n)=>{const s=e.get(t);s?s.push(n):e.set(t,[n])},"add"),_e=d((e,t)=>{const n=new Map;for(const s of e)Be(n,t(s),s);return n},"groupBy");function us(e,t,n=new Set){const s=new Set(e.map(c=>c.id)),r=[...e];t.some(c=>!s.has(c.topic))&&r.push({id:"",title:"Other"});const a=_e(t,c=>s.has(c.topic)?c.topic:"");return r.map(c=>{const l=a.get(c.id)||[],u=d(p=>l.filter(w=>w.state===p).length,"count"),m=l.every(p=>p.state==="resolved")||n.has(c.id)&&!u("open"),f=l.length&&m?"resolved":"open";return{...c,state:f,questions:l.map(p=>p.id),open:u("open"),answered:u("answered"),replied:u("replied"),resolved:u("resolved"),round:ds(l)}}).filter(c=>c.questions.length)}d(us,"ownerTopics");const Xe={implement:"Implementation requested",prototype:"Prototype requested",grill:"Grill requested",visual:"Visual requested",reask:"Re-ask requested",hold:"Held",resume:"Resumed",done:"Marked done",staged:"Marked as staging",readied:"Marked as ready",related:"Related to",unrelated:"Unrelated from",followup:"Follow-up","followup-of":"Follow-up of"},Mt={"grill-more":"grill","prototype-request":"prototype","visual-request":"visual","reask-request":"reask"},It={"mark-ready":"Mark ready",...Object.fromEntries(Object.entries(Mt).map(([e,t])=>[e,Xe[t]]))},ps=["grill-more","prototype-request","visual-request"],fs="answers submitted",qt={reply:"Reply",build:"Implement"},gs=d(e=>qt[e.data.intent],"intentLabel"),ks=d((e,t)=>{if(e.kind!=="prototype-request"||!t.has(e.data.question))return e.data.text||(e.data.files?.length?"":R(It,e.kind))||"";const n=t.get(e.data.question),s=(n.options||[]).find(r=>r.id===e.data.choice);return[Dt(t,n),s&&`${s.id}. ${s.label}`,e.data.note].filter(Boolean).join(`
2
+ \u2192 `)},"actionText"),Ct=d((e,t)=>[...e.keys()].indexOf(t)+1,"numberOf"),Dt=d((e,t)=>`Question ${Ct(e,t.id)} \xB7 ${t.question}`,"numbered"),ms="question reopened",Ye=d(e=>e.data?.shared_by?.login?{by:e.data.shared_by.name||e.data.shared_by.login}:{},"byOf"),ws=d((e,t)=>{const n=t.get(e.card);return{...e,text:`${Xe[e.command]} ${n?`${n.ref}: ${n.title}`:e.card}`,link:`#selectedCard=${encodeURIComponent(e.card)}`}},"linkLine"),Nt=d(e=>({kind:"command",command:e,request:!0,mark:Xe[e]}),"commandLine"),hs=d((e,t)=>{if(e.kind==="item-message")return qt[e.data.intent]?{status:gs(e)}:{};const n={request:!0,command:Mt[e.kind]};return ps.includes(e.kind)?(e.data.question?t.has(e.data.question):String(e.data.text||"").trim()||e.data.files?.length)?{status:It[e.kind]}:n:e.kind==="reask-request"?n:{}},"requestOf"),Lt=d(e=>[...e.filter(t=>t.who==="claude"&&!["status","agent","command",$e,De.answer].includes(t.kind)).map(t=>t.ts),...e.filter(t=>t.kind==="ask").map(t=>t.reply?.at)].filter(Boolean).map(String).sort().pop()||"","claudeAtOf");function Tt(e,t={}){const n=new Map,s=new Map;for(const p of t.items||[])Be(n,p.topic,p),s.set(p.id,p.topic);const r=new Map,a=new Map,c=new Map,l=new Map,u=new Map,m=new Map,f=new Map;e.forEach((p,w)=>{f.set(p,w),p.data?.key&&kn.includes(p.kind)&&Be(r,p.data.key,p),p.kind==="owner-answer"&&s.has(p.data?.id)&&Be(a,s.get(p.data.id),p),p.kind===mt&&s.has(p.data?.question)&&Be(c,s.get(p.data.question),p),p.kind==="ask"&&l.set(p.id,p)});for(const p of e.filter(w=>w.kind==="ask-edited").sort((w,v)=>String(w.ts).localeCompare(String(v.ts)))){u.set(p.data?.id,p.data?.text);for(const w of p.data?.files||[])Be(m,p.data?.id,w)}return{byKey:r,answers:a,reopens:c,asks:l,edits:u,editFiles:m,questions:n,order:f}}d(Tt,"threadIndex");const ct=d((e,t)=>{const n=t.filter(s=>s?.length);return n.length>1?n.flat().sort((s,r)=>e.order.get(s)-e.order.get(r)):[...n[0]||[]]},"inLogOrder"),ys=/; its log is \S*\/\.claude\/kickflip\/logs\/([^/\s]+\.log)\.$/,bs=d(e=>{const t=!e.log&&typeof e.text=="string"?ys.exec(e.text):null;return t?{...e,text:`${e.text.slice(0,t.index)}.`,log:t[1]}:e},"withLog");function Ss(e,t){const n=t.run?e.find(s=>s.started===t.run):e.filter(s=>Z(s)===!!t.planner&&s.started&&String(s.started)<=String(t.ts)&&(!s.done||String(t.ts)<=String(s.done))).pop();return n?{agent:Ae(n),run:ut(e,n),running:!n.done}:{}}d(Ss,"agentOfLine");function ut(e,t){return t.label!==He?t.started:e.filter(n=>Q(n)&&n.label!==He&&n.started&&String(n.started)<String(t.started)).pop()?.started??t.started}d(ut,"sectionOf");function vs(e,{lines:t=[],events:n=[],owner:s={},working:r={},fromAsk:a=null,links:c=[],agents:l={},moved:u=[],cards:m=new Map,index:f=Tt(n,s)}){const p=e.startsWith("ask:")?[e.slice(4)]:[a,...u].filter(Boolean),w=[...new Set([e,...p.map(i=>`ask:${i}`)])],v=new Map((f.questions.get(`item:${e}`)||[]).map(i=>[i.id,i])),_=f.answers.get(`item:${e}`)||[],x=new Set([...v.values()].map(i=>i.round_of).filter(Boolean)),P=lt(l,!0).filter(Q).map(i=>String(i.started||"")).filter(Boolean),C=new Set(_.filter(i=>Rt(v.get(i.data.id),i.ts)||x.has(i.data.id)||P.some(S=>S>String(i.ts))).map(i=>i.id)),L=lt(l,!0),T=[...L.flatMap(i=>[...i.started?[{ts:i.started,who:"claude",kind:"agent",text:`${Ae(i)} started`,agent:Ae(i),run:ut(L,i),finished:!1,eta:i.done?null:i.eta,...i.log?{log:i.log}:{},...Z(i)?{planner:!0}:{}}]:[],...i.done?[{ts:i.done,who:"claude",kind:"agent",text:`${Ae(i)} finished`,agent:Ae(i),run:ut(L,i),finished:!0,eta:null,...Z(i)?{planner:!0}:{}}]:[],...i.calls.length?[{ts:i.done||i.calls.at(-1).at,who:"claude",kind:"calls",text:Ae(i),calls:i.calls.map(S=>S.text),verified:i.verified}]:[]]),...t.map(bs).map(i=>i.card?ws(i,m):i).map(i=>({ts:i.ts,who:i.who||"claude",...i.log?{log:i.log}:{},...i.kind==="status"?{kind:"status",...i.planner?{planner:!0}:{},...Ss(L,i)}:{},...i.kind===fe||i.kind===$e?{kind:i.kind}:{},...i.kind===Qe?{kind:Qe,line:i.line,...gt(i),...i.detail?{detail:i.detail}:{}}:{},...i.command?Nt(i.command):{},...i.card?{card:i.card}:{},...Object.values(De).includes(i.kind)?{kind:i.kind,ask:i.ask}:{},text:i.text||"",html:i.html||null,link:i.link||null,via:i.via||null,...i.by?{by:i.by}:{}})),...ct(f,w.map(i=>f.byKey.get(i))).map(i=>({ts:i.ts,who:"love",via:"site",kind:i.kind,text:ks(i,v),files:i.data.files||[],eventId:i.id,reply:i.reply,replies:i.replies,...hs(i,v),...Ye(i)})),..._.map(i=>{const S=[i.data.label||i.data.choice,i.data.note].filter(Boolean).join(" \xB7 ");return{ts:i.ts,who:"love",via:"questions",kind:i.kind,text:`${Dt(v,v.get(i.data.id))}
3
+ \u2192 ${S}`,files:i.data.files||[],eventId:i.id,reply:i.reply,replies:i.replies,status:fs,...Ye(i)}}),...(f.reopens.get(`item:${e}`)||[]).map(i=>({ts:i.ts,who:"love",kind:i.kind,request:!0,mark:ms,text:`Question ${Ct(v,i.data.question)} was reopened`,...Ye(i)})),...ct(f,[...new Set(p)].map(i=>f.asks.has(i)?[f.asks.get(i)]:[])).flatMap(i=>[{ts:i.ts,who:"love",via:"ask",kind:i.kind,text:i.data?.text||"",files:i.data?.files||[],eventId:i.id,reply:i.reply,replies:i.replies,...u.includes(i.id)?{moved:!0}:{},...Ye(i),...typeof i.data?.from?.title=="string"?{from:i.data.from.title}:{}},...i.data?.quick===!0?[{ts:i.ts,who:"love",...Nt("implement"),text:Xe.implement}]:[],...c.map(S=>({ts:i.ts,who:"claude",kind:"ask-link",text:S.folded?`Moved to ${S.ref}: ${S.title}`:`${S.became?"Became":"Added to"} ${S.ref}`,link:`#selectedCard=${encodeURIComponent(S.key)}`,html:null,via:null}))])].sort((i,S)=>String(i.ts).localeCompare(String(S.ts))),W=Lt(T),{edits:h,editFiles:b}=f;for(const i of T){if(!i.eventId)continue;(i.kind==="ask"||i.kind==="item-message")&&typeof h.get(i.eventId)=="string"&&Object.assign(i,{text:h.get(i.eventId),edited:!0,files:[...i.files,...b.get(i.eventId)||[]]});const S=i.kind==="ask"&&(c.length>0||!!i.moved);i.state=i.reply?"replied":S||C.has(i.eventId)||W>String(i.ts)?"answered":R(r,i.eventId)?"working":"waiting",i.canDelete=i.kind==="item-message"&&(i.state==="working"||i.state==="waiting"),i.canEdit=i.canDelete}return xs(T)}d(vs,"threadOf");const Pt=["waiting","working","answered","replied"];function xs(e){const t=new Map;for(const n of e)n.kind==="owner-answer"&&t.set(n.ts,[...t.get(n.ts)||[],n]);return e.flatMap(n=>{if(n.kind!=="owner-answer")return[n];const s=t.get(n.ts);return s.length===1?[n]:s[0]!==n?[]:[{...n,text:s.map(r=>r.text).join(`
4
4
 
5
- `),files:s.flatMap(r=>r.files),state:s.map(r=>r.state).sort((r,a)=>Pt.indexOf(r)-Pt.indexOf(a))[0],reply:void 0,answers:s.map(r=>({eventId:r.eventId,state:r.state,reply:r.reply,replies:r.replies,text:r.text}))}]})}d(vs,"foldSubmits");const Ut=d(e=>(e.answers||[e]).filter(t=>t.eventId).map(t=>[t.eventId,t.state]),"stateEntries");function xs(e,t,n,s,r,a){const c=d((p,w)=>{const v=a.filter(x=>x.kind==="wave-triage"&&x.data?.[p]===w).pop(),_=r.filter(x=>x.topic===`${p}:${w}`&&(x.state==="open"||x.state==="answered")).length;return{running:!!(v&&!v.reply),questions:_}},"triageOf"),l=new Map(s.map(p=>[p.key,p])),u=d(p=>p.filter(w=>w.lane==="done"&&!St(w)).length,"merged"),m=n.map(p=>({l:p,cards:p.keys.map(w=>l.get(w)).filter(Boolean)})).map(p=>({...p,open:!p.l.finished_at&&p.cards.some(w=>w.lane!=="done")})).sort((p,w)=>Number(p.open)-Number(w.open));for(const{l:p,cards:w}of m)for(const v of w)v.wave={slug:p.slug,title:p.title};const f=m.filter(p=>p.open).map(({l:p,cards:w})=>({kind:"wave",slug:p.slug,title:p.title,goal:p.goal,keys:w.map(v=>v.key),next:Os(w),merged:u(w),total:w.length,triage:c("wave",p.slug)}));return e.fromWaves?[...f,...t.filter(p=>!p.finished).map(p=>({w:p,cards:s.filter(w=>w.file===p.slug&&w.kind!=="ask")})).filter(({cards:p})=>p.length).map(({w:p,cards:w})=>({kind:"file",slug:p.slug,title:p.title,goal:null,keys:w.map(v=>v.key),next:null,merged:u(w),total:w.length,triage:c("file",p.slug)}))]:f}d(xs,"waveBandsOf");function Os(e){const t=e.filter(a=>a.lane==="todo"),n=t.find(a=>a.ready&&a.buildable)||t[0];if(!n)return null;const s=n.ready&&n.buildable,r=s?"ready":n.held?"held":n.blockedBy.length?`waits on ${n.blockedBy.map(a=>a.ref).join(", ")}`:n.blockedUntil?`blocked until ${n.blockedUntil}`:n.action?"needs you":n.phase==="new"?"not ready":n.phase;return{key:n.key,ref:n.ref,ready:s,word:r}}d(Os,"nextOf");const Es=d(e=>e.items||e.phases.flat(),"waveItems");function $o(e){const{owner:t={},topicItems:n={},events:s=[],threads:r={},prs:a={},working:c={}}=e,l=e.now??Date.now(),u=Tt(s,t),m=new Set(s.filter(o=>o.kind==="ask-withdrawn").map(o=>o.data?.id)),f=new Map(s.filter(o=>o.kind==="ask"&&!m.has(o.id)).map(o=>[o.id,o])),p=d((o,g)=>new Map(s.filter(E=>E.kind===o).sort((E,$)=>String(E.ts).localeCompare(String($.ts))).map(E=>[E.data?.[g],E.ts])),"latest"),w=p("card-unbump","key"),v=new Map([...p("card-bump","key")].filter(([o,g])=>!(String(w.get(o)||"")>String(g)))),_=p("card-done","key"),x=p("card-merge","key"),P=e.autoMerge===!0,C=e.tickets,L=new Map(s.filter(o=>o.kind==="card-hold").sort((o,g)=>String(o.ts).localeCompare(String(g.ts))).map(o=>[o.data?.key,o])),T=new Map,W=new Map(e.files.flatMap(({slug:o,itemFile:g})=>g.items.map(E=>[`${o}/${E.id}`,{ref:nt(g,E,C),title:E.title}]))),h=e.askLinks||{},b=new Map;for(const[o,g]of Object.entries(h))f.has(o)&&b.set(g,[...b.get(g)||[],o]);const i=[],S=[],oe=new Map,ke=new Map,me=new Map,K=new Map,F=e.github?null:tn(e.remote);for(const{slug:o,itemFile:g,agents:E={}}of e.files){const $=e.github||g.repo||null;i.push({slug:o,title:g.title||o,status:g.status||null,internal:!!g.internal,finished:!1,reviewers:(g.reviewers||[]).map(y=>y.name)}),g.items.forEach((y,M)=>{const B=`${o}/${y.id}`,Ke=(b.get(B)||[]).filter(O=>O!==y.from_ask),le=[y.from_ask,...Ke].filter(O=>f.has(O)),Ce=new Set(le.map(O=>`ask:${O}`)),Oe=[...R(r,B)||[],...le.flatMap(O=>R(r,`ask:${O}`)||[])];y.from_ask&&T.set(y.from_ask,[...T.get(y.from_ask)||[],{key:B,ref:nt(g,y,C),became:!0}]);const ne=Ss(B,{lines:Oe,events:s,owner:t,working:c,fromAsk:y.from_ask||null,moved:Ke,cards:W,index:u});for(const O of ne)for(const[ie,Ge]of Ut(O))oe.set(ie,Ge);ke.set(B,Lt(ne)),S.push(Nn({slug:o,itemFile:g,it:y,order:M,repo:$,remote:F,base:e.branch||"main",prs:rn(y,$).map(O=>({...O,gh:R(a,ln(O))||null})),...(O=>({agents:O,builder:ts(O,R(r,B),l,e.moved?.[it(R(E,y.id))]??null,R(e.alive,B)??null,!!e.commandRunning?.[it(R(E,y.id))]),reachedPhase:es(O,R(r,B)),eta:O.map(ie=>ie.eta).filter(Boolean).sort().pop()||null}))(lt(R(E,y.id))),worktree:it(R(E,y.id))??y.worktree?.path??null,thread:Oe,events:[...ct(u,[B,...Ce].map(O=>u.byKey.get(O))),...le.map(O=>f.get(O))],working:ne.some(O=>Ut(O).some(([,ie])=>ie==="working")),said:ne.filter(O=>O.who==="love"&&(O.kind==="item-message"||O.kind==="owner-answer")),askedAt:(u.questions.get(`item:${B}`)||[]).filter(O=>O.asked_at).map(O=>O.asked_at),topicItems:n,prSlack:e.prSlack||{},boardReviewers:e.reviewers||[],now:l,bumpedAt:v.get(B),holdAsk:L.get(B),closedAt:_.get(B),mergeAt:x.get(B),autoMerge:P,skipDraft:e.skipDraft===!0,tickets:C}));const J=S[S.length-1];f.has(y.from_ask)&&(J.created=f.get(y.from_ask).ts),J.askMsg=ne.find(O=>O.kind==="ask"&&O.eventId===y.from_ask)||null,K.set(B,{parent:y.parent?Wt(o,y.parent):null,related:(y.related||[]).map(O=>Wt(o,O))}),J.lane==="done"&&me.set(B,J.closedAt||String(J.updatedAt||""))})}const ee=new Map(S.map(o=>[o.key,o])),I=new Map,G=e.try||{},ze=e.autoBuild===!0,U=["web","app"].includes(G.kind)?G.kind:e.files.some(({itemFile:o})=>o.items.some(g=>g.install?.url))?"app":"web";for(const o of S){if(o.kind!=="work"||o.lane==="done")continue;const g=R(G.cards,o.key)||{},E=g.head||o.pr?.headRefOid,$=U==="web"?g.sha:o.install?.sha,y=o.builder?.kind===ue.install?"running":g.state||(U==="app"&&o.install?"ready":null);o.try={kind:U,state:y,stale:!!($&&E&&!String(E).toLowerCase().startsWith(String($).toLowerCase())),url:U==="web"?null:o.install?.url||null,port:U==="web"&&y==="ready"&&g.https||null,sha:$||null,changes:g.ahead>0,script:g.script===!0,autoBuild:ze}}const N=G.main,we=N?.script&&N.sha?{slug:N.slug,branch:N.branch||"main",sha:N.sha.slice(0,7),at:N.at,kind:U,state:N.state||null,url:U==="web"?null:e.main?.install?.url||null,port:U==="web"&&(N.state==="ready"?N.https:N.serving?.https)||null,serving:U==="web"&&N.serving?{sha:N.serving.sha.slice(0,7),at:N.serving.at}:null,pull:G.pull?{running:G.pull.running===!0,error:G.pull.error||null}:null,script:pn(N.target)}:null,he=[],ye=[],Le=_e(s.filter(o=>o.kind==="owner-answer"),o=>o.data?.id),j=_e(s.filter(o=>o.kind==="prototype-request"),o=>o.data?.question),Re=_e(s.filter(o=>o.kind==="reask-request"),o=>o.data?.question),Je=_e(s.filter(o=>o.kind===mt),o=>o.data?.question),H=(t.items||[]).map(o=>as(o,Le.get(o.id)||[],j.get(o.id)||[],Re.get(o.id)||[],Je.get(o.id)||[])),X=new Map(H.map(o=>[o.id,o])),Te=_e(H,o=>o.topic);for(const o of f.values()){const g=`ask:${o.id}`,E=R(r,g)||[],$=T.get(o.id)?.[0].key||R(h,o.id);if(!$){E.some(B=>B.line==="ask-moved")||ye.push(o.id);continue}I.set(g,$);const y=E.filter(B=>B.line===fn).at(-1),M=ee.get($);if(y&&M){const B=y.title||String(u.edits.get(o.id)??o.data?.text??"").trim().split(`
6
- `)[0]||"Ask";he.push({key:M.key,ref:M.ref,text:B,at:String(y.ts)})}}for(const o of i){const g=S.filter(E=>E.file===o.slug);if(o.finished=On(g),o.finished)for(const E of g)E.lane==="done"&&(E.fold=yn(o.slug))}for(const o of S)o.wave=null;const be=new Set((t.topics||[]).map(o=>o.id)),Se=e.files.flatMap(({slug:o,itemFile:g})=>(g.waves||[]).map(E=>({...E,keys:Es(E).map($=>`${o}/${$}`)}))),ve=d(()=>cs([...t.topics||[],...S.filter(o=>!be.has(`item:${o.key}`)).map(o=>({id:`item:${o.key}`,card:o.key,title:`${o.ref}: ${o.title}`})),...Se.filter(o=>!be.has(`wave:${o.slug}`)).map(o=>({id:`wave:${o.slug}`,title:o.title,summary:"Wave triage."})),...(e.fromWaves?i:[]).filter(o=>!be.has(`file:${o.slug}`)).map(o=>({id:`file:${o.slug}`,title:o.title,summary:"Wave triage."}))],H,new Set(S.filter(pe).map(o=>`item:${o.key}`))),"topicsOf"),Pe=new Map(ve().map(o=>[o.id,o]));for(const o of S){const g=Pe.get(`item:${o.key}`);if(!g){o.questions=null,o.prototypes=null;continue}const E=g.questions.filter(M=>X.get(M)?.state!=="resolved"),$=g.questions.find(M=>X.get(M)?.state==="open")||E[0]||g.questions[0],y=g.questions.map(M=>X.get(M)).filter(M=>M?.state==="open");o.questions={topic:g.id,state:g.state,open:g.open,answered:g.answered,replied:g.replied,resolved:g.resolved,first:$,askedAt:y.map(M=>M.asked_at).filter(Boolean).sort(),fromAsks:y.length>0&&y.every(M=>M.ask)},o.prototypes=ds(g.questions.map(M=>X.get(M)))}const te=new Map(S.map(o=>[o.key,o])),Ue=new Map(Se.map(o=>[`wave:${o.slug}`,o.keys]));for(const o of S){const g=o.kind==="work"&&o.lane!=="done",E=new Set(o.deps.flatMap(y=>Ue.get(y)||[String(y).includes("/")?y:`${o.file}/${y}`]));o.blockedBy=g?[...E].map(y=>te.get(y)).filter(y=>y&&y.lane!=="done"&&!y.reopened).map(jt):[],o.blockedUntil=g?o.blockedUntil??null:null,o.blockReason=g?o.blockReason??null:null,o.blocked=o.blockedBy.length>0||!!o.blockedUntil,Xn(o,X,P),o.lane==="todo"&&o.kind==="work"&&!o.held&&Et(o.storedLane,o.agents)&&(o.lane="progress"),o.unpicked=o.kind==="work"&&o.lane==="todo"&&!!Kn(H,o.key),o.kind==="work"&&(o.phase=Ys(o)),o.unpicked&&!o.action&&(o.next=Gn),o.buildable=Wn(o);const $=o.kind==="work"&&o.lane==="todo";if(o.unsorted=$&&(!!o.fromAsk||o.unfiled)&&!o.filedHeld&&o.phase==="new",o.kind==="work"){const y=o.askMsg;delete o.askMsg,o.unsorted&&y&&(o.isNew=!0,o.ask={eventId:y.eventId,state:y.state,askedAt:y.ts,edited:!!y.edited,canEdit:!0,text:y.text,files:y.files,from:y.from||null})}o.ready=$&&o.phase==="ready"&&!o.blocked&&!o.recheckAt&&!o.action,o.staging=$&&o.phase==="staging",o.kind==="work"&&(o.hostHeld=!!e.hostBusy&&o.ready&&!!o.bumpedAt&&!o.held)}Bs(S,te,K);const je=new Map((t.items||[]).map(o=>[o.id,o.topic])),Y=d(o=>o.kind==="owner-answer"?je.has(o.data?.id)?/^item:(.+)$/.exec(je.get(o.data.id))?.[1]||null:"":o.kind==="ask"?`ask:${o.id}`:o.data?.key||(o.kind.startsWith("ask-")&&o.data?.id?`ask:${o.data.id}`:null),"ownCardOf"),z=d(o=>{const g=Y(o);return I.get(g)||g},"cardOf"),Me=d(o=>[_.get(o),me.get(o)].filter(Boolean).sort().pop()||"","closedAt"),Ie=d(o=>{const g=z(o);return g===null?!o.reply:!te.has(g)||!(Me(g)<String(R(c,o.id)))?!1:oe.has(o.id)?oe.get(o.id)==="working":!o.reply&&!I.has(Y(o))&&!(String(ke.get(g)||"")>String(o.ts))},"unanswered"),re=s.filter(o=>R(c,o.id)&&Ie(o)).map(o=>({id:o.id,kind:o.kind,key:z(o),data:o.data,since:R(c,o.id)}));for(const o of S)o.working=re.some(g=>g.key===o.key),o.kind==="work"&&o.lane==="progress"&&!o.builder&&!o.next&&o.waitsOn!=="checking"&&!o.working&&(o.next=$t),o.sortAt=_s[o.lane](o)||(o.lane==="review"?null:o.updatedAt)||null;for(const o of S){if(o.kind!=="work")continue;const g=(Te.get(`item:${o.key}`)||[]).filter($=>$.state==="answered").map($=>$.answers.at(-1).ts).sort().pop(),E=re.filter($=>$.key===o.key).map($=>String($.since)).sort()[0];o.orchestrator=!o.stalled&&(["progress","todo"].includes(o.lane)||o.waitsOn==="checking"||o.lane==="review"&&(o.stale||o.waitFacts.unblockedAt||o.waitFacts.replyAt))?no(o,o.waitFacts,{answeredAt:g,workingSince:E}):null,delete o.waitFacts}Ks(S,s,c,I),Gs(S,e.screening||{}),S.sort(gn);const Ze=xs(e,i,Se,S,H,s),A=ve(),We=nn({on:e.autoReview,incoming:e.incoming,records:e.reviewRecords,events:s,now:l,refs:new Map(S.filter(o=>o.kind==="work").map(o=>[o.key,o.ref]))}),ae=[...Ms(S,A,H),...sn(We)],D=new Map(ae.filter(o=>o.questions).map((o,g)=>[o.topic||`item:${o.key}`,g])),Fe=d(o=>D.get(o.id)??D.size,"rankOf");A.sort((o,g)=>Fe(o)-Fe(g));const qe=new Set(ae.filter(o=>o.questions&&o.progress).map(o=>`item:${o.key}`));for(const o of A)qe.has(o.id)&&(o.progress=!0);const xe=S.flatMap(o=>o.answered&&ke.get(o.key)?[{key:o.key,id:o.id,text:o.title,at:ke.get(o.key)}]:[]).sort((o,g)=>g.at.localeCompare(o.at));return he.sort((o,g)=>g.at.localeCompare(o.at)),$s({kind:U,main:we,remote:F&&{host:F.host,name:`${F.host}/${F.path}`},itemFiles:i,waveBands:Ze,items:S,moved:Object.fromEntries(I),answers:xe,merges:he,unfiled:ye,owner:H,ownerTopics:A,reviews:We,needs:ae,working:re.length,workingOn:re,checks:Rs(e,l)},e)}d($o,"buildBoard");function $s(e,{listen:t,prompts:n}={}){const s=[...qs(n),...e.needs];return{...e,needs:s,needsSummary:Cs(s),checks:{...e.checks,watcher:{listening:"running",asleep:"asleep",waking:"waking"}[t]||"stopped"}}}d($s,"withHub");const jt=d(e=>({key:e.key,ref:e.ref}),"linkOf"),Wt=d((e,t)=>String(t).includes("/")?String(t):`${e}/${t}`,"linkKey"),As=d((e,t)=>e.ref.localeCompare(t.ref,void 0,{numeric:!0}),"byRef");function Bs(e,t,n){const s=new Map,r=new Map,a=new Map,c=d((u,m,f)=>u.set(m,[...u.get(m)||[],f]),"add");for(const[u,m]of n){m.parent&&c(s,m.parent,u);for(const f of m.related)f!==u&&(c(r,u,f),c(r,f,u))}for(const u of e)for(const m of u.blockedBy||[])c(a,m.key,u.key);const l=d((u=[])=>[...new Set(u)].map(m=>t.get(m)).filter(Boolean).map(jt).sort(As),"cards");for(const u of e){const m=n.get(u.key)?.parent;u.parent=m?{key:m,ref:t.get(m)?.ref||m.slice(m.indexOf("/")+1)}:null,u.children=l(s.get(u.key)),u.related=l(r.get(u.key)),u.waitsOnIt=l(a.get(u.key))}}d(Bs,"linkCards");const _s={todo:d(e=>e.created,"todo"),progress:d(e=>e.progressSince,"progress"),review:d(e=>e.reviewSince,"review"),done:d(e=>e.closedAt,"done")},se=d((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural");function Rs({checked:e,watcher:t,replyAt:n,threads:s={},working:r={},files:a=[]},c){const l=Number(e?.every)||30,m=[n,t?.since,...Object.values(r),...Object.values(s).flat().filter(p=>(p.who||"claude")==="claude").map(p=>p.ts),...a.flatMap(p=>Object.values(p.agents||{}).flatMap(w=>Object.values(w||{})).map(w=>w?.done||w?.started))].filter(p=>typeof p=="string"&&!Number.isNaN(Date.parse(p))).reduce((p,w)=>p&&Date.parse(p)>Date.parse(w)?p:w,null),f=!!e?.idle;return{at:e?.at||null,every:f?null:l,idle:f,late:!f&&!!e?.at&&c-Date.parse(e.at)>2*l*6e4,claudeAt:m}}d(Rs,"checksOf");function Ms(e,t,n){const s=new Set(e.map(l=>l.questions?.topic).filter(Boolean)),r=d(l=>l.find(u=>n.find(m=>m.id===u)?.state==="open")||l[0],"firstOpen"),a=t.filter(l=>l.state!=="resolved"&&l.open>0&&!s.has(l.id)).map(l=>{const u=`questions.html#${r(l.questions)}`,m=/^(?:wave|file):(.+)$/.exec(l.id)?.[1]||null;return{kind:"Question",title:l.title,text:`${l.title} \xB7 ${se(l.open,"question")}`,url:u,topic:l.id,band:m,questions:{open:l.open,url:u},ready:null,since:n.filter(f=>f.topic===l.id&&f.state==="open").map(f=>f.asked_at).filter(Boolean).sort()[0]||null}}),c=e.map(l=>{const u=l.questions&&l.questions.state!=="resolved"&&l.questions.open>0?{open:l.questions.open,url:`questions.html#${l.questions.first}`}:null,m=l.waitsOn==="ready"?l.pr.url:null,f=!u&&!m&&l.action?{label:l.action.label,url:l.action.url}:null;if(!u&&!m&&!f)return null;const p=`${l.ref}: ${l.title}`,w=[p,u&&se(u.open,"question"),m&&"Ready on GitHub",f?.label].filter(Boolean).join(" \xB7 ");return{kind:u?"Question":m?"Tap Ready":"Action needed",title:p,text:w,url:`#selectedCard=${encodeURIComponent(l.key)}`,key:l.key,questions:u,ready:m,action:f,since:l.created||null,progress:l.lane==="progress"}}).filter(Boolean);return[...a,...c].sort(Is)}d(Ms,"needsOf");const Is=d((e,t)=>!!t.progress-!!e.progress||(e.since&&t.since?e.since.localeCompare(t.since):!!t.since-!!e.since),"oldestFirst");function qs(e=[]){return e.map(t=>{const n=t.questions?.length?`Question: ${t.questions.map(s=>s.question).join(" \xB7 ")}`:`${t.tool}: ${t.detail||t.action}`;return{kind:"Prompt",title:n,text:n,url:"",prompt:t}})}d(qs,"promptLines");function Cs(e){const t=e.filter(a=>a.prompt).length,n=e.reduce((a,c)=>a+(c.questions?.open||0),0),s=e.filter(a=>a.ready).length,r=e.filter(a=>a.review).length;return[t&&se(t,"prompt"),n&&se(n,"question"),s&&`${se(s,"draft")} waiting on Ready`,r&&`${se(r,"review")} held`].filter(Boolean).join(" \xB7 ")}d(Cs,"needsSummary");function Ao(e){const t=d((...n)=>e.items.filter(s=>n.includes(s.lane)).length,"count");return{items:e.needs.map(({kind:n,text:s,url:r})=>({kind:n,text:s,url:r})),working:e.working,summary:e.needsSummary,lanes:{review:t("review"),progress:t("progress"),todo:t("todo")},building:e.items.some(n=>(n.agents||[]).some(s=>!s.done))}}d(Ao,"needsAnswer");const Ns=d(e=>e.buildable&&e.phase==="ready"&&!e.held&&!e.blocked&&!e.recheckAt,"pullableCard"),Ds=10;function Ls(e,{cap:t=Ds,pulled:n=[],hold:s=[],taken:r=0}={}){const a=e.filter(h=>!pe(h)),c=d((h,b)=>h.started&&!h.done&&Q(h)&&!(h.kind===$e&&!h.writes)&&!h.pause?.paused&&!(h.waits&&b.some(i=>i.name===h.waits&&!i.done)),"counts"),l=a.filter(h=>!h.stalled).reduce((h,b)=>h+(b.agents||[]).filter((i,S,oe)=>c(i,oe)).length,0),u=a.filter(h=>Ns(h)&&!h.working).map(h=>h.key),m=a.filter(h=>n.includes(h.key)&&(u.includes(h.key)||h.buildable&&h.working)).map(h=>h.key),f=a.flatMap(h=>(h.agents||[]).filter(b=>b.kind===$e&&!b.started&&!b.done).map(b=>({key:h.key,name:b.name,writes:b.writes}))),p=Math.max(0,t-l-m.length-r),w=f.filter(h=>h.writes),v=[...f.filter(h=>!h.writes),...w.slice(0,p)].map(({key:h,name:b})=>({key:h,name:b})),_=Math.max(0,p-w.length),x=new Set(a.filter(h=>h.bumpedAt).map(h=>h.key)),P=u.filter(h=>!m.includes(h)&&!s.includes(h)),C=P.filter(h=>x.has(h)),L=[...C,...P.filter(h=>!x.has(h)).slice(0,Math.max(0,_-C.length))],T=C.slice(_),W=Ts(a,c).slice(0,T.length).map((h,b)=>({key:h,by:T[b]}));return{idle:!l&&!a.some(h=>h.waitsOn==="checking"),pullable:u,waiting:m,pulls:L,helpers:v,bumpOuts:W,pastCap:T,free:p}}d(Ls,"pullOf");function Ts(e,t){const n=d(s=>{const r=s.agents||[],a=r.filter(u=>t(u,r)),[c]=a;return s.lane==="progress"&&!s.bumpedAt&&!s.stalled&&s.waitsOn!=="checking"&&s.builder?.phase!=="landing"&&!(s.prs||[]).length&&!s.pushed&&!s.mergeReady&&a.length===1&&c.kind!==$e&&c.pid&&c.label!==He&&!c.pause&&!r.some(u=>u.kind===$e&&u.started&&!u.done)?String(c.started):null},"newest");return e.map(s=>({key:s.key,at:n(s)})).filter(s=>s.at).sort((s,r)=>r.at.localeCompare(s.at)).map(s=>s.key)}d(Ts,"bumpOutsOf");function Bo(e,t,n){return e.filter(s=>s.kind==="work"&&!pe(s)&&s.waitsOn!=="checking"&&!(s.agents||[]).some(r=>r.started&&!r.done)).flatMap(s=>{const r=(s.prs||[]).find(c=>c.state==="OPEN"&&c.mergeable==="CONFLICTING"&&c.repo===s.repo&&c.headRefOid),a=r&&`${r.headRefOid}@${n}`;return r&&R(t,s.key)!==a?[{key:s.key,pr:r.number,branch:r.headRefName,conflict:a}]:[]})}d(Bo,"rebasesDue");const Ps=3;function _o(e,{cap:t=Ps}={}){const n=e.filter(l=>!pe(l)),s=n.filter(l=>(l.agents||[]).some(u=>Z(u)&&u.started&&!u.done)).length,r=n.filter(l=>l.buildable&&!["ready","staging"].includes(l.phase)&&!l.unsorted&&!l.held&&!l.working&&!l.grilling&&!l.prototyping&&!l.questions&&!(l.agents||[]).some(u=>Z(u)&&u.kind!==fe)),a=[...r.filter(l=>!l.blocked),...r.filter(l=>l.blocked)],c=a.filter(l=>l.bumpedAt);return[...c,...a.filter(l=>!l.bumpedAt).slice(0,Math.max(0,t-s-c.length))].map(l=>l.key)}d(_o,"arrivalsOf");function Ro(e){return e.filter(t=>t.kind==="work"&&t.lane==="todo"&&t.roundAt&&["grilling","prototyping"].includes(t.phase)&&!(t.agents||[]).some(n=>Z(n)&&n.kind!==fe&&n.started&&(String(n.started)>=String(t.roundAt)||!n.done))).map(t=>({key:t.key,kind:t.phase==="grilling"?"grill":"prototype"}))}d(Ro,"roundsDue");const Us=d(e=>`${fe}-${e.id}`,"visualAgent");function Mo(e,t){const n=[];for(const s of e){const r=s.agents||[];if(r.some(l=>l.kind===fe&&l.started&&!l.done))continue;const a=new Set(r.map(l=>l.name)),c=t.find(l=>l.kind==="visual-request"&&l.data?.key===s.key&&!a.has(Us(l)));c&&n.push({key:s.key,request:c})}return n}d(Mo,"visualsDue");const js=d((e,t)=>e.kind==="ask"?t.get(`ask:${e.id}`)??null:e.kind==="card-added"?e.data?.key??null:null,"intakeKeyOf");function Ws(e,t,n){const s=e.get(n);return s?t.kind==="ask"?!!s.isNew:s.unfiled:!1}d(Ws,"unsorted");const Fs={ask:d((e,t)=>`Sort the new task: item notes, then item set ${e} --phase grilling or prototyping (ready, with --size, for a Quick build); merge it into a card with item relate-ask ${t.id} <card> --summary; or answer it with reply ${e}`,"ask"),"card-added":d(()=>"Link and file the card an agent added: item notes, then item set --relate and --phase","card-added")};function Ks(e,t,n,s){const r=new Map(e.map(c=>[c.key,c])),a=new Set;for(const c of t){const l=js(c,s);!l||a.has(l)||!Ws(r,c,l)||(a.add(l),r.get(l).orchestrator={kind:"intake",since:String(c.ts),picked:R(n,c.id)||null,next:Fs[c.kind](l,c)})}}d(Ks,"intakeWaits");function Gs(e,t){for(const n of e){const s=R(t,n.key);s&&(n.orchestrator={kind:"screen",since:s.since,picked:null,next:`Screen the grill's questions ${s.ids.join(", ")}: question settle <id> --note for each the board already answers, then question publish ${n.key}; left 15 minutes unscreened, they reach the owner as they are`})}}d(Gs,"screenWaits");function Qs(e){return e.filter(t=>t.lane==="todo"||t.lane==="review"&&t.stale).map(t=>JSON.stringify([t.key,t.title,t.deps||[]])).sort().join(`
7
- `)}d(Qs,"todoOf");function Io(e){const t=e.filter(s=>s.kind==="work"&&s.lane!=="done"&&s.questions?.open>0),n=t.map(s=>JSON.stringify([s.key,s.questions.open,s.questions.askedAt||[]])).sort().join(`
5
+ `),files:s.flatMap(r=>r.files),state:s.map(r=>r.state).sort((r,a)=>Pt.indexOf(r)-Pt.indexOf(a))[0],reply:void 0,answers:s.map(r=>({eventId:r.eventId,state:r.state,reply:r.reply,replies:r.replies,text:r.text}))}]})}d(xs,"foldSubmits");const Ut=d(e=>(e.answers||[e]).filter(t=>t.eventId).map(t=>[t.eventId,t.state]),"stateEntries");function Os(e,t,n,s,r,a){const c=d((p,w)=>{const v=a.filter(x=>x.kind==="wave-triage"&&x.data?.[p]===w).pop(),_=r.filter(x=>x.topic===`${p}:${w}`&&(x.state==="open"||x.state==="answered")).length;return{running:!!(v&&!v.reply),questions:_}},"triageOf"),l=new Map(s.map(p=>[p.key,p])),u=d(p=>p.filter(w=>w.lane==="done"&&!St(w)).length,"merged"),m=n.map(p=>({l:p,cards:p.keys.map(w=>l.get(w)).filter(Boolean)})).map(p=>({...p,open:!p.l.finished_at&&p.cards.some(w=>w.lane!=="done")})).sort((p,w)=>Number(p.open)-Number(w.open));for(const{l:p,cards:w}of m)for(const v of w)v.wave={slug:p.slug,title:p.title};const f=m.filter(p=>p.open).map(({l:p,cards:w})=>({kind:"wave",slug:p.slug,title:p.title,goal:p.goal,keys:w.map(v=>v.key),next:Es(w),merged:u(w),total:w.length,triage:c("wave",p.slug)}));return e.fromWaves?[...f,...t.filter(p=>!p.finished).map(p=>({w:p,cards:s.filter(w=>w.file===p.slug&&w.kind!=="ask")})).filter(({cards:p})=>p.length).map(({w:p,cards:w})=>({kind:"file",slug:p.slug,title:p.title,goal:null,keys:w.map(v=>v.key),next:null,merged:u(w),total:w.length,triage:c("file",p.slug)}))]:f}d(Os,"waveBandsOf");function Es(e){const t=e.filter(a=>a.lane==="todo"),n=t.find(a=>a.ready&&a.buildable)||t[0];if(!n)return null;const s=n.ready&&n.buildable,r=s?"ready":n.held?"held":n.blockedBy.length?`waits on ${n.blockedBy.map(a=>a.ref).join(", ")}`:n.blockedUntil?`blocked until ${n.blockedUntil}`:n.action?"needs you":n.phase==="new"?"not ready":n.phase;return{key:n.key,ref:n.ref,ready:s,word:r}}d(Es,"nextOf");const $s=d(e=>e.items||e.phases.flat(),"waveItems");function Ao(e){const{owner:t={},topicItems:n={},events:s=[],threads:r={},prs:a={},working:c={}}=e,l=e.now??Date.now(),u=Tt(s,t),m=new Set(s.filter(o=>o.kind==="ask-withdrawn").map(o=>o.data?.id)),f=new Map(s.filter(o=>o.kind==="ask"&&!m.has(o.id)).map(o=>[o.id,o])),p=d((o,g)=>new Map(s.filter(E=>E.kind===o).sort((E,$)=>String(E.ts).localeCompare(String($.ts))).map(E=>[E.data?.[g],E.ts])),"latest"),w=p("card-unbump","key"),v=new Map([...p("card-bump","key")].filter(([o,g])=>!(String(w.get(o)||"")>String(g)))),_=p("card-done","key"),x=p("card-merge","key"),P=e.autoMerge===!0,C=e.tickets,L=new Map(s.filter(o=>o.kind==="card-hold").sort((o,g)=>String(o.ts).localeCompare(String(g.ts))).map(o=>[o.data?.key,o])),T=new Map,W=new Map(e.files.flatMap(({slug:o,itemFile:g})=>g.items.map(E=>[`${o}/${E.id}`,{ref:nt(g,E,C),title:E.title}]))),h=e.askLinks||{},b=new Map;for(const[o,g]of Object.entries(h))f.has(o)&&b.set(g,[...b.get(g)||[],o]);const i=[],S=[],oe=new Map,me=new Map,we=new Map,K=new Map,F=e.github?null:tn(e.remote);for(const{slug:o,itemFile:g,agents:E={}}of e.files){const $=e.github||g.repo||null;i.push({slug:o,title:g.title||o,status:g.status||null,internal:!!g.internal,finished:!1,reviewers:(g.reviewers||[]).map(y=>y.name)}),g.items.forEach((y,M)=>{const B=`${o}/${y.id}`,Ke=(b.get(B)||[]).filter(O=>O!==y.from_ask),le=[y.from_ask,...Ke].filter(O=>f.has(O)),Ce=new Set(le.map(O=>`ask:${O}`)),Ee=[...R(r,B)||[],...le.flatMap(O=>R(r,`ask:${O}`)||[])];y.from_ask&&T.set(y.from_ask,[...T.get(y.from_ask)||[],{key:B,ref:nt(g,y,C),became:!0}]);const ne=vs(B,{lines:Ee,events:s,owner:t,working:c,fromAsk:y.from_ask||null,moved:Ke,cards:W,index:u});for(const O of ne)for(const[ie,Ge]of Ut(O))oe.set(ie,Ge);me.set(B,Lt(ne)),S.push(Dn({slug:o,itemFile:g,it:y,order:M,repo:$,remote:F,base:e.branch||"main",prs:rn(y,$).map(O=>({...O,gh:R(a,ln(O))||null})),...(O=>({agents:O,builder:ts(O,R(r,B),l,e.moved?.[it(R(E,y.id))]??null,R(e.alive,B)??null,!!e.commandRunning?.[it(R(E,y.id))]),reachedPhase:es(O,R(r,B)),eta:O.map(ie=>ie.eta).filter(Boolean).sort().pop()||null}))(lt(R(E,y.id))),worktree:it(R(E,y.id))??y.worktree?.path??null,thread:Ee,events:[...ct(u,[B,...Ce].map(O=>u.byKey.get(O))),...le.map(O=>f.get(O))],working:ne.some(O=>Ut(O).some(([,ie])=>ie==="working")),said:ne.filter(O=>O.who==="love"&&(O.kind==="item-message"||O.kind==="owner-answer")),askedAt:(u.questions.get(`item:${B}`)||[]).filter(O=>O.asked_at).map(O=>O.asked_at),topicItems:n,prSlack:e.prSlack||{},boardReviewers:e.reviewers||[],now:l,bumpedAt:v.get(B),holdAsk:L.get(B),closedAt:_.get(B),mergeAt:x.get(B),autoMerge:P,skipDraft:e.skipDraft===!0,tickets:C}));const J=S[S.length-1];f.has(y.from_ask)&&(J.created=f.get(y.from_ask).ts),J.askMsg=ne.find(O=>O.kind==="ask"&&O.eventId===y.from_ask)||null,K.set(B,{parent:y.parent?Wt(o,y.parent):null,related:(y.related||[]).map(O=>Wt(o,O))}),J.lane==="done"&&we.set(B,J.closedAt||String(J.updatedAt||""))})}const ee=new Map(S.map(o=>[o.key,o])),I=new Map,G=e.try||{},ze=e.autoBuild===!0,U=["web","app"].includes(G.kind)?G.kind:e.files.some(({itemFile:o})=>o.items.some(g=>g.install?.url))?"app":"web";for(const o of S){if(o.kind!=="work"||o.lane==="done")continue;const g=R(G.cards,o.key)||{},E=g.head||o.pr?.headRefOid,$=U==="web"?g.sha:o.install?.sha,y=o.builder?.kind===ue.install?"running":g.state||(U==="app"&&o.install?"ready":null);o.try={kind:U,state:y,stale:!!($&&E&&!String(E).toLowerCase().startsWith(String($).toLowerCase())),url:U==="web"?null:o.install?.url||null,port:U==="web"&&y==="ready"&&g.https||null,sha:$||null,changes:g.ahead>0,script:g.script===!0,autoBuild:ze}}const D=G.main,he=D?.script&&D.sha?{slug:D.slug,branch:D.branch||"main",sha:D.sha.slice(0,7),at:D.at,kind:U,state:D.state||null,url:U==="web"?null:e.main?.install?.url||null,port:U==="web"&&(D.state==="ready"?D.https:D.serving?.https)||null,serving:U==="web"&&D.serving?{sha:D.serving.sha.slice(0,7),at:D.serving.at}:null,pull:G.pull?{running:G.pull.running===!0,error:G.pull.error||null}:null,script:pn(D.target)}:null,ye=[],be=[],Le=_e(s.filter(o=>o.kind==="owner-answer"),o=>o.data?.id),j=_e(s.filter(o=>o.kind==="prototype-request"),o=>o.data?.question),Re=_e(s.filter(o=>o.kind==="reask-request"),o=>o.data?.question),Je=_e(s.filter(o=>o.kind===mt),o=>o.data?.question),H=(t.items||[]).map(o=>ls(o,Le.get(o.id)||[],j.get(o.id)||[],Re.get(o.id)||[],Je.get(o.id)||[])),X=new Map(H.map(o=>[o.id,o])),Te=_e(H,o=>o.topic);for(const o of f.values()){const g=`ask:${o.id}`,E=R(r,g)||[],$=T.get(o.id)?.[0].key||R(h,o.id);if(!$){E.some(B=>B.line==="ask-moved")||be.push(o.id);continue}I.set(g,$);const y=E.filter(B=>B.line===fn).at(-1),M=ee.get($);if(y&&M){const B=y.title||String(u.edits.get(o.id)??o.data?.text??"").trim().split(`
6
+ `)[0]||"Ask";ye.push({key:M.key,ref:M.ref,text:B,at:String(y.ts)})}}for(const o of i){const g=S.filter(E=>E.file===o.slug);if(o.finished=On(g),o.finished)for(const E of g)E.lane==="done"&&(E.fold=yn(o.slug))}for(const o of S)o.wave=null;const Se=new Set((t.topics||[]).map(o=>o.id)),ve=e.files.flatMap(({slug:o,itemFile:g})=>(g.waves||[]).map(E=>({...E,keys:$s(E).map($=>`${o}/${$}`)}))),xe=d(()=>us([...t.topics||[],...S.filter(o=>!Se.has(`item:${o.key}`)).map(o=>({id:`item:${o.key}`,card:o.key,title:`${o.ref}: ${o.title}`})),...ve.filter(o=>!Se.has(`wave:${o.slug}`)).map(o=>({id:`wave:${o.slug}`,title:o.title,summary:"Wave triage."})),...(e.fromWaves?i:[]).filter(o=>!Se.has(`file:${o.slug}`)).map(o=>({id:`file:${o.slug}`,title:o.title,summary:"Wave triage."}))],H,new Set(S.filter(pe).map(o=>`item:${o.key}`))),"topicsOf"),Pe=new Map(xe().map(o=>[o.id,o]));for(const o of S){const g=Pe.get(`item:${o.key}`);if(!g){o.questions=null,o.prototypes=null;continue}const E=g.questions.filter(M=>X.get(M)?.state!=="resolved"),$=g.questions.find(M=>X.get(M)?.state==="open")||E[0]||g.questions[0],y=g.questions.map(M=>X.get(M)).filter(M=>M?.state==="open");o.questions={topic:g.id,state:g.state,open:g.open,answered:g.answered,replied:g.replied,resolved:g.resolved,first:$,askedAt:y.map(M=>M.asked_at).filter(Boolean).sort(),fromAsks:y.length>0&&y.every(M=>M.ask)},o.prototypes=cs(g.questions.map(M=>X.get(M)))}const te=new Map(S.map(o=>[o.key,o])),Ue=new Map(ve.map(o=>[`wave:${o.slug}`,o.keys]));for(const o of S){const g=o.kind==="work"&&o.lane!=="done",E=new Set(o.deps.flatMap(y=>Ue.get(y)||[String(y).includes("/")?y:`${o.file}/${y}`]));o.blockedBy=g?[...E].map(y=>te.get(y)).filter(y=>y&&y.lane!=="done"&&!y.reopened).map(jt):[],o.blockedUntil=g?o.blockedUntil??null:null,o.blockReason=g?o.blockReason??null:null,o.blocked=o.blockedBy.length>0||!!o.blockedUntil,Xn(o,X,P),o.lane==="todo"&&o.kind==="work"&&!o.held&&Et(o.storedLane,o.agents)&&(o.lane="progress"),o.unpicked=o.kind==="work"&&o.lane==="todo"&&!!Kn(H,o.key),o.kind==="work"&&(o.phase=zs(o)),o.unpicked&&!o.action&&(o.next=Gn),o.buildable=Wn(o);const $=o.kind==="work"&&o.lane==="todo";if(o.unsorted=$&&(!!o.fromAsk||o.unfiled)&&!o.filedHeld&&o.phase==="new",o.kind==="work"){const y=o.askMsg;delete o.askMsg,o.unsorted&&y&&(o.isNew=!0,o.ask={eventId:y.eventId,state:y.state,askedAt:y.ts,edited:!!y.edited,canEdit:!0,text:y.text,files:y.files,from:y.from||null})}o.ready=$&&o.phase==="ready"&&!o.blocked&&!o.recheckAt&&!o.action,o.staging=$&&o.phase==="staging",o.kind==="work"&&(o.hostHeld=!!e.hostBusy&&o.ready&&!!o.bumpedAt&&!o.held)}_s(S,te,K);const je=new Map((t.items||[]).map(o=>[o.id,o.topic])),Y=d(o=>o.kind==="owner-answer"?je.has(o.data?.id)?/^item:(.+)$/.exec(je.get(o.data.id))?.[1]||null:"":o.kind==="ask"?`ask:${o.id}`:o.data?.key||(o.kind.startsWith("ask-")&&o.data?.id?`ask:${o.data.id}`:null),"ownCardOf"),z=d(o=>{const g=Y(o);return I.get(g)||g},"cardOf"),Me=d(o=>[_.get(o),we.get(o)].filter(Boolean).sort().pop()||"","closedAt"),Ie=d(o=>{const g=z(o);return g===null?!o.reply:!te.has(g)||!(Me(g)<String(R(c,o.id)))?!1:oe.has(o.id)?oe.get(o.id)==="working":!o.reply&&!I.has(Y(o))&&!(String(me.get(g)||"")>String(o.ts))},"unanswered"),re=s.filter(o=>R(c,o.id)&&Ie(o)).map(o=>({id:o.id,kind:o.kind,key:z(o),data:o.data,since:R(c,o.id)}));for(const o of S)o.working=re.some(g=>g.key===o.key),o.kind==="work"&&o.lane==="progress"&&!o.builder&&!o.next&&o.waitsOn!=="checking"&&!o.working&&(o.next=$t),o.sortAt=Rs[o.lane](o)||(o.lane==="review"?null:o.updatedAt)||null;for(const o of S){if(o.kind!=="work")continue;const g=(Te.get(`item:${o.key}`)||[]).filter($=>$.state==="answered").map($=>$.answers.at(-1).ts).sort().pop(),E=re.filter($=>$.key===o.key).map($=>String($.since)).sort()[0];o.orchestrator=!o.stalled&&(["progress","todo"].includes(o.lane)||o.waitsOn==="checking"||o.lane==="review"&&(o.stale||o.waitFacts.unblockedAt||o.waitFacts.replyAt))?so(o,o.waitFacts,{answeredAt:g,workingSince:E}):null,delete o.waitFacts}Gs(S,s,c,I),Qs(S,e.screening||{}),S.sort(gn);const Ze=Os(e,i,ve,S,H,s),A=xe(),We=nn({on:e.autoReview,incoming:e.incoming,records:e.reviewRecords,events:s,now:l,refs:new Map(S.filter(o=>o.kind==="work").map(o=>[o.key,o.ref]))}),ae=[...Is(S,A,H),...sn(We)],N=new Map(ae.filter(o=>o.questions).map((o,g)=>[o.topic||`item:${o.key}`,g])),Fe=d(o=>N.get(o.id)??N.size,"rankOf");A.sort((o,g)=>Fe(o)-Fe(g));const qe=new Set(ae.filter(o=>o.questions&&o.progress).map(o=>`item:${o.key}`));for(const o of A)qe.has(o.id)&&(o.progress=!0);const Oe=S.flatMap(o=>o.answered&&me.get(o.key)?[{key:o.key,id:o.id,text:o.title,at:me.get(o.key)}]:[]).sort((o,g)=>g.at.localeCompare(o.at));return ye.sort((o,g)=>g.at.localeCompare(o.at)),As({kind:U,main:he,remote:F&&{host:F.host,name:`${F.host}/${F.path}`},itemFiles:i,waveBands:Ze,items:S,moved:Object.fromEntries(I),answers:Oe,merges:ye,unfiled:be,owner:H,ownerTopics:A,reviews:We,needs:ae,working:re.length,workingOn:re,checks:Ms(e,l)},e)}d(Ao,"buildBoard");function As(e,{listen:t,prompts:n}={}){const s=[...Cs(n),...e.needs];return{...e,needs:s,needsSummary:Ds(s),checks:{...e.checks,watcher:{listening:"running",asleep:"asleep",waking:"waking"}[t]||"stopped"}}}d(As,"withHub");const jt=d(e=>({key:e.key,ref:e.ref}),"linkOf"),Wt=d((e,t)=>String(t).includes("/")?String(t):`${e}/${t}`,"linkKey"),Bs=d((e,t)=>e.ref.localeCompare(t.ref,void 0,{numeric:!0}),"byRef");function _s(e,t,n){const s=new Map,r=new Map,a=new Map,c=d((u,m,f)=>u.set(m,[...u.get(m)||[],f]),"add");for(const[u,m]of n){m.parent&&c(s,m.parent,u);for(const f of m.related)f!==u&&(c(r,u,f),c(r,f,u))}for(const u of e)for(const m of u.blockedBy||[])c(a,m.key,u.key);const l=d((u=[])=>[...new Set(u)].map(m=>t.get(m)).filter(Boolean).map(jt).sort(Bs),"cards");for(const u of e){const m=n.get(u.key)?.parent;u.parent=m?{key:m,ref:t.get(m)?.ref||m.slice(m.indexOf("/")+1)}:null,u.children=l(s.get(u.key)),u.related=l(r.get(u.key)),u.waitsOnIt=l(a.get(u.key))}}d(_s,"linkCards");const Rs={todo:d(e=>e.created,"todo"),progress:d(e=>e.progressSince,"progress"),review:d(e=>e.reviewSince,"review"),done:d(e=>e.closedAt,"done")},se=d((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural");function Ms({checked:e,watcher:t,replyAt:n,threads:s={},working:r={},files:a=[]},c){const l=Number(e?.every)||30,m=[n,t?.since,...Object.values(r),...Object.values(s).flat().filter(p=>(p.who||"claude")==="claude").map(p=>p.ts),...a.flatMap(p=>Object.values(p.agents||{}).flatMap(w=>Object.values(w||{})).map(w=>w?.done||w?.started))].filter(p=>typeof p=="string"&&!Number.isNaN(Date.parse(p))).reduce((p,w)=>p&&Date.parse(p)>Date.parse(w)?p:w,null),f=!!e?.idle;return{at:e?.at||null,every:f?null:l,idle:f,late:!f&&!!e?.at&&c-Date.parse(e.at)>2*l*6e4,claudeAt:m}}d(Ms,"checksOf");function Is(e,t,n){const s=new Set(e.map(l=>l.questions?.topic).filter(Boolean)),r=d(l=>l.find(u=>n.find(m=>m.id===u)?.state==="open")||l[0],"firstOpen"),a=t.filter(l=>l.state!=="resolved"&&l.open>0&&!s.has(l.id)).map(l=>{const u=`questions.html#${r(l.questions)}`,m=/^(?:wave|file):(.+)$/.exec(l.id)?.[1]||null;return{kind:"Question",title:l.title,text:`${l.title} \xB7 ${se(l.open,"question")}`,url:u,topic:l.id,band:m,questions:{open:l.open,url:u},ready:null,since:n.filter(f=>f.topic===l.id&&f.state==="open").map(f=>f.asked_at).filter(Boolean).sort()[0]||null}}),c=e.map(l=>{const u=l.questions&&l.questions.state!=="resolved"&&l.questions.open>0?{open:l.questions.open,url:`questions.html#${l.questions.first}`}:null,m=l.waitsOn==="ready"?l.pr.url:null,f=!u&&!m&&l.action?{label:l.action.label,url:l.action.url}:null;if(!u&&!m&&!f)return null;const p=`${l.ref}: ${l.title}`,w=[p,u&&se(u.open,"question"),m&&"Ready on GitHub",f?.label].filter(Boolean).join(" \xB7 ");return{kind:u?"Question":m?"Tap Ready":"Action needed",title:p,text:w,url:`#selectedCard=${encodeURIComponent(l.key)}`,key:l.key,questions:u,ready:m,action:f,since:l.created||null,progress:l.lane==="progress"}}).filter(Boolean);return[...a,...c].sort(qs)}d(Is,"needsOf");const qs=d((e,t)=>!!t.progress-!!e.progress||(e.since&&t.since?e.since.localeCompare(t.since):!!t.since-!!e.since),"oldestFirst");function Cs(e=[]){return e.map(t=>{const n=t.questions?.length?`Question: ${t.questions.map(s=>s.question).join(" \xB7 ")}`:`${t.tool}: ${t.detail||t.action}`;return{kind:"Prompt",title:n,text:n,url:"",prompt:t}})}d(Cs,"promptLines");function Ds(e){const t=e.filter(a=>a.prompt).length,n=e.reduce((a,c)=>a+(c.questions?.open||0),0),s=e.filter(a=>a.ready).length,r=e.filter(a=>a.review).length;return[t&&se(t,"prompt"),n&&se(n,"question"),s&&`${se(s,"draft")} waiting on Ready`,r&&`${se(r,"review")} held`].filter(Boolean).join(" \xB7 ")}d(Ds,"needsSummary");function Bo(e){const t=d((...n)=>e.items.filter(s=>n.includes(s.lane)).length,"count");return{items:e.needs.map(({kind:n,text:s,url:r})=>({kind:n,text:s,url:r})),working:e.working,summary:e.needsSummary,lanes:{review:t("review"),progress:t("progress"),todo:t("todo")},building:e.items.some(n=>(n.agents||[]).some(s=>!s.done))}}d(Bo,"needsAnswer");const Ns=d(e=>e.buildable&&e.phase==="ready"&&!e.held&&!e.blocked&&!e.recheckAt,"pullableCard"),Ls=10;function Ts(e,{cap:t=Ls,pulled:n=[],hold:s=[],taken:r=0}={}){const a=e.filter(h=>!pe(h)),c=d((h,b)=>h.started&&!h.done&&Q(h)&&!(h.kind===ge&&!h.writes)&&!h.pause?.paused&&!(h.waits&&b.some(i=>i.name===h.waits&&!i.done)),"counts"),l=a.filter(h=>!h.stalled).reduce((h,b)=>h+(b.agents||[]).filter((i,S,oe)=>c(i,oe)).length,0),u=a.filter(h=>Ns(h)&&!h.working).map(h=>h.key),m=a.filter(h=>n.includes(h.key)&&(u.includes(h.key)||h.buildable&&h.working)).map(h=>h.key),f=a.flatMap(h=>(h.agents||[]).filter(b=>b.kind===ge&&!b.started&&!b.done).map(b=>({key:h.key,name:b.name,writes:b.writes}))),p=Math.max(0,t-l-m.length-r),w=f.filter(h=>h.writes),v=[...f.filter(h=>!h.writes),...w.slice(0,p)].map(({key:h,name:b})=>({key:h,name:b})),_=Math.max(0,p-w.length),x=new Set(a.filter(h=>h.bumpedAt).map(h=>h.key)),P=u.filter(h=>!m.includes(h)&&!s.includes(h)),C=P.filter(h=>x.has(h)),L=[...C,...P.filter(h=>!x.has(h)).slice(0,Math.max(0,_-C.length))],T=C.slice(_),W=Ps(a,c).slice(0,T.length).map((h,b)=>({key:h,by:T[b]}));return{idle:!l&&!a.some(h=>h.waitsOn==="checking"),pullable:u,waiting:m,pulls:L,helpers:v,bumpOuts:W,pastCap:T,free:p}}d(Ts,"pullOf");function Ps(e,t){const n=d(s=>{const r=s.agents||[],a=r.filter(u=>t(u,r)),[c]=a;return s.lane==="progress"&&!s.bumpedAt&&!s.stalled&&s.waitsOn!=="checking"&&s.builder?.phase!=="landing"&&!(s.prs||[]).length&&!s.pushed&&!s.mergeReady&&a.length===1&&c.kind!==ge&&c.pid&&c.label!==He&&!c.pause&&!r.some(u=>u.kind===ge&&u.started&&!u.done)?String(c.started):null},"newest");return e.map(s=>({key:s.key,at:n(s)})).filter(s=>s.at).sort((s,r)=>r.at.localeCompare(s.at)).map(s=>s.key)}d(Ps,"bumpOutsOf");function _o(e,t,n){return e.filter(s=>s.kind==="work"&&!pe(s)&&s.waitsOn!=="checking"&&!(s.agents||[]).some(r=>r.started&&!r.done)).flatMap(s=>{const r=(s.prs||[]).find(c=>c.state==="OPEN"&&c.mergeable==="CONFLICTING"&&c.repo===s.repo&&c.headRefOid),a=r&&`${r.headRefOid}@${n}`;return r&&R(t,s.key)!==a?[{key:s.key,pr:r.number,branch:r.headRefName,conflict:a}]:[]})}d(_o,"rebasesDue");const Us=3;function Ro(e,{cap:t=Us}={}){const n=e.filter(l=>!pe(l)),s=n.filter(l=>(l.agents||[]).some(u=>Z(u)&&u.started&&!u.done)).length,r=n.filter(l=>l.buildable&&!["ready","staging"].includes(l.phase)&&!l.unsorted&&!l.held&&!l.working&&!l.grilling&&!l.prototyping&&!l.questions&&!(l.agents||[]).some(u=>Z(u)&&u.kind!==fe)),a=[...r.filter(l=>!l.blocked),...r.filter(l=>l.blocked)],c=a.filter(l=>l.bumpedAt);return[...c,...a.filter(l=>!l.bumpedAt).slice(0,Math.max(0,t-s-c.length))].map(l=>l.key)}d(Ro,"arrivalsOf");function Mo(e){return e.filter(t=>t.kind==="work"&&t.lane==="todo"&&t.roundAt&&["grilling","prototyping"].includes(t.phase)&&!(t.agents||[]).some(n=>Z(n)&&n.kind!==fe&&n.started&&(String(n.started)>=String(t.roundAt)||!n.done))).map(t=>({key:t.key,kind:t.phase==="grilling"?"grill":"prototype"}))}d(Mo,"roundsDue");const js=d(e=>`${fe}-${e.id}`,"visualAgent");function Io(e,t){const n=[];for(const s of e){const r=s.agents||[];if(r.some(l=>l.kind===fe&&l.started&&!l.done))continue;const a=new Set(r.map(l=>l.name)),c=t.find(l=>l.kind==="visual-request"&&l.data?.key===s.key&&!a.has(js(l)));c&&n.push({key:s.key,request:c})}return n}d(Io,"visualsDue");const Ws=d((e,t)=>e.kind==="ask"?t.get(`ask:${e.id}`)??null:e.kind==="card-added"?e.data?.key??null:null,"intakeKeyOf");function Fs(e,t,n){const s=e.get(n);return s?t.kind==="ask"?!!s.isNew:s.unfiled:!1}d(Fs,"unsorted");const Ks={ask:d((e,t)=>`Sort the new task: item notes, then item set ${e} --phase grilling or prototyping (ready, with --size, for a Quick build); merge it into a card with item relate-ask ${t.id} <card> --summary; or answer it with reply ${e}`,"ask"),"card-added":d(()=>"Link and file the card an agent added: item notes, then item set --relate and --phase","card-added")};function Gs(e,t,n,s){const r=new Map(e.map(c=>[c.key,c])),a=new Set;for(const c of t){const l=Ws(c,s);!l||a.has(l)||!Fs(r,c,l)||(a.add(l),r.get(l).orchestrator={kind:"intake",since:String(c.ts),picked:R(n,c.id)||null,next:Ks[c.kind](l,c)})}}d(Gs,"intakeWaits");function Qs(e,t){for(const n of e){const s=R(t,n.key);s&&(n.orchestrator={kind:"screen",since:s.since,picked:null,next:`Screen the grill's questions ${s.ids.join(", ")}: question settle <id> --note for each the board already answers, then question publish ${n.key}; left 15 minutes unscreened, they reach the owner as they are`})}}d(Qs,"screenWaits");function Hs(e){return e.filter(t=>t.lane==="todo"||t.lane==="review"&&t.stale).map(t=>JSON.stringify([t.key,t.title,t.deps||[]])).sort().join(`
7
+ `)}d(Hs,"todoOf");function qo(e){const t=e.filter(s=>s.kind==="work"&&s.lane!=="done"&&s.questions?.open>0),n=t.map(s=>JSON.stringify([s.key,s.questions.open,s.questions.askedAt||[]])).sort().join(`
8
8
  `);return{waiting:t.map(s=>s.key),seen:`${n}
9
9
  --
10
- ${Qs(e)}`}}d(Io,"triageOf");const Hs=100,Vs=["key","kind","id","ref","title","lane","phase","file","fileTitle","fold","internal","ticket","ticketSource","linear","pr","prs","review","reviewers","risky","sortAt","threadCount","othersAt","hasNotes","questions","prototypes","next","ask","action","actionButton","builder","working","waitsOn","reachedPhase","grilling","refusal","install","parent","children","related","waitsOnIt","blockedBy","ready","finishable","reopened","manualSteps","branch","worktree"],qo=d(e=>Object.fromEntries(Vs.filter(t=>t in e).map(t=>[t,e[t]])),"slimDone");function Co(e,t=Hs){const n=new Set((e.waveBands||[]).flatMap(r=>r.keys)),s=new Set(e.items.filter(r=>r.lane!=="done").flatMap(r=>[...(r.deps||[]).map(a=>String(a).includes("/")?String(a):`${r.file}/${a}`),r.parent?.key,...(r.children||[]).map(a=>a.key),...(r.related||[]).map(a=>a.key)]));return e.items.filter(r=>r.lane==="done"&&r.kind==="work").sort((r,a)=>String(a.closedAt||"").localeCompare(String(r.closedAt||""))).slice(t).filter(r=>r.storedLane==="done"&&!r.reopened&&!n.has(r.key)&&!s.has(r.key)&&(!r.questions||r.questions.state==="resolved"))}d(Co,"archivedOf");const Xs={ready:"draft",ci:"draft",reviewers:"reviewers",merge:"merge"};function Ys(e){return e.lane==="todo"?e.unpicked?"prototyping":kt.todo.includes(e.storedPhase)?e.storedPhase:e.storedLane&&e.storedLane!=="todo"?"ready":"new":e.lane==="progress"?e.waitsOn==="checking"?"checking":e.builder&&!e.builder.planner&&e.builder.kind!==ue.install&&e.builder.phase||e.reachedPhase||"reading":e.lane==="review"?e.stale?"stale":e.waitsOn==="owner"&&e.pushed?"merge":Xs[e.waitsOn]??null:e.storedLane==="done"&&kt.done.includes(e.storedPhase)?e.storedPhase:e.prs.some(t=>t.status===V.merged)?"merged":"closed"}d(Ys,"phaseOf");function No(e){return e.items.filter(t=>t.kind==="work").flatMap(t=>{const n=t.lane;return n==="done"||t.storedLane==="done"&&!t.reopened?[]:n===t.storedLane&&(n==="todo"||t.phase===t.storedPhase)?[]:[{key:t.key,to:n,phase:t.phase,why:zs(t,n),from:{lane:t.storedLane,phase:t.storedPhase}}]})}d(No,"movesOf");function zs(e,t){return t==="todo"?e.held?"it is held":e.blocked?"it is blocked":"nothing builds it":e.reopened&&e.storedLane==="done"?"a message or question reopened it":e.answered&&t==="review"?"answered, it waits for your Done":t==="progress"?e.waitsOn==="checking"?"its build handed back for a check":e.builder?"a build started":"Claude acts next":e.next||"it waits on review"}d(zs,"moveWhy");const Js=d(e=>e.startsWith("ask:")?`ask-${e.slice(4)}`:`item-${e}`,"pushTag");function Do(e){const t=d(a=>e.owner.filter(c=>c.topic===a&&c.state==="open").map(({id:c,question:l})=>({id:c,question:l})),"open"),n=[q.ready,q.merge],s=e.items.filter(a=>a.action).map(a=>{const c=rt.has(a.action.kind)?t(a.questions.topic):[];return{tag:Js(a.key),kind:a.action.kind,title:`${a.ref}: ${a.action.label}`,body:c[0]?.question||a.title,url:c.length?a.action.url:`#selectedCard=${encodeURIComponent(a.key)}`,now:!n.includes(a.action.kind),questions:c}}),r=e.needs.filter(a=>a.topic).map(a=>{const c=t(a.topic);return{tag:`topic-${a.topic}`,kind:q.questions,title:a.text,body:c[0]?.question||a.title,url:a.url,now:!0,questions:c}});return[...s,...r,...on(e.reviews)]}d(Do,"ownerActions");function Lo(e,{pulled:t=[]}={}){return!e.items.filter(r=>!pe(r)).some(r=>r.waitsOn==="checking"||r.grilling||r.prototyping||(r.agents||[]).some(a=>!a.done))&&!e.working&&!Ls(e.items,{pulled:t}).waiting.length}d(Lo,"strictlyIdle");const Zs="item stall it with the reason when it can't go on",Ft="restart it once from its worktree with a thread line; if the restarted run goes stale too, item stall it with the reason",eo='Judge the staged card against the whole board: item set --phase ready --text "<what you checked>", or --phase grilling or prototyping for another round; where its notes answer a split question Split as proposed, file the split instead',to='Its block ended: re-read its notes and answered questions against what landed; answer a stale one again with question settle <id> --note, or send the card back with item set --phase grilling when the change is too big; then item set --phase ready --text "<what you re-checked>"';function no(e,t,{answeredAt:n,workingSince:s}){const r=d(m=>e.agents.some(f=>f.kind===m&&f.started&&!f.done),"running"),a=[e.progressSince,...e.agents.map(m=>m.done)].filter(Boolean).map(String).sort().pop()||null,c=t.ask?{kind:"ask",since:t.ask.at,next:`Answer the builder's ask: ${t.ask.text}`}:e.staging?{kind:"staging",since:e.stagedAt,next:eo}:n?{kind:"answer",since:n,next:"Act on the owner's answer"}:t.replyAt?{kind:"reply",since:t.replyAt,next:"Act on the owner's reply"}:rt.has(e.action?.kind)?null:e.builder?.stopped?{kind:"stale",since:e.builder.silentSince,next:`${e.builder.stopped}: ${Ft}, or drop the card`}:e.builder?.stale?{kind:"stale",since:e.builder.silentSince,next:`Find out why the builder went silent, then finish its run or ${Ft}`}:e.lane==="review"&&e.stale?{kind:"stale",since:new Date(Date.parse(e.inReviewSince)+ht).toISOString(),daily:!0,next:`Find out why the review went stale and fix what you can: rebase, CI, comments; if only a reviewer owes it, a thread line naming who; or ${Zs}`}:e.waitsOn==="checking"?t.unverified?{kind:"calls",since:t.handedBackAt,next:t.next||"Verify the builder's judgment calls"}:{kind:"checking",since:t.handedBackAt,next:t.next||"Land the checked build"}:e.grilling&&t.grillAt&&!r("grill")?{kind:"grill",since:t.grillAt,next:"Start the grill asked for"}:e.prototyping&&t.prototypeAt&&!r("prototype")?{kind:"prototype",since:t.prototypeAt,next:"Draw the prototype asked for"}:e.recheckAt&&e.lane==="todo"&&e.phase==="ready"&&!e.blocked?{kind:"recheck",since:e.recheckAt,next:to}:e.refusal&&t.refusedAt?{kind:"refused",since:t.refusedAt,next:e.refusal}:e.next===$t&&a?{kind:"unowned",since:a,next:"Start a builder on it, or set its Next"}:t.unblockedAt&&e.lane!=="todo"&&!e.builder&&!e.blocked&&!t.writes.some(m=>m>t.unblockedAt)?{kind:"unblocked",since:t.unblockedAt,next:"Its block ended: act on what it waited for, or set its Next"}:null;if(!c?.since)return null;const l=String(c.since),u=[t.writes.find(m=>m>l),s].filter(Boolean).sort()[0]||null;return{kind:c.kind,since:l,picked:u,next:c.next,...c.daily?{daily:!0}:{}}}d(no,"orchestratorWaitOf");const To=d((e,t=null)=>({key:e.id,ref:e.data.date,title:`Overnight triage ${e.data.date}`,kind:"triage",since:e.ts,picked:t,next:`Run the overnight triage and reply: board.mjs reply ${e.id}`}),"triageWaitOf");function Po(e){const t=e.items.filter(n=>n.orchestrator).map(n=>({key:n.key,ref:n.ref,title:n.title,...n.orchestrator,bumpedAt:n.bumpedAt||null}));return[...t.filter(n=>n.bumpedAt).sort((n,s)=>n.bumpedAt.localeCompare(s.bumpedAt)),...t.filter(n=>!n.bumpedAt)]}d(Po,"orchestratorWaits");const Uo=30*6e4,so=15*6e4,oo=60*6e4,ro=1440*6e4;function jo(e,t,n){const s=n.toISOString(),r=[],a=[];return{waits:t.map(l=>{const u=e.find(p=>p.key===l.key&&p.kind===l.kind&&p.since===l.since);if(!u)return l.picked||r.push(l.key),{...l,bumped:s};const m=l.picked?[l.picked,u.bumped].filter(Boolean).sort().pop():u.bumped||l.since,f=n-Date.parse(m)>=(l.picked?l.daily?ro:oo:so);return f&&a.push({key:l.key,ref:l.ref,kind:l.kind,since:l.since,next:l.next}),{...l,bumped:f?s:u.bumped||l.since,...u.pushed?{pushed:!0}:{}}}),added:r,again:a}}d(jo,"waitsStep");function Wo(e,t){const n=d(s=>{const r=Math.floor((t-Date.parse(s))/6e4),a=Math.floor(r/60),c=r%60;return a?`${a}h${c?` ${c}m`:""}`:`${c}m`},"age");return`still waiting on you: ${e.map(s=>`${s.ref} ${s.kind} for ${n(s.since)}: ${s.next}`).join("; ")}`}d(Wo,"waitsAgainLine");const ao=15;function Fo(e,{idle:t,now:n}){const s=n.toISOString(),r=e.last||s;return t?e.since?e.pushed||n-Date.parse(e.since)<ao*6e4?{state:{...e,last:r},push:!1}:{state:{last:s,since:e.since,pushed:!0},push:!0}:{state:{last:r,since:s},push:!1}:{state:{last:r},push:!1}}d(Fo,"idleStep");function Ko(e,t){const n=d(u=>String(u.closedAt||"")>t,"after"),s=e.filter(u=>u.kind==="work"&&u.lane==="done"&&!St(u)&&n(u)),r=new Map;for(const u of e)u.wave&&r.set(u.wave.slug,[...r.get(u.wave.slug)||[],u]);const a=[...r.values()].filter(u=>u.every(m=>m.lane==="done")&&u.some(n)).map(u=>u[0].wave.title),c=s.slice(0,3).map(u=>u.ref).join(", ")+(s.length>3?` and ${s.length-3} more`:"");return[s.length&&`${s.length} ${s.length===1?"card":"cards"} landed: ${c}`,...a.map(u=>`${u} finished`)].filter(Boolean).join(" \xB7 ")||"Nothing closed since the last idle notification."}d(Ko,"idleSummary");export{q as ACTION_KIND,It as ACTION_LABELS,ps as ANSWERS_SUBMITTED,Ne as BUILDER_ASK,ue as BUILDER_KIND,wn as BUILDER_QUIET_AFTER,mn as BUILDER_STALE_AFTER,wt as BUILD_REFUSED,ce as BUTTON,Xe as COMMANDS,ro as DAILY_REWAKE_AFTER,Vs as DONE_FIELDS,Hs as DONE_KEPT,$e as HELPER,ao as IDLE_MINUTES,qt as INTENT_LABELS,kn as ITEM_EVENTS,He as LANDER,bo as LANES,Ds as MAX_IMPLEMENTERS,Ps as MAX_PLANNERS,Ee as MOVE,$t as NO_NEXT,Uo as ORCHESTRATOR_PUSH_AFTER,Oo as PAUSE_CLEARS,ns as PAUSE_HARD_STOP,kt as PHASES,oo as PICKED_REWAKE_AFTER,zn as PLANNER_WORD,Gn as PROTOTYPE_AGAIN,vo as PROTOTYPE_WAIT,V as PR_STATE,mt as QUESTION_REOPEN,so as REWAKE_AFTER,fe as VISUAL,Co as archivedOf,_o as arrivalsOf,$o as buildBoard,Q as builds,yn as fileFold,st as handedBackAt,Fo as idleStep,Ko as idleSummary,Tn as mergeBlockers,rs as modelName,No as movesOf,Ao as needsAnswer,Kn as noTakePicked,Jn as orchestratorDid,Po as orchestratorWaits,So as owesNext,Do as ownerActions,as as ownerQuestion,Eo as pauseWork,Fn as picksNoTake,Z as plans,xo as prototypeWaits,_t as providerOf,Ls as pullOf,Js as pushTag,Bo as rebasesDue,nt as refOf,ge as roundOf,ls as roundSettledBy,Ro as roundsDue,qo as slimDone,Ut as stateEntries,At as stoppedWords,Lo as strictlyIdle,Tt as threadIndex,Ss as threadOf,Qs as todoOf,Io as triageOf,To as triageWaitOf,St as unlanded,Us as visualAgent,Mo as visualsDue,Wo as waitsAgainLine,jo as waitsStep,Es as waveItems,$s as withHub};
10
+ ${Hs(e)}`}}d(qo,"triageOf");const Vs=100,Xs=["key","kind","id","ref","title","lane","phase","file","fileTitle","fold","internal","ticket","ticketSource","linear","pr","prs","review","reviewers","risky","sortAt","threadCount","othersAt","hasNotes","questions","prototypes","next","ask","action","actionButton","builder","working","waitsOn","reachedPhase","grilling","refusal","install","parent","children","related","waitsOnIt","blockedBy","ready","finishable","reopened","manualSteps","branch","worktree"],Co=d(e=>Object.fromEntries(Xs.filter(t=>t in e).map(t=>[t,e[t]])),"slimDone");function Do(e,t=Vs){const n=new Set((e.waveBands||[]).flatMap(r=>r.keys)),s=new Set(e.items.filter(r=>r.lane!=="done").flatMap(r=>[...(r.deps||[]).map(a=>String(a).includes("/")?String(a):`${r.file}/${a}`),r.parent?.key,...(r.children||[]).map(a=>a.key),...(r.related||[]).map(a=>a.key)]));return e.items.filter(r=>r.lane==="done"&&r.kind==="work").sort((r,a)=>String(a.closedAt||"").localeCompare(String(r.closedAt||""))).slice(t).filter(r=>r.storedLane==="done"&&!r.reopened&&!n.has(r.key)&&!s.has(r.key)&&(!r.questions||r.questions.state==="resolved"))}d(Do,"archivedOf");const Ys={ready:"draft",ci:"draft",reviewers:"reviewers",merge:"merge"};function zs(e){return e.lane==="todo"?e.unpicked?"prototyping":kt.todo.includes(e.storedPhase)?e.storedPhase:e.storedLane&&e.storedLane!=="todo"?"ready":"new":e.lane==="progress"?e.waitsOn==="checking"?"checking":e.builder&&!e.builder.planner&&e.builder.kind!==ue.install&&e.builder.phase||e.reachedPhase||"reading":e.lane==="review"?e.stale?"stale":e.waitsOn==="owner"&&e.pushed?"merge":Ys[e.waitsOn]??null:e.storedLane==="done"&&kt.done.includes(e.storedPhase)?e.storedPhase:e.prs.some(t=>t.status===V.merged)?"merged":"closed"}d(zs,"phaseOf");function No(e){return e.items.filter(t=>t.kind==="work").flatMap(t=>{const n=t.lane;return n==="done"||t.storedLane==="done"&&!t.reopened?[]:n===t.storedLane&&(n==="todo"||t.phase===t.storedPhase)?[]:[{key:t.key,to:n,phase:t.phase,why:Js(t,n),from:{lane:t.storedLane,phase:t.storedPhase}}]})}d(No,"movesOf");function Js(e,t){return t==="todo"?e.held?"it is held":e.blocked?"it is blocked":"nothing builds it":e.reopened&&e.storedLane==="done"?"a message or question reopened it":e.answered&&t==="review"?"answered, it waits for your Done":t==="progress"?e.waitsOn==="checking"?"its build handed back for a check":e.builder?"a build started":"Claude acts next":e.next||"it waits on review"}d(Js,"moveWhy");const Zs=d(e=>e.startsWith("ask:")?`ask-${e.slice(4)}`:`item-${e}`,"pushTag");function Lo(e){const t=d(a=>e.owner.filter(c=>c.topic===a&&c.state==="open").map(({id:c,question:l})=>({id:c,question:l})),"open"),n=[q.ready,q.merge],s=e.items.filter(a=>a.action).map(a=>{const c=rt.has(a.action.kind)?t(a.questions.topic):[];return{tag:Zs(a.key),kind:a.action.kind,title:`${a.ref}: ${a.action.label}`,body:c[0]?.question||a.title,url:c.length?a.action.url:`#selectedCard=${encodeURIComponent(a.key)}`,now:!n.includes(a.action.kind),questions:c}}),r=e.needs.filter(a=>a.topic).map(a=>{const c=t(a.topic);return{tag:`topic-${a.topic}`,kind:q.questions,title:a.text,body:c[0]?.question||a.title,url:a.url,now:!0,questions:c}});return[...s,...r,...on(e.reviews)]}d(Lo,"ownerActions");function To(e,{pulled:t=[]}={}){return!e.items.filter(r=>!pe(r)).some(r=>r.waitsOn==="checking"||r.grilling||r.prototyping||(r.agents||[]).some(a=>!a.done))&&!e.working&&!Ts(e.items,{pulled:t}).waiting.length}d(To,"strictlyIdle");const eo="item stall it with the reason when it can't go on",Ft="restart it once from its worktree with a thread line; if the restarted run goes stale too, item stall it with the reason",to='Judge the staged card against the whole board: item set --phase ready --text "<what you checked>", or --phase grilling or prototyping for another round; where its notes answer a split question Split as proposed, file the split instead',no='Its block ended: re-read its notes and answered questions against what landed; answer a stale one again with question settle <id> --note, or send the card back with item set --phase grilling when the change is too big; then item set --phase ready --text "<what you re-checked>"';function so(e,t,{answeredAt:n,workingSince:s}){const r=d(m=>e.agents.some(f=>f.kind===m&&f.started&&!f.done),"running"),a=[e.progressSince,...e.agents.map(m=>m.done)].filter(Boolean).map(String).sort().pop()||null,c=t.ask?{kind:"ask",since:t.ask.at,next:`Answer the builder's ask: ${t.ask.text}`}:e.staging?{kind:"staging",since:e.stagedAt,next:to}:n?{kind:"answer",since:n,next:"Act on the owner's answer"}:t.replyAt?{kind:"reply",since:t.replyAt,next:"Act on the owner's reply"}:rt.has(e.action?.kind)?null:e.builder?.stopped?{kind:"stale",since:e.builder.silentSince,next:`${e.builder.stopped}: ${Ft}, or drop the card`}:e.builder?.stale?{kind:"stale",since:e.builder.silentSince,next:`Find out why the builder went silent, then finish its run or ${Ft}`}:e.lane==="review"&&e.stale?{kind:"stale",since:new Date(Date.parse(e.inReviewSince)+ht).toISOString(),daily:!0,next:`Find out why the review went stale and fix what you can: rebase, CI, comments; if only a reviewer owes it, a thread line naming who; or ${eo}`}:e.waitsOn==="checking"?t.unverified?{kind:"calls",since:t.handedBackAt,next:t.next||"Verify the builder's judgment calls"}:{kind:"checking",since:t.handedBackAt,next:t.next||"Land the checked build"}:e.grilling&&t.grillAt&&!r("grill")?{kind:"grill",since:t.grillAt,next:"Start the grill asked for"}:e.prototyping&&t.prototypeAt&&!r("prototype")?{kind:"prototype",since:t.prototypeAt,next:"Draw the prototype asked for"}:e.recheckAt&&e.lane==="todo"&&e.phase==="ready"&&!e.blocked?{kind:"recheck",since:e.recheckAt,next:no}:e.refusal&&t.refusedAt?{kind:"refused",since:t.refusedAt,next:e.refusal}:e.next===$t&&a?{kind:"unowned",since:a,next:"Start a builder on it, or set its Next"}:t.unblockedAt&&e.lane!=="todo"&&!e.builder&&!e.blocked&&!t.writes.some(m=>m>t.unblockedAt)?{kind:"unblocked",since:t.unblockedAt,next:"Its block ended: act on what it waited for, or set its Next"}:null;if(!c?.since)return null;const l=String(c.since),u=[t.writes.find(m=>m>l),s].filter(Boolean).sort()[0]||null;return{kind:c.kind,since:l,picked:u,next:c.next,...c.daily?{daily:!0}:{}}}d(so,"orchestratorWaitOf");const Po=d((e,t=null)=>({key:e.id,ref:e.data.date,title:`Overnight triage ${e.data.date}`,kind:"triage",since:e.ts,picked:t,next:`Run the overnight triage and reply: board.mjs reply ${e.id}`}),"triageWaitOf");function Uo(e){const t=e.items.filter(n=>n.orchestrator).map(n=>({key:n.key,ref:n.ref,title:n.title,...n.orchestrator,bumpedAt:n.bumpedAt||null}));return[...t.filter(n=>n.bumpedAt).sort((n,s)=>n.bumpedAt.localeCompare(s.bumpedAt)),...t.filter(n=>!n.bumpedAt)]}d(Uo,"orchestratorWaits");const jo=30*6e4,oo=15*6e4,ro=60*6e4,ao=1440*6e4;function Wo(e,t,n){const s=n.toISOString(),r=[],a=[];return{waits:t.map(l=>{const u=e.find(p=>p.key===l.key&&p.kind===l.kind&&p.since===l.since);if(!u)return l.picked||r.push(l.key),{...l,bumped:s};const m=l.picked?[l.picked,u.bumped].filter(Boolean).sort().pop():u.bumped||l.since,f=n-Date.parse(m)>=(l.picked?l.daily?ao:ro:oo);return f&&a.push({key:l.key,ref:l.ref,kind:l.kind,since:l.since,next:l.next}),{...l,bumped:f?s:u.bumped||l.since,...u.pushed?{pushed:!0}:{}}}),added:r,again:a}}d(Wo,"waitsStep");function Fo(e,t){const n=d(s=>{const r=Math.floor((t-Date.parse(s))/6e4),a=Math.floor(r/60),c=r%60;return a?`${a}h${c?` ${c}m`:""}`:`${c}m`},"age");return`still waiting on you: ${e.map(s=>`${s.ref} ${s.kind} for ${n(s.since)}: ${s.next}`).join("; ")}`}d(Fo,"waitsAgainLine");const lo=15;function Ko(e,{idle:t,now:n}){const s=n.toISOString(),r=e.last||s;return t?e.since?e.pushed||n-Date.parse(e.since)<lo*6e4?{state:{...e,last:r},push:!1}:{state:{last:s,since:e.since,pushed:!0},push:!0}:{state:{last:r,since:s},push:!1}:{state:{last:r},push:!1}}d(Ko,"idleStep");function Go(e,t){const n=d(u=>String(u.closedAt||"")>t,"after"),s=e.filter(u=>u.kind==="work"&&u.lane==="done"&&!St(u)&&n(u)),r=new Map;for(const u of e)u.wave&&r.set(u.wave.slug,[...r.get(u.wave.slug)||[],u]);const a=[...r.values()].filter(u=>u.every(m=>m.lane==="done")&&u.some(n)).map(u=>u[0].wave.title),c=s.slice(0,3).map(u=>u.ref).join(", ")+(s.length>3?` and ${s.length-3} more`:"");return[s.length&&`${s.length} ${s.length===1?"card":"cards"} landed: ${c}`,...a.map(u=>`${u} finished`)].filter(Boolean).join(" \xB7 ")||"Nothing closed since the last idle notification."}d(Go,"idleSummary");export{q as ACTION_KIND,It as ACTION_LABELS,fs as ANSWERS_SUBMITTED,De as BUILDER_ASK,ue as BUILDER_KIND,wn as BUILDER_QUIET_AFTER,mn as BUILDER_STALE_AFTER,wt as BUILD_REFUSED,ce as BUTTON,Xe as COMMANDS,ao as DAILY_REWAKE_AFTER,Xs as DONE_FIELDS,Vs as DONE_KEPT,ge as HELPER,lo as IDLE_MINUTES,qt as INTENT_LABELS,kn as ITEM_EVENTS,He as LANDER,So as LANES,Ls as MAX_IMPLEMENTERS,Us as MAX_PLANNERS,$e as MOVE,$t as NO_NEXT,jo as ORCHESTRATOR_PUSH_AFTER,Eo as PAUSE_CLEARS,ns as PAUSE_HARD_STOP,kt as PHASES,ro as PICKED_REWAKE_AFTER,zn as PLANNER_WORD,Gn as PROTOTYPE_AGAIN,xo as PROTOTYPE_WAIT,V as PR_STATE,mt as QUESTION_REOPEN,oo as REWAKE_AFTER,fe as VISUAL,Do as archivedOf,Ro as arrivalsOf,Ao as buildBoard,Q as builds,$o as confirmedDrops,yn as fileFold,st as handedBackAt,Ko as idleStep,Go as idleSummary,Tn as mergeBlockers,as as modelName,No as movesOf,Bo as needsAnswer,Kn as noTakePicked,Jn as orchestratorDid,Uo as orchestratorWaits,vo as owesNext,Lo as ownerActions,ls as ownerQuestion,rs as pauseWork,Fn as picksNoTake,Z as plans,Oo as prototypeWaits,_t as providerOf,Ts as pullOf,Zs as pushTag,_o as rebasesDue,nt as refOf,ke as roundOf,is as roundSettledBy,Mo as roundsDue,Co as slimDone,Ut as stateEntries,At as stoppedWords,To as strictlyIdle,Tt as threadIndex,vs as threadOf,Hs as todoOf,qo as triageOf,Po as triageWaitOf,St as unlanded,js as visualAgent,Io as visualsDue,Fo as waitsAgainLine,Wo as waitsStep,$s as waveItems,As as withHub};