@lovek4d/kickflip 0.7.0 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CONTEXT.md +53 -49
  2. package/SKILL.md +17 -13
  3. package/bin/event-lines.mjs +1 -1
  4. package/bin/kickflip.mjs +3 -3
  5. package/board/agents.mjs +2 -2
  6. package/board/arch-review.mjs +4 -4
  7. package/board/bin/board.mjs +113 -105
  8. package/board/domain.mjs +7 -7
  9. package/board/finish.mjs +4 -4
  10. package/board/headless.mjs +8 -8
  11. package/board/hub-lines.mjs +1 -0
  12. package/board/onboarding.mjs +3 -3
  13. package/board/public/app-arch.js +1 -1
  14. package/board/public/app-cards.js +6 -7
  15. package/board/public/app-header.js +1 -1
  16. package/board/public/app-lanes.js +39 -62
  17. package/board/public/app-needs.js +16 -11
  18. package/board/public/app-reader.js +9 -5
  19. package/board/public/app.js +3 -3
  20. package/board/public/attach.js +18 -2
  21. package/board/public/dialogs.js +11 -13
  22. package/board/public/hub-kit.js +1 -1
  23. package/board/public/hub.css +0 -1
  24. package/board/public/linear-key.js +2 -2
  25. package/board/public/new-task.js +1 -1
  26. package/board/public/prototype-kit.js +2 -5
  27. package/board/public/router.js +1 -1
  28. package/board/public/sidebar.css +3 -3
  29. package/board/public/sidebar.js +2 -2
  30. package/board/public/style.css +43 -43
  31. package/board/public/ui-cards.js +25 -20
  32. package/board/public/ui-hub.js +1 -5
  33. package/board/public/ui-links.js +5 -5
  34. package/board/public/ui-order.js +6 -7
  35. package/board/public/ui-questions.js +17 -13
  36. package/board/public/ui-sidebar.js +1 -1
  37. package/board/public/ui-threads.js +29 -21
  38. package/board/public/ui.js +23 -6
  39. package/board/public/view-hub-settings.js +11 -19
  40. package/board/public/view-hub.js +25 -11
  41. package/board/public/view-notes.js +1 -1
  42. package/board/public/view-questions.js +18 -5
  43. package/board/public/view-settings.js +7 -7
  44. package/board/render-check.mjs +10 -10
  45. package/board/review.mjs +1 -1
  46. package/board/server.mjs +18 -19
  47. package/board/stop.mjs +1 -1
  48. package/board/store.mjs +26 -26
  49. package/board/tickets.mjs +3 -3
  50. package/hooks-plugin/hooks/board-data-gate.mjs +6 -6
  51. package/hub/awake.mjs +1 -1
  52. package/hub/board-repo.mjs +1 -1
  53. package/hub/boards.mjs +4 -4
  54. package/hub/github.mjs +3 -3
  55. package/hub/hub.mjs +11 -11
  56. package/hub/incoming.mjs +2 -2
  57. package/hub/linear.mjs +1 -1
  58. package/hub/locks.mjs +1 -1
  59. package/hub/new-board.mjs +2 -2
  60. package/hub/owner-checks.mjs +1 -1
  61. package/hub/readiness.mjs +1 -1
  62. package/hub/review-send.mjs +1 -1
  63. package/hub/slack.mjs +1 -1
  64. package/hub/try.mjs +6 -7
  65. package/hub/views.mjs +1 -1
  66. package/package.json +1 -1
  67. package/shared/usage-gate.mjs +1 -1
  68. package/starter/server.mjs +3 -3
package/board/domain.mjs CHANGED
@@ -1,10 +1,10 @@
1
- var Kt=Object.defineProperty;var l=(e,t)=>Kt(e,"name",{value:t,configurable:!0});import{routeRecord as B}from"../hub/routes.mjs";import Gt from"node:fs";import{ticketBadge as pt,ticketIn as Qt}from"./tickets.mjs";import{prLinks as Ht,reviewLinks as Vt,reviewTime as Xt,reviewersOf as Yt}from"./review.mjs";import{remoteFromInput as zt}from"../hub/repos.mjs";import{reviewsOf as Jt,reviewNeeds as Zt,reviewActions as en}from"./auto-review.mjs";import{cardPRs as tn,hasPR as et,leastReady as nn,prKeyOf as sn,prURL as on}from"../shared/card-prs.mjs";import ft from"node:vm";import{checkWords as rn,parseCheck as an}from"../shared/owner-check.mjs";import{buildScriptOf as ln}from"./build-script.mjs";const tt=ft.createContext({});for(const e of["ui-enums.js","ui-order.js"])ft.runInContext(Gt.readFileSync(new URL(`./public/${e}`,import.meta.url),"utf8"),tt);const{BUTTON:le,ACTION_KIND:N,BUILDER_KIND:pe,PR_STATE:H,PHASES:gt}=tt.BoardUI,{laneOrder:dn}=tt.BoardUI,cn=["item-message","mark-ready","grill-more","prototype-request","visual-request","reask-request"],kt="question-reopen",lo=Object.freeze({todo:"Todo",progress:"In Progress",review:"In Review",done:"Done"}),Oe="move",un=10*6e4,pn=5*6e4,mt="build-refused",Ne=Object.freeze({ask:"builder-ask",answer:"builder-answer"}),fn=864e5,fe=l(e=>e.lane==="done"||e.lane==="asks","closedLane"),gn=l(e=>`wave:${e}`,"waveFold"),wt=7*fn,ht=l((e,t)=>({id:e,url:t?.workspace?`https://linear.app/${t.workspace}/issue/${e}`:null}),"linearRef"),kn=l((e,t)=>String(e).replace(/^S(\d+)$/,`${t||"INT"}-$1`),"internalRef"),Ge=l((e,t,n)=>Qt(n,t.ticket)?t.ticket:e.internal===!0?kn(t.id,n?.prefix):t.id,"refOf"),mn=l((e,t,n,s)=>pt(e||(t?{source:"internal",prefix:"INT"}:null),n,s)||(t?{id:String(t),url:null,source:null}:null),"ticketOf");function wn(e,t,n,s,r,a,d,c,p){return!a&&(e.lane==="done"||t?.state==="MERGED"||t?.state==="CLOSED")?"done":(n||s)&&!c?"progress":r?"review":t?.state==="OPEN"?t.checks?.state==="fail"&&(!t.isDraft||d)?"progress":"review":t||p?"progress":"todo"}l(wn,"laneOf");const Qe="Lander",yt=l(e=>e.kind!==pe.install&&e.label!==Qe,"changesCode");function hn(e,t){return e?.state==="MERGED"||t?H.merged:e?.state==="CLOSED"?H.closed:e?.state==="OPEN"?e.isDraft?H.draft:H.open:null}l(hn,"prStateOf");const bt=l(e=>e.pr?.status===H.closed,"unlanded"),yn=l(e=>e.some(t=>t.kind==="work")&&e.every(t=>t.lane==="done"),"finishedOf");function nt(e){const t=St(e);return t?.done&&t.handed_back?t.handed_back:null}l(nt,"handedBackAt");const St=l(e=>e.filter(t=>t?.started&&te(t)&&t.kind!==pe.install).sort((t,n)=>String(t.started).localeCompare(String(n.started))).at(-1),"newestBuild");function bn(e,t,n){return Object.fromEntries(e.map(s=>{const r=B(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"?B(n,s.name):null,github:s.github||null}]}))}l(bn,"reviewOf");function Sn(e,t,n,s,r,a,{held:d,needsApproval:c}){return n?.kind===pe.install?"builder":s?"checking":n?"builder":d&&e==="review"?"merge":r&&e==="review"?"owner":e==="review"&&t?.state==="OPEN"&&t.isDraft?a?"ci":"ready":e==="review"?vt(t,c)?"merge":"reviewers":null}l(Sn,"waitsOnOf");const vt=l((e,t)=>e?.reviewDecision==="APPROVED"||!t&&!["REVIEW_REQUIRED","CHANGES_REQUESTED"].includes(e?.reviewDecision),"reviewed"),De=/(^|\/)prototype-[\w-]+\.html/,vn={reviewers:"Waiting for PR reviewers",merge:"Approved, merges once CI and the merge state allow",ci:"Marked ready for review once CI passes"},He={waiting:"Approved, Merge shows once CI and the merge state allow",ready:"Approved and green: tap Merge",merging:"Merging"},st={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"},On=l(e=>`Verified: tap Merge to land it on ${e}`,"heldNext"),xn="Fix the failing CI",Ot="Tap Done once it is settled",$n=["status","agent","ask-link","command",Oe,Ne.answer],xt=l(e=>(e.who==="claude"||e.via==="github")&&!$n.includes(e.kind),"countsUnread"),An=/^(?:Not merged yet: |Lander launched headless )/;function En({slug:e,wave:t,it:n,order:s,prs:r,repo:a,remote:d,base:c,builder:p,reachedPhase:f,agents:g,worktree:u,eta:h,thread:S,events:_,working:v,said:T,askedAt:D,topicItems:R,prSlack:C,boardReviewers:U,now:m,bumpedAt:A,holdAsk:i,closedAt:E,mergeAt:y,autoMerge:ne,skipDraft:de,tickets:F}){const V=r.map(w=>({repo:w.repo,number:w.number,url:on(w),...w.gh||w.kept||{},status:hn(w.gh,w.merged_at)})),K=nn(r.map(w=>w.gh)),L=r[K]?.gh||null,X=V[K]?.status??null,Y=n.lane||null,Te=!!E&&String(E)>String(n.lane_at||"");Te&&(n={...n,lane:"done",closed_at:E,reopened_at:void 0});const W=[n.closed_at,...r.flatMap(w=>[w.merged_at,w.gh?.mergedAt])].filter(Boolean).map(String).sort().pop()||null,j=String(W||""),Le=V.length>0&&V.every(w=>w.status===H.closed),G=(n.lane==="done"||n.reopened_at||X===H.merged)&&!Le&&([...T.filter(w=>w.kind==="item-message").map(w=>w.ts),...D].map(String).filter(w=>w>j).sort().pop()||n.reopened_at)||void 0,me=n.owner_step&&!Te?String(n.owner_step):null,Ye=(n.lane==="done"||X===H.merged)&&!Le,Pe=!!G&&!!n.next&&String(n.next_at||"")>String(n.reopened_at||W||"");G&&!Pe&&(n={...n,next:void 0});const Be=nt(g),ze=!!G&&T.some(w=>String(w.ts)>j&&(w.state==="waiting"||w.state==="working")),Q=`${e}/${n.id}`,z=Yt(t,U),_e=Object.fromEntries(Object.entries(Vt(t,n,Q,R,Ht(C,r))).map(([w,Z])=>[w,Xt(Z.ts)])),we=Object.values(_e).filter(Boolean).sort()[0]||null,he=[...S.map(w=>w.ts),..._.map(w=>w.ts)].sort().pop()||null,je=[...S.filter(w=>xt({...w,who:w.who||"claude"})).map(w=>w.ts),..._.map(w=>w.reply?.at)].filter(Boolean).sort(),J=!et(n)&&n.pushed?.branch?{branch:n.pushed.branch,at:n.pushed.at||null,host:d?.host||null}:null,se=!et(n)&&n.merge_ready?.branch?{branch:n.merge_ready.branch,at:n.merge_ready.at||null,base:c}:null,oe=!!n.rebase_run&&L?.state==="OPEN",ye=(n.rebased||[]).at(-1),Re=g.filter(w=>w.started&&!w.done&&te(w)),Ue=!!Be&&yt(St(g));let M=wn(n,L,Re.some(yt),Ue,J||se,!!G,de,oe,Re.length>0||!!Be);G&&M==="todo"&&(M="progress");const Je=M==="review"&&!!we&&m-Date.parse(we)>wt,re=!!me&&Ye&&M==="done";re&&(M="review");let P=Sn(M,L,p,!!Be&&M!=="done",J,de,{held:se,needsApproval:z.length>0});const be=P==="builder"&&L?.state==="OPEN"&&!L.isDraft,Me=M==="progress"&&!P&&L?.state==="OPEN"&&(!L.isDraft||de),ae=re||!!G&&M==="progress"&&!P&&!Me&&!ze&&!Pe;ae&&(P="owner");const qe=i&&String(i.ts)>String(n.held_at||""),Ie=M==="todo"&&(qe?!!i.data.hold:!!n.held),Ze=Ie&&(qe?i.data.until:n.pick_up_at)||null,We=M!=="done",o=!!A&&!(j&&String(A)<=j),k=S.filter(w=>(w.who||"claude")==="claude"&&!["status","command",Oe].includes(w.kind)&&!An.test(w.text||"")).map(w=>String(w.ts)).sort().pop()||"",b=[y,se&&n.merge_ready.tapped].filter(Boolean).map(String).sort().pop(),O=P==="merge"&&!!b&&b>k,x=S.filter(w=>w.kind==="status"&&String(w.ts)>String(b)).sort((w,Z)=>String(w.ts).localeCompare(String(Z.ts))).at(-1),q=x?.text.startsWith("Waiting for ")?`${He.merging} \xB7 ${x.text[0].toLowerCase()}${x.text.slice(1)}`:He.merging,I=S.filter(w=>!["status",Oe].includes(w.kind)).sort((w,Z)=>String(w.ts).localeCompare(String(Z.ts))).at(-1),ce=M==="todo"&&I?.kind===mt?I.text:null,ue=G||g.filter(te).map(w=>w.started).filter(Boolean).map(String).sort().pop()||null,Fe=L?.reviewDecision==="APPROVED",Ke=J&&P==="owner"?`merge ${J.branch} into ${c}`:se&&P==="merge"?O?q:On(c):P==="merge"&&!ne?O?q:(Fe?He:st).waiting:P==="merge"&&!Fe?st.auto:vn[P],Se=X===H.draft?`Review draft PR #${V[K].number}`:null,ve=!oe&&ye?.to&&ye.to===L?.headRefOid?`Rebased onto ${ye.base||c}, pushed${L.mergeable==="MERGEABLE"?" \xB7 PR is clean again":""}`:null,$=oe&&P==="checking"?g.flatMap(w=>w.calls).sort((w,Z)=>String(w.at).localeCompare(String(Z.at))).at(-1)?.text??null:null;return{key:Q,kind:"work",order:s,wave:e,waveTitle:t.title||e,id:n.id,ref:Ge(t,n,F),title:n.title,storedLane:Y,created:n.created||null,reviewSince:n.review_since||we||n.merge_ready?.at||n.pushed?.at||n.created||null,progressSince:ue,closedAt:M==="done"?W:null,internal:t.internal===!0,repo:t.internal===!0&&!t.repo?null:a,lane:M,waitsOn:P,builder:P==="checking"?null:p,reachedPhase:f,agents:g,worktree:u??null,eta:h,working:v,reopened:!!G,awaitsDone:ae,ownerStep:ae?me:null,ownerCheck:ae&&me&&n.owner_check?{words:rn(an(n.owner_check.check)),broken:n.owner_check.broken||null}:null,stagedAt:M==="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:Ie,heldUntil:Ze,risky:!!n.risky,bumpable:We,bumpedAt:We&&o?A:null,bumpedOut:n.bumped_out?{key:n.bumped_out.by,at:n.bumped_out.at}:null,holdable:M!=="done",hasNotes:!!(n.plan||String(n.notes||"").trim()),finishable:M!=="done",merging:O,refusal:ce,manualSteps:n.manual_steps||[],fromAsk:n.from_ask||null,unfiled:!!n.unfiled,filedHeld:!!n.filed_held,next:be||M==="done"||P==="checking"?null:Me?xn:ve||Ke||n.next||Se||null,rebaseFailed:$,branch:n.branch||L?.headRefName||J?.branch||null,pushed:M==="done"||re?null:J,mergeReady:M==="review"?se:null,stale:M!=="done"&&(Je||!!p?.stale),stalled:n.stalled?.reason||null,landStopped:M==="review"&&se&&n.merge_ready.stopped&&String(n.merge_ready.stopped)>String(n.merge_ready.tapped||"")?{words:Bt("land"),at:n.merge_ready.stopped}:null,ticket:F?.source==="linear"&&!n.ticket&&n.linear?.length?null:mn(F,n.ticket,n.ticket||(t.internal?Ge(t,n,F):n.linear?.[0]),{repo:a,key:Q}),ticketSource:F?.source||null,linear:(n.linear||[]).map(w=>F?.source==="linear"&&pt(F,w,{key:Q,repo:a})||ht(w,F)),pr:V[K]||null,prs:V,reviewers:z.map(w=>w.name),review:bn(z,L||r[K]?.kept,_e),inReviewSince:we,threadCount:S.length+_.length,lastTs:he,othersAt:je,grilling:_t("grill",_,g,D),prototyping:_t("prototype",_,g,D),storedPhase:n.phase||null,phase:null,updatedAt:L?.mergedAt||L?.updatedAt||r[K]?.merged_at||p?.at||he||null,ask:null,fold:null,action:null,install:M==="done"?null:_n(n.install,L),waitFacts:Bn(n,{agents:g,thread:S,events:_,refusedAt:ce?I.ts:null})}}l(En,"workItem");function Bn(e,{agents:t,thread:n,events:s,refusedAt:r}){const a=new Set(n.filter(f=>f.kind===Ne.answer).map(f=>f.ask)),d=n.filter(f=>f.kind===Ne.ask&&!a.has(f.ask)).sort((f,g)=>String(f.ts).localeCompare(String(g.ts)))[0],c=l(f=>s.filter(g=>rt(g,f)).pop()?.ts||null,"requestAt"),p=n.filter(f=>(f.who||"claude")==="claude"&&!["status","agent","command",Oe,mt].includes(f.kind)).map(f=>f.ts);return{handedBackAt:nt(t),next:e.next||null,ask:d?{at:d.ts,text:d.text}:null,grillAt:c("grill"),prototypeAt:c("prototype"),refusedAt:r,unblockedAt:e.unblocked_at||null,unverified:t.some(f=>f.calls.some(g=>!f.verified||String(g.at)>String(f.verified.at))),writes:[...p,...t.flatMap(f=>[f.verified?.at,f.started])].filter(Boolean).map(String).sort()}}l(Bn,"waitFactsOf");function _n(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))}}l(_n,"installOf");function Rn(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",!vt(e,t)&&`review: ${String(e.reviewDecision||"none").toLowerCase().replace(/_/g," ")}`,n==="fail"&&`failing: ${r?.length?r.join(", "):"a check"}`,n==="pending"&&`pending: ${s?ie(s,"check"):"checks"}`,e.mergeStateStatus!=="CLEAN"&&`merge state: ${String(e.mergeStateStatus||"unknown").toLowerCase()}`].filter(Boolean)}l(Rn,"mergeBlockers");const Mn=l((e,t)=>!Rn(e,{needsApproval:t}).length,"mergeable");function qn(e,t,n){if(fe(e))return null;const s=`#selectedCard=${encodeURIComponent(e.key)}`;if(e.stalled)return{kind:N.stalled,url:s,label:`stalled: ${e.stalled}`};if(In(e)){const r=t.get(e.questions.first);return De.test(r?.url||"")?{kind:N.pick,url:`questions.html#${r.id}`,label:"Prototypes ready: pick a take"}:{kind:N.questions,url:`questions.html#${e.questions.first}`,label:`Answer ${ie(e.questions.open,"question")}`}}return e.waitsOn==="ready"?{kind:N.ready,url:e.pr.url,label:`Review draft PR #${e.pr.number}`}:e.kind==="ask"&&e.waitsOn==="owner"?{kind:N.done,url:s,label:e.next||Ot}:e.waitsOn==="merge"&&e.manualSteps.length&&!e.mergeReady?{kind:N.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)||Mn(r,e.reviewers.length>0))?{kind:N.merge,url:s,label:"Merge"}:null}l(qn,"actionOf");const In=l(e=>!!(e.questions&&e.questions.state!=="resolved"&&e.questions.open>0),"asking"),ot=new Set([N.pick,N.questions]);function $t(e){return e.questions?le.openQuestions:null}l($t,"actionButtonOf");const Nn=l(e=>e.kind==="work"&&e.lane==="todo"&&!e.action&&!e.unpicked,"buildableOf"),Dn=l((e,t)=>/^item:/.test(e.topic||"")&&De.test(e.url||"")&&!(e.options||[]).some(n=>n.id===t),"picksNoTake");function Cn(e,t){const n=e.filter(a=>a.topic===`item:${t}`),r=[...n.filter(a=>De.test(a.url||"")).flatMap(a=>a.answers.map(d=>({q:a,a:d,again:Dn(a,d.choice)}))),...n.filter(a=>a.request).map(a=>({q:a,a:a.request,again:!0}))].sort((a,d)=>String(a.a.ts).localeCompare(String(d.a.ts))).at(-1);return r?.again?{id:r.q.id,note:r.a.note.replace(/\s+/g," ").trim()}:null}l(Cn,"noTakePicked");const Tn="Prototype again",Ln=Object.freeze({[N.pick]:le.openQuestions,[N.questions]:le.openQuestions,[N.ready]:le.github,[N.steps]:le.github,[N.merge]:le.merge,[N.done]:le.done,[N.stalled]:le.reply}),Pn="Merges once unblocked",jn=l(e=>`Blocked ${[e.blockedBy.length&&`by ${e.blockedBy.map(t=>t.ref).join(", ")}`,e.blockedUntil&&`until ${e.blockedUntil}`].filter(Boolean).join(" and ")}`,"mergeBlockedWords");function Un(e,t,n){if(e.action=qn(e,t,n),e.mergeBlocked=e.action?.kind===N.merge&&e.blocked?jn(e):null,e.mergeBlocked&&Object.assign(e,{action:null,next:Pn}),e.action?.kind===N.questions&&e.questions.fromAsks){Object.assign(e,{action:null,waitsOn:"owner",next:e.action.label,actionButton:$t(e),resolvedBy:null});return}e.awaitsDone&&=!e.action,e.awaitsDone||Object.assign(e,{ownerStep:null,ownerCheck:null}),e.actionButton=$t(e),e.resolvedBy=Ln[e.action?.kind]||null,e.action?.kind===N.merge&&!e.mergeReady&&(e.next=(e.pr?.reviewDecision==="APPROVED"?He:st).ready),e.awaitsDone&&Object.assign(e,{lane:"review",next:e.ownerStep||Ot,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"&&ot.has(e.action.kind)?"todo":"review";Object.assign(e,{lane:r,waitsOn:e.waitsOn==="ready"?"ready":"owner",next:e.action.label})}l(Un,"placeOwnerWait");const At=l((e,t)=>e?e!=="todo":t.some(te),"started"),Et="none set yet";function io(e,t){const n=t.filter(s=>s?.started);return e.next||et(e)||e.pushed||e.held||e.lane==="done"||nt(n)?!1:!n.some(s=>!s.done)&&At(e.lane,n)}l(io,"owesNext");function Wn(e,t=new Date){const n=new Date(e),s=n.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"});return n.toDateString()===t.toDateString()?s:`${n.getMonth()+1}/${n.getDate()} ${s}`}l(Wn,"askedLabel");function Fn(e,t,n,s,r,a,d,c){const p=t.find(y=>y.kind==="ask"&&y.eventId===e.id),f=p.files,g=c||(p.text||"").trim().split(`
2
- `)[0]||f.map(y=>y.name).join(", ")||"Ask",u=p.state==="replied"||p.state==="answered",h=r?.state==="progress"&&!(String(a||"")>String(r.at||"")),S=!h&&(!!r||!!a),_=u&&!S&&!h&&d.open>0,v=u&&!S&&!h&&!_&&d.answered>0,T=S||u&&!h&&!_&&!v,D=u&&!s&&!r?.moved&&[...t.filter(y=>y.who==="claude"&&y.kind!=="ask-link"&&y.kind!=="status"&&y.kind!=="command").map(y=>y.ts),...t.map(y=>y.reply?.at)].filter(Boolean).sort().pop()||null,R=T||h||_||v,C=t.some(y=>y.who==="love"&&y.kind!=="ask"&&(y.state==="waiting"||y.state==="working")),U=t.filter(y=>y.who==="love"&&y.kind==="item-message").flatMap(Ce).filter(([,y])=>y==="waiting"||y==="working").map(([y])=>y),m=R?"answered":p.state,A=R?null:n||null,i=[...t.filter(xt).map(y=>y.ts),...t.map(y=>y.reply?.at)].filter(Boolean).sort(),E=[...t.map(y=>y.ts),...i,...h?[r.at]:[]].filter(Boolean).sort().pop();return{key:`ask:${e.id}`,kind:"ask",order:0,wave:null,waveTitle:null,id:e.id,ref:R?Wn(e.ts):"New",isNew:!R,title:g,storedLane:null,internal:!1,repo:null,lane:h?"progress":T?"asks":"todo",waitsOn:h&&!C?"owner":null,builder:null,agents:[],eta:null,working:t.some(y=>Ce(y).some(([,ne])=>ne==="working")),deps:[],held:!1,risky:!1,bumpable:!R,bumpedAt:A,manualSteps:[],fromAsk:null,from:null,next:h&&r.next||null,hasNotes:!1,branch:null,finishable:R&&!T,linear:[],pr:null,prs:[],reviewers:[],review:{},inReviewSince:null,reviewSince:null,progressSince:h&&r.at||null,closedAt:null,threadCount:t.length,lastTs:E,othersAt:R?i:[],grilling:!1,prototyping:!1,created:e.ts,updatedAt:R?E:e.ts,ask:{eventId:e.id,state:m,askedAt:e.ts,bumpedAt:A,edited:!!p.edited,canEdit:!R,text:p.text,files:f,answerAt:D,from:p.from||null,owed:U},fold:null,action:null}}l(Fn,"askItem");const ge="visual",xe="helper",Kn=new Set(["grill","prototype",ge]),ee=l(e=>Kn.has(e.kind),"plans"),te=l(e=>!ee(e),"builds"),Gn={grill:"grilling",prototype:"prototyping"},Qn=l((e,t)=>`${e} ${t} by orchestrator`,"orchestratorDid"),Bt=l(e=>Qn(e,"stopped"),"stoppedWords"),Hn={grill:"grill-more",prototype:"prototype-request"},rt=l((e,t)=>e.kind===Hn[t]&&!e.data?.question,"isRequest");function _t(e,t,n,s){if(n.some(a=>a.kind===e&&a.started&&!a.done))return!0;const r=t.filter(a=>rt(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)))}l(_t,"planningOf");const co=30*6e4;function uo(e,t){const n=[];for(const s of e.items){if(fe(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&&rt(a,"prototype")).pop();r&&n.push({key:s.key,request:r.id,since:r.ts});for(const a of e.owner.filter(d=>d.topic===`item:${s.key}`&&d.state==="requested"))n.push({key:s.key,request:a.request.id,question:a.id,since:a.request.ts})}return n}l(uo,"prototypeWaits");function at(e={},t=!1){return Object.entries(e).filter(([n,s])=>s&&typeof s=="object"&&(t||!n.startsWith("past-"))).map(([n,s])=>({name:n,kind:Rt(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.kind===xe?{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))}l(at,"agentsOf");function lt(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}l(lt,"worktreeOf");function Vn(e,t=[]){const n=e.filter(te).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}l(Vn,"reachedPhaseOf");function Xn(e,t=[],n,s=null,r=null,a=!1){const d=e.filter(m=>m.started&&!m.done&&m.kind!==ge),c=d.every(ee),p=c?d:d.filter(te),f=p.map(m=>String(m.started||"")).sort()[0];if(f===void 0)return null;const g=t.filter(m=>m.kind==="status"&&String(m.ts)>=f&&(c||!m.planner)).sort((m,A)=>String(m.ts).localeCompare(String(A.ts))).pop(),u=p.filter(m=>m.kind!==xe).at(-1),h=p.some(m=>m.kind===pe.install)?pe.install:u?Rt(u.kind):"claude",S=c?null:p.find(m=>m.stopped&&String(m.stopped.at)>=String(m.started))?.stopped,_=g?.ts||f,v=S?S.at:s!==null&&s>Date.parse(_)?new Date(s).toISOString():_,T=g?g.phase||g.planner?g.text.replace(": "," \xB7 "):g.text||null:c?Gn[h]:null,D=n-Date.parse(v),R=!c&&!S&&r==="held",C=c||R?null:S?!1:r,U=R?!1:C===null?D>=un:!C;return{progress:T,phase:g?.phase||null,at:_,kind:h,planner:c,silentSince:v,stale:U,alive:C,held:R,quiet:C===!0&&!a&&D>=pn,stopped:S?Bt(S.run):null}}l(Xn,"builderOf");const it={opus:"Claude Opus",sonnet:"Claude Sonnet",codex:"Codex"},Yn=l(({model:e,kind:t})=>it[e]||it[t]||(t==="claude"?it.opus:null),"modelName"),Rt=l(e=>e==="opus"||e==="sonnet"?"claude":e,"providerOf");function $e(e){const t=Yn(e),{kind:n}=e,s=e.label?.replace(/\bbuilder\b/,"implementer").replace(/\bBuilder\b/,"Implementer"),r=l(d=>d[0].toLowerCase()+d.slice(1),"lower");if(t&&ee(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"}l($e,"agentName");const Mt=l((e,t)=>!!e.resolved&&(!e.resolved_at||String(e.resolved_at)>=String(t)),"resolvedSince");function zn(e,t,n=[],s=[],r=[]){const a=t.filter(v=>v.data?.id===e.id),d=a[a.length-1]||null,c=r.filter(v=>v.data?.question===e.id).at(-1),p=l((v,...T)=>!!v&&T.every(D=>String(v.ts)>String(D||"")),"after"),f=!!(e.resolved&&e.resolved_at&&d&&String(d.ts)>e.resolved_at),g=n.filter(v=>v.data?.question===e.id&&p(v,d?.ts,c?.ts)).at(-1),u=p(c,d?.ts,g?.ts,e.resolved_at),h=e.resolved&&!f&&!u,S=h?s.filter(v=>v.data?.question===e.id&&String(v.ts)>String(e.resolved_at||"")).at(-1):null,_=u?"open":h?"resolved":g?"requested":d?d.reply?"replied":"answered":"open";return{...e,state:_,reopened:u,request:g?{id:g.id,ts:g.ts,note:g.data.note||"",choice:g.data.choice||null}:null,reask:S?{id:S.id,ts:S.ts}:null,answers:a.map(v=>({ts:v.ts,choice:v.data.choice||null,note:v.data.note||"",files:v.data.files||[],reply:v.reply,acted:Mt(e,v.ts)}))}}l(zn,"ownerQuestion");const ke=l(e=>e.round??(De.test(e.url||"")?1:0),"roundOf");function Jn(e,t){const n=l((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)}l(Jn,"roundSettledBy");function Zn(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=Jn(e,n);return s?{n,state:"closed",take:s.choice}:e.some(r=>ke(r)===n&&r.state!=="resolved")?{n,state:"back"}:null}l(Zn,"roundState");function es(e){const t=e.filter(n=>De.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}l(es,"prototypesOf");const Ae=l((e,t,n)=>{const s=e.get(t);s?s.push(n):e.set(t,[n])},"add"),Ee=l((e,t)=>{const n=new Map;for(const s of e)Ae(n,t(s),s);return n},"groupBy");function ts(e,t,n=new Set){const s=new Set(e.map(d=>d.id)),r=[...e];t.some(d=>!s.has(d.topic))&&r.push({id:"",title:"Other"});const a=Ee(t,d=>s.has(d.topic)?d.topic:"");return r.map(d=>{const c=a.get(d.id)||[],p=l(u=>c.filter(h=>h.state===u).length,"count"),f=c.every(u=>u.state==="resolved")||n.has(d.id)&&!p("open"),g=c.length&&f?"resolved":"open";return{...d,state:g,questions:c.map(u=>u.id),open:p("open"),answered:p("answered"),replied:p("replied"),resolved:p("resolved"),round:Zn(c)}}).filter(d=>d.questions.length)}l(ts,"ownerTopics");const Ve={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"},qt={"grill-more":"grill","prototype-request":"prototype","visual-request":"visual","reask-request":"reask"},It={"mark-ready":"Mark ready",...Object.fromEntries(Object.entries(qt).map(([e,t])=>[e,Ve[t]]))},ns=["grill-more","prototype-request","visual-request"],ss="answers submitted",Nt={reply:"Reply",build:"Implement"},os=l(e=>Nt[e.data.intent],"intentLabel"),rs=l((e,t)=>{if(e.kind!=="prototype-request"||!t.has(e.data.question))return e.data.text||(e.data.files?.length?"":B(It,e.kind))||"";const n=t.get(e.data.question),s=(n.options||[]).find(r=>r.id===e.data.choice);return[Ct(t,n),s&&`${s.id}. ${s.label}`,e.data.note].filter(Boolean).join(`
3
- \u2192 `)},"actionText"),Dt=l((e,t)=>[...e.keys()].indexOf(t)+1,"numberOf"),Ct=l((e,t)=>`Question ${Dt(e,t.id)} \xB7 ${t.question}`,"numbered"),as="question reopened",Xe=l(e=>e.data?.shared_by?.login?{by:e.data.shared_by.name||e.data.shared_by.login}:{},"byOf"),ls=l((e,t)=>{const n=t.get(e.card);return{...e,text:`${Ve[e.command]} ${n?`${n.ref}: ${n.title}`:e.card}`,link:`#selectedCard=${encodeURIComponent(e.card)}`}},"linkLine"),Tt=l(e=>({kind:"command",command:e,request:!0,mark:Ve[e]}),"commandLine"),is=l((e,t)=>{if(e.kind==="item-message")return Nt[e.data.intent]?{status:os(e)}:{};const n={request:!0,command:qt[e.kind]};return ns.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"),dt=l(e=>[...e.filter(t=>t.who==="claude"&&!["status","agent","command",Oe,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 Lt(e,t={}){const n=new Map,s=new Map;for(const u of t.items||[])Ae(n,u.topic,u),s.set(u.id,u.topic);const r=new Map,a=new Map,d=new Map,c=new Map,p=new Map,f=new Map,g=new Map;e.forEach((u,h)=>{g.set(u,h),u.data?.key&&cn.includes(u.kind)&&Ae(r,u.data.key,u),u.kind==="owner-answer"&&s.has(u.data?.id)&&Ae(a,s.get(u.data.id),u),u.kind===kt&&s.has(u.data?.question)&&Ae(d,s.get(u.data.question),u),u.kind==="ask"&&c.set(u.id,u)});for(const u of e.filter(h=>h.kind==="ask-edited").sort((h,S)=>String(h.ts).localeCompare(String(S.ts)))){p.set(u.data?.id,u.data?.text);for(const h of u.data?.files||[])Ae(f,u.data?.id,h)}return{byKey:r,answers:a,reopens:d,asks:c,edits:p,editFiles:f,questions:n,order:g}}l(Lt,"threadIndex");const ct=l((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"),ds=/; its log is \S*\/\.claude\/kickflip\/logs\/([^/\s]+\.log)\.$/,cs=l(e=>{const t=!e.log&&typeof e.text=="string"?ds.exec(e.text):null;return t?{...e,text:`${e.text.slice(0,t.index)}.`,log:t[1]}:e},"withLog");function us(e,t){const n=t.run?e.find(s=>s.started===t.run):e.filter(s=>ee(s)===!!t.planner&&s.started&&String(s.started)<=String(t.ts)&&(!s.done||String(t.ts)<=String(s.done))).pop();return n?{agent:$e(n),run:ut(e,n),running:!n.done}:{}}l(us,"agentOfLine");function ut(e,t){return t.label!==Qe?t.started:e.filter(n=>te(n)&&n.label!==Qe&&n.started&&String(n.started)<String(t.started)).pop()?.started??t.started}l(ut,"sectionOf");function Pt(e,{lines:t=[],events:n=[],owner:s={},working:r={},fromAsk:a=null,links:d=[],agents:c={},moved:p=[],cards:f=new Map,index:g=Lt(n,s)}){const u=e.startsWith("ask:")?[e.slice(4)]:[a,...p].filter(Boolean),h=[...new Set([e,...u.map(i=>`ask:${i}`)])],S=new Map((g.questions.get(`item:${e}`)||[]).map(i=>[i.id,i])),_=g.answers.get(`item:${e}`)||[],v=new Set([...S.values()].map(i=>i.round_of).filter(Boolean)),T=at(c,!0).filter(te).map(i=>String(i.started||"")).filter(Boolean),D=new Set(_.filter(i=>Mt(S.get(i.data.id),i.ts)||v.has(i.data.id)||T.some(E=>E>String(i.ts))).map(i=>i.id)),R=at(c,!0),C=[...R.flatMap(i=>[...i.started?[{ts:i.started,who:"claude",kind:"agent",text:`${$e(i)} started`,agent:$e(i),run:ut(R,i),finished:!1,eta:i.done?null:i.eta,...i.log?{log:i.log}:{},...ee(i)?{planner:!0}:{}}]:[],...i.done?[{ts:i.done,who:"claude",kind:"agent",text:`${$e(i)} finished`,agent:$e(i),run:ut(R,i),finished:!0,eta:null,...ee(i)?{planner:!0}:{}}]:[],...i.calls.length?[{ts:i.done||i.calls.at(-1).at,who:"claude",kind:"calls",text:$e(i),calls:i.calls.map(E=>E.text),verified:i.verified}]:[]]),...t.map(cs).map(i=>i.card?ls(i,f):i).map(i=>({ts:i.ts,who:i.who||"claude",...i.log?{log:i.log}:{},...i.kind==="status"?{kind:"status",...i.planner?{planner:!0}:{},...us(R,i)}:{},...i.kind===ge||i.kind===Oe?{kind:i.kind}:{},...i.command?Tt(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(g,h.map(i=>g.byKey.get(i))).map(i=>({ts:i.ts,who:"love",via:"site",kind:i.kind,text:rs(i,S),files:i.data.files||[],eventId:i.id,reply:i.reply,...is(i,S),...Xe(i)})),..._.map(i=>{const E=[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:`${Ct(S,S.get(i.data.id))}
4
- \u2192 ${E}`,files:i.data.files||[],eventId:i.id,reply:i.reply,status:ss,...Xe(i)}}),...(g.reopens.get(`item:${e}`)||[]).map(i=>({ts:i.ts,who:"love",kind:i.kind,request:!0,mark:as,text:`Question ${Dt(S,i.data.question)} was reopened`,...Xe(i)})),...ct(g,[...new Set(u)].map(i=>g.asks.has(i)?[g.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,...p.includes(i.id)?{moved:!0}:{},...Xe(i),...typeof i.data?.from?.title=="string"?{from:i.data.from.title}:{}},...i.data?.quick===!0?[{ts:i.ts,who:"love",...Tt("implement"),text:Ve.implement}]:[],...d.map(E=>({ts:i.ts,who:"claude",kind:"ask-link",text:E.folded?`Moved to ${E.ref}: ${E.title}`:`${E.became?"Became":"Added to"} ${E.ref}`,link:`#selectedCard=${encodeURIComponent(E.key)}`,html:null,via:null}))])].sort((i,E)=>String(i.ts).localeCompare(String(E.ts))),U=dt(C),{edits:m,editFiles:A}=g;for(const i of C){if(!i.eventId)continue;(i.kind==="ask"||i.kind==="item-message")&&typeof m.get(i.eventId)=="string"&&Object.assign(i,{text:m.get(i.eventId),edited:!0,files:[...i.files,...A.get(i.eventId)||[]]});const E=i.kind==="ask"&&(d.length>0||!!i.moved);i.state=i.reply?"replied":E||D.has(i.eventId)||U>String(i.ts)?"answered":B(r,i.eventId)?"working":"waiting",i.canDelete=i.kind==="item-message"&&(i.state==="working"||i.state==="waiting"),i.canEdit=i.canDelete}return ps(C)}l(Pt,"threadOf");const jt=["waiting","working","answered","replied"];function ps(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 Ht=Object.defineProperty;var i=(e,t)=>Ht(e,"name",{value:t,configurable:!0});import{routeRecord as E}from"../hub/routes.mjs";import Vt from"node:fs";import{ticketBadge as ft,ticketIn as Xt}from"./tickets.mjs";import{prLinks as Yt,reviewLinks as zt,reviewTime as Jt,reviewersOf as Zt}from"./review.mjs";import{remoteFromInput as en}from"../hub/repos.mjs";import{reviewsOf as tn,reviewNeeds as nn,reviewActions as sn}from"./auto-review.mjs";import{cardPRs as on,hasPR as et,leastReady as rn,prKeyOf as an,prURL as ln}from"../shared/card-prs.mjs";import gt from"node:vm";import{checkWords as dn,parseCheck as cn}from"../shared/owner-check.mjs";import{buildScriptOf as un}from"./build-script.mjs";import{HUB as Fe,hubLineOf as kt}from"./hub-lines.mjs";const tt=gt.createContext({});for(const e of["ui-enums.js","ui-order.js"])gt.runInContext(Vt.readFileSync(new URL(`./public/${e}`,import.meta.url),"utf8"),tt);const{BUTTON:oe,ACTION_KIND:q,BUILDER_KIND:ce,PR_STATE:H,PHASES:mt}=tt.BoardUI,{laneOrder:pn}=tt.BoardUI,fn=["item-message","mark-ready","grill-more","prototype-request","visual-request","reask-request"],wt="question-reopen",ko=Object.freeze({todo:"Todo",progress:"In Progress",review:"In Review",done:"Done"}),Se="move",gn=10*6e4,kn=5*6e4,ht="build-refused",qe=Object.freeze({ask:"builder-ask",answer:"builder-answer"}),mn=864e5,ue=i(e=>e.lane==="done","closedLane"),wn=i(e=>`file:${e}`,"fileFold"),yt=7*mn,bt=i((e,t)=>({id:e,url:t?.workspace?`https://linear.app/${t.workspace}/issue/${e}`:null}),"linearRef"),hn=i(e=>String(e).replace(/^S(\d+)$/,"INT-$1"),"internalRef"),nt=i((e,t,n)=>Xt(n,t.ticket)?t.ticket:e.internal===!0?hn(t.id):t.id,"refOf"),yn=i((e,t,n)=>ft(e,t,n)||(t?{id:String(t),url:null,source:null}:null),"ticketOf");function bn(e,t,n,s,r,a,d,c,u){return!a&&(e.lane==="done"||t?.state==="MERGED"||t?.state==="CLOSED")?"done":(n||s)&&!c?"progress":r?"review":t?.state==="OPEN"?t.checks?.state==="fail"&&(!t.isDraft||d)?"progress":"review":t||u?"progress":"todo"}i(bn,"laneOf");const Ke="Lander",St=i(e=>e.kind!==ce.install&&e.label!==Ke,"changesCode");function Sn(e,t){return e?.state==="MERGED"||t?H.merged:e?.state==="CLOSED"?H.closed:e?.state==="OPEN"?e.isDraft?H.draft:H.open:null}i(Sn,"prStateOf");const vt=i(e=>e.pr?.status===H.closed,"unlanded"),vn=i(e=>e.some(t=>t.kind==="work")&&e.every(t=>t.lane==="done"),"finishedOf");function st(e){const t=xt(e);return t?.done&&t.handed_back?t.handed_back:null}i(st,"handedBackAt");const xt=i(e=>e.filter(t=>t?.started&&V(t)&&t.kind!==ce.install).sort((t,n)=>String(t.started).localeCompare(String(n.started))).at(-1),"newestBuild");function xn(e,t,n){return Object.fromEntries(e.map(s=>{const r=E(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"?E(n,s.name):null,github:s.github||null}]}))}i(xn,"reviewOf");function On(e,t,n,s,r,a,{held:d,needsApproval:c}){return n?.kind===ce.install?"builder":s?"checking":n?"builder":d&&e==="review"?"merge":r&&e==="review"?"owner":e==="review"&&t?.state==="OPEN"&&t.isDraft?a?"ci":"ready":e==="review"?Ot(t,c)?"merge":"reviewers":null}i(On,"waitsOnOf");const Ot=i((e,t)=>e?.reviewDecision==="APPROVED"||!t&&!["REVIEW_REQUIRED","CHANGES_REQUESTED"].includes(e?.reviewDecision),"reviewed"),De=/(^|\/)prototype-[\w-]+\.html/,$n={reviewers:"Waiting for PR reviewers",merge:"Approved, merges once CI and the merge state allow",ci:"Marked ready for review once CI passes"},Ge={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"},An=i(e=>`Verified: tap Merge to land it on ${e}`,"heldNext"),En="Fix the failing CI",$t="Tap Done once it is settled",Bn=["status","agent","ask-link","command",Se,qe.answer],At=i(e=>(e.who==="claude"||e.via==="github")&&!Bn.includes(e.kind)&&(e.kind!==Fe||kt(e).fault),"countsUnread"),_n=["lander-handoff","land-waiting"];function Rn({slug:e,itemFile:t,it:n,order:s,prs:r,repo:a,remote:d,base:c,builder:u,reachedPhase:g,agents:m,worktree:p,eta:w,thread:x,events:_,working:O,said:N,askedAt:D,topicItems:B,prSlack:T,boardReviewers:P,now:y,bumpedAt:b,holdAsk:l,closedAt:A,mergeAt:h,autoMerge:te,skipDraft:ae,tickets:G}){const X=r.map(f=>({repo:f.repo,number:f.number,url:ln(f),...f.gh||f.kept||{},status:Sn(f.gh,f.merged_at)})),F=rn(r.map(f=>f.gh)),L=r[F]?.gh||null,Y=X[F]?.status??null,z=n.lane||null,Ne=!!A&&String(A)>String(n.lane_at||"");Ne&&(n={...n,lane:"done",closed_at:A,reopened_at:void 0});const U=[n.closed_at,...r.flatMap(f=>[f.merged_at,f.gh?.mergedAt])].filter(Boolean).map(String).sort().pop()||null,j=String(U||""),Te=X.length>0&&X.every(f=>f.status===H.closed),K=(n.lane==="done"||n.reopened_at||Y===H.merged)&&!Te&&([...N.filter(f=>f.kind==="item-message").map(f=>f.ts),...D].map(String).filter(f=>f>j).sort().pop()||n.reopened_at)||void 0,ge=n.owner_step&&!Ne?String(n.owner_step):null,Ve=(n.lane==="done"||Y===H.merged)&&!Te,Le=!!K&&!!n.next&&String(n.next_at||"")>String(n.reopened_at||U||"");K&&!Le&&(n={...n,next:void 0});const Ae=st(m),Xe=!!K&&N.some(f=>String(f.ts)>j&&(f.state==="waiting"||f.state==="working")),Q=`${e}/${n.id}`,J=Zt(t,P),Ee=Object.fromEntries(Object.entries(zt(t,n,Q,B,Yt(T,r))).map(([f,W])=>[f,Jt(W.ts)])),ke=Object.values(Ee).filter(Boolean).sort()[0]||null,me=[...x.map(f=>f.ts),..._.map(f=>f.ts)].sort().pop()||null,Be=[...x.filter(f=>At({...f,who:f.who||"claude"})).map(f=>f.ts),..._.map(f=>f.reply?.at)].filter(Boolean).sort(),Z=!et(n)&&n.pushed?.branch?{branch:n.pushed.branch,at:n.pushed.at||null,host:d?.host||null}:null,ne=!et(n)&&n.merge_ready?.branch?{branch:n.merge_ready.branch,at:n.merge_ready.at||null,base:c}:null,le=!!n.rebase_run&&L?.state==="OPEN",_e=(n.rebased||[]).at(-1),Re=m.filter(f=>f.started&&!f.done&&V(f)),Pe=!!Ae&&St(xt(m));let R=bn(n,L,Re.some(St),Pe,Z||ne,!!K,ae,le,Re.length>0||!!Ae);K&&R==="todo"&&(R="progress");const Ye=R==="review"&&!!ke&&y-Date.parse(ke)>yt,Me=!!ge&&Ve&&R==="done";Me&&(R="review");let C=On(R,L,u,!!Ae&&R!=="done",Z,ae,{held:ne,needsApproval:J.length>0});const ze=C==="builder"&&L?.state==="OPEN"&&!L.isDraft,ie=R==="progress"&&!C&&L?.state==="OPEN"&&(!L.isDraft||ae),de=Me||!!K&&R==="progress"&&!C&&!ie&&!Xe&&!Le;de&&(C="owner");const we=l&&String(l.ts)>String(n.held_at||""),Ie=R==="todo"&&(we?!!l.data.hold:!!n.held),je=Ie&&(we?l.data.until:n.pick_up_at)||null,Ue=R!=="done",Je=!!b&&!(j&&String(b)<=j),o=x.filter(f=>(f.who||"claude")==="claude"&&!["status","command",Se].includes(f.kind)&&!_n.includes(f.line)).map(f=>String(f.ts)).sort().pop()||"",k=[h,ne&&n.merge_ready.tapped].filter(Boolean).map(String).sort().pop(),S=C==="merge"&&!!k&&k>o,$=x.filter(f=>(f.kind==="status"||f.kind===Fe)&&String(f.ts)>String(k)).sort((f,W)=>String(f.ts).localeCompare(String(W.ts))).at(-1),v=$?.line==="land-waiting"?`${Ge.merging} \xB7 ${$.text[0].toLowerCase()}${$.text.slice(1)}`:Ge.merging,M=x.filter(f=>!["status",Se].includes(f.kind)).sort((f,W)=>String(f.ts).localeCompare(String(W.ts))).at(-1),I=R==="todo"&&M?.line===ht?M.text:null,he=K||m.filter(V).map(f=>f.started).filter(Boolean).map(String).sort().pop()||null,se=L?.reviewDecision==="APPROVED",Ze=Z&&C==="owner"?`merge ${Z.branch} into ${c}`:ne&&C==="merge"?S?v:An(c):C==="merge"&&!te?S?v:(se?Ge:ot).waiting:C==="merge"&&!se?ot.auto:$n[C],We=Y===H.draft?`Review draft PR #${X[F].number}`:null,ye=!le&&_e?.to&&_e.to===L?.headRefOid?`Rebased onto ${_e.base||c}, pushed${L.mergeable==="MERGEABLE"?" \xB7 PR is clean again":""}`:null,be=le&&C==="checking"?m.flatMap(f=>f.calls).sort((f,W)=>String(f.at).localeCompare(String(W.at))).at(-1)?.text??null:null;return{key:Q,kind:"work",order:s,file:e,fileTitle:t.title||e,id:n.id,ref:nt(t,n,G),title:n.title,storedLane:z,created:n.created||null,reviewSince:n.review_since||ke||n.merge_ready?.at||n.pushed?.at||n.created||null,progressSince:he,closedAt:R==="done"?U:null,internal:t.internal===!0,repo:t.internal===!0&&!t.repo?null:a,lane:R,waitsOn:C,builder:C==="checking"?null:u,reachedPhase:g,agents:m,worktree:p??null,eta:w,working:O,reopened:!!K,awaitsDone:de,ownerStep:de?ge:null,ownerCheck:de&&ge&&n.owner_check?{words:dn(cn(n.owner_check.check)),broken:n.owner_check.broken||null}:null,stagedAt:R==="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:Ie,heldUntil:je,risky:!!n.risky,bumpable:Ue,bumpedAt:Ue&&Je?b:null,holdable:R!=="done",hasNotes:!!(n.plan||String(n.notes||"").trim()),finishable:R!=="done",merging:S,refusal:I,manualSteps:n.manual_steps||[],fromAsk:n.from_ask||null,unfiled:!!n.unfiled,filedHeld:!!n.filed_held,next:ze||R==="done"||C==="checking"?null:ie?En:ye||Ze||n.next||We||null,rebaseFailed:be,branch:n.branch||L?.headRefName||Z?.branch||null,pushed:R==="done"||Me?null:Z,mergeReady:R==="review"?ne:null,stale:R!=="done"&&(Ye||!!u?.stale),stalled:n.stalled?.reason||null,landStopped:R==="review"&&ne&&n.merge_ready.stopped&&String(n.merge_ready.stopped)>String(n.merge_ready.tapped||"")?{words:Rt("land"),at:n.merge_ready.stopped}:null,ticket:G?.source==="linear"&&!n.ticket&&n.linear?.length?null:yn(G,n.ticket,{repo:a}),ticketSource:G?.source||null,linear:(n.linear||[]).map(f=>G?.source==="linear"&&ft(G,f,{repo:a})||bt(f,G)),pr:X[F]||null,prs:X,reviewers:J.map(f=>f.name),review:xn(J,L||r[F]?.kept,Ee),inReviewSince:ke,threadCount:x.length+_.length,lastTs:me,othersAt:Be,grilling:Mt("grill",_,m,D),prototyping:Mt("prototype",_,m,D),storedPhase:n.phase||null,phase:null,updatedAt:L?.mergedAt||L?.updatedAt||r[F]?.merged_at||u?.at||me||null,ask:null,fold:null,action:null,install:R==="done"?null:In(n.install,L),waitFacts:Mn(n,{agents:m,thread:x,events:_,refusedAt:I?M.ts:null})}}i(Rn,"workItem");function Mn(e,{agents:t,thread:n,events:s,refusedAt:r}){const a=new Set(n.filter(g=>g.kind===qe.answer).map(g=>g.ask)),d=n.filter(g=>g.kind===qe.ask&&!a.has(g.ask)).sort((g,m)=>String(g.ts).localeCompare(String(m.ts)))[0],c=i(g=>s.filter(m=>at(m,g)).pop()?.ts||null,"requestAt"),u=n.filter(g=>(g.who||"claude")==="claude"&&!["status","agent","command",Se].includes(g.kind)&&g.line!==ht).map(g=>g.ts);return{handedBackAt:st(t),next:e.next||null,ask:d?{at:d.ts,text:d.text}:null,grillAt:c("grill"),prototypeAt:c("prototype"),refusedAt:r,unblockedAt:e.unblocked_at||null,unverified:t.some(g=>g.calls.some(m=>!g.verified||String(m.at)>String(g.verified.at))),writes:[...u,...t.flatMap(g=>[g.verified?.at,g.started])].filter(Boolean).map(String).sort()}}i(Mn,"waitFactsOf");function In(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))}}i(In,"installOf");function qn(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",!Ot(e,t)&&`review: ${String(e.reviewDecision||"none").toLowerCase().replace(/_/g," ")}`,n==="fail"&&`failing: ${r?.length?r.join(", "):"a check"}`,n==="pending"&&`pending: ${s?re(s,"check"):"checks"}`,e.mergeStateStatus!=="CLEAN"&&`merge state: ${String(e.mergeStateStatus||"unknown").toLowerCase()}`].filter(Boolean)}i(qn,"mergeBlockers");const Dn=i((e,t)=>!qn(e,{needsApproval:t}).length,"mergeable");function Cn(e,t,n){if(ue(e))return null;const s=`#selectedCard=${encodeURIComponent(e.key)}`;if(e.stalled)return{kind:q.stalled,url:s,label:`stalled: ${e.stalled}`};if(Nn(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 ${re(e.questions.open,"question")}`}}return e.waitsOn==="ready"?{kind:q.ready,url:e.pr.url,label:`Review draft PR #${e.pr.number}`}:e.kind==="ask"&&e.waitsOn==="owner"?{kind:q.done,url:s,label:e.next||$t}: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)||Dn(r,e.reviewers.length>0))?{kind:q.merge,url:s,label:"Merge"}:null}i(Cn,"actionOf");const Nn=i(e=>!!(e.questions&&e.questions.state!=="resolved"&&e.questions.open>0),"asking"),rt=new Set([q.pick,q.questions]);function Et(e){return e.questions?oe.openQuestions:null}i(Et,"actionButtonOf");const Tn=i(e=>e.kind==="work"&&e.lane==="todo"&&!e.action&&!e.unpicked,"buildableOf"),Ln=i((e,t)=>/^item:/.test(e.topic||"")&&De.test(e.url||"")&&!(e.options||[]).some(n=>n.id===t),"picksNoTake");function Pn(e,t){const n=e.filter(a=>a.topic===`item:${t}`),r=[...n.filter(a=>De.test(a.url||"")).flatMap(a=>a.answers.map(d=>({q:a,a:d,again:Ln(a,d.choice)}))),...n.filter(a=>a.request).map(a=>({q:a,a:a.request,again:!0}))].sort((a,d)=>String(a.a.ts).localeCompare(String(d.a.ts))).at(-1);return r?.again?{id:r.q.id,note:r.a.note.replace(/\s+/g," ").trim()}:null}i(Pn,"noTakePicked");const jn="Prototype again",Un=Object.freeze({[q.pick]:oe.openQuestions,[q.questions]:oe.openQuestions,[q.ready]:oe.github,[q.steps]:oe.github,[q.merge]:oe.merge,[q.done]:oe.done,[q.stalled]:oe.reply}),Wn="Merges once unblocked",Fn=i(e=>`Blocked ${[e.blockedBy.length&&`by ${e.blockedBy.map(t=>t.ref).join(", ")}`,e.blockedUntil&&`until ${e.blockedUntil}`].filter(Boolean).join(" and ")}`,"mergeBlockedWords");function Kn(e,t,n){if(e.action=Cn(e,t,n),e.mergeBlocked=e.action?.kind===q.merge&&e.blocked?Fn(e):null,e.mergeBlocked&&Object.assign(e,{action:null,next:Wn}),e.action?.kind===q.questions&&e.questions.fromAsks){Object.assign(e,{action:null,waitsOn:"owner",next:e.action.label,actionButton:Et(e),resolvedBy:null});return}e.awaitsDone&&=!e.action,e.awaitsDone||Object.assign(e,{ownerStep:null,ownerCheck:null}),e.actionButton=Et(e),e.resolvedBy=Un[e.action?.kind]||null,e.action?.kind===q.merge&&!e.mergeReady&&(e.next=(e.pr?.reviewDecision==="APPROVED"?Ge:ot).ready),e.awaitsDone&&Object.assign(e,{lane:"review",next:e.ownerStep||$t,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})}i(Kn,"placeOwnerWait");const Bt=i((e,t)=>e?e!=="todo":t.some(V),"started"),_t="none set yet";function mo(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)&&Bt(e.lane,n)}i(mo,"owesNext");function Gn(e,t=new Date){const n=new Date(e),s=n.toLocaleTimeString("en-GB",{hour:"2-digit",minute:"2-digit"});return n.toDateString()===t.toDateString()?s:`${n.getMonth()+1}/${n.getDate()} ${s}`}i(Gn,"askedLabel");function Qn(e,t,n,s,r,a,d,c){const u=t.find(h=>h.kind==="ask"&&h.eventId===e.id),g=u.files,m=c||(u.text||"").trim().split(`
2
+ `)[0]||g.map(h=>h.name).join(", ")||"Ask",p=u.state==="replied"||u.state==="answered",w=r?.state==="progress"&&!(String(a||"")>String(r.at||"")),x=!w&&(!!r||!!a),_=p&&!x&&!w&&d.open>0,O=p&&!x&&!w&&!_&&d.answered>0,N=x||p&&!w&&!_&&!O,D=p&&!s&&!r?.moved&&[...t.filter(h=>h.who==="claude"&&h.kind!=="ask-link"&&h.kind!=="status"&&h.kind!=="command").map(h=>h.ts),...t.map(h=>h.reply?.at)].filter(Boolean).sort().pop()||null,B=N||w||_||O,T=t.some(h=>h.who==="love"&&h.kind!=="ask"&&(h.state==="waiting"||h.state==="working")),P=t.filter(h=>h.who==="love"&&h.kind==="item-message").flatMap(Ce).filter(([,h])=>h==="waiting"||h==="working").map(([h])=>h),y=B?"answered":u.state,b=B?null:n||null,l=[...t.filter(At).map(h=>h.ts),...t.map(h=>h.reply?.at)].filter(Boolean).sort(),A=[...t.map(h=>h.ts),...l,...w?[r.at]:[]].filter(Boolean).sort().pop();return{key:`ask:${e.id}`,kind:"ask",order:0,file:null,fileTitle:null,id:e.id,ref:B?Gn(e.ts):"New",isNew:!B,title:m,storedLane:null,internal:!1,repo:null,lane:w?"progress":N?"done":"todo",waitsOn:w&&!T?"owner":null,builder:null,agents:[],eta:null,working:t.some(h=>Ce(h).some(([,te])=>te==="working")),deps:[],held:!1,risky:!1,bumpable:!B,bumpedAt:b,manualSteps:[],fromAsk:null,from:null,next:w&&r.next||null,hasNotes:!1,branch:null,finishable:B&&!N,linear:[],pr:null,prs:[],reviewers:[],review:{},inReviewSince:null,reviewSince:null,progressSince:w&&r.at||null,closedAt:null,threadCount:t.length,lastTs:A,othersAt:B?l:[],grilling:!1,prototyping:!1,created:e.ts,updatedAt:B?A:e.ts,ask:{eventId:e.id,state:y,askedAt:e.ts,bumpedAt:b,edited:!!u.edited,canEdit:!B,text:u.text,files:g,answerAt:D,from:u.from||null,owed:P},fold:null,action:null}}i(Qn,"askItem");const pe="visual",ve="helper",Hn=new Set(["grill","prototype",pe]),ee=i(e=>Hn.has(e.kind),"plans"),V=i(e=>!ee(e),"builds"),Vn={grill:"grilling",prototype:"prototyping"},Xn=i((e,t)=>`${e} ${t} by orchestrator`,"orchestratorDid"),Rt=i(e=>Xn(e,"stopped"),"stoppedWords"),Yn={grill:"grill-more",prototype:"prototype-request"},at=i((e,t)=>e.kind===Yn[t]&&!e.data?.question,"isRequest");function Mt(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)))}i(Mt,"planningOf");const wo=30*6e4;function ho(e,t){const n=[];for(const s of e.items){if(ue(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(d=>d.topic===`item:${s.key}`&&d.state==="requested"))n.push({key:s.key,request:a.request.id,question:a.id,since:a.request.ts})}return n}i(ho,"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:It(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===ve?{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))}i(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}i(it,"worktreeOf");function zn(e,t=[]){const n=e.filter(V).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}i(zn,"reachedPhaseOf");function Jn(e,t=[],n,s=null,r=null,a=!1){const d=e.filter(b=>b.started&&!b.done&&b.kind!==pe),c=d.every(ee),u=c?d:d.filter(V),g=u.map(b=>String(b.started||"")).sort()[0];if(g===void 0)return null;const m=t.filter(b=>b.kind==="status"&&String(b.ts)>=g&&(c||!b.planner)).sort((b,l)=>String(b.ts).localeCompare(String(l.ts))).pop(),p=u.filter(b=>b.kind!==ve).at(-1),w=u.some(b=>b.kind===ce.install)?ce.install:p?It(p.kind):"claude",x=c?null:u.find(b=>b.stopped&&String(b.stopped.at)>=String(b.started))?.stopped,_=m?.ts||g,O=x?x.at:s!==null&&s>Date.parse(_)?new Date(s).toISOString():_,N=m?m.phase||m.planner?m.text.replace(": "," \xB7 "):m.text||null:c?Vn[w]:null,D=n-Date.parse(O),B=c?null:u.find(b=>b.pause)?.pause??null,T=!c&&!x&&(r==="held"||!!B?.paused),P=c||T?null:x?!1:r,y=T?!1:P===null?D>=gn:!P;return{progress:N,phase:m?.phase||null,at:_,kind:w,planner:c,silentSince:O,stale:y,alive:P,held:T,quiet:!!B||P===!0&&!a&&D>=kn,stopped:x?Rt(x.run):null,...B?{pause:{cause:B.cause,words:B.words,paused:!!B.paused}}:{}}}i(Jn,"builderOf");const yo={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"]},Zn=15*6e4,es=i(e=>(e.agents||[]).find(t=>t.name==="main"&&t.started&&!t.done&&V(t))??null,"mainBuild"),ts=i((e,t,n,{now:s,usageHeld:r})=>e.blocked||e.held||r(n??"claude")||!!(t.until&&s<Date.parse(t.until)),"stillPaused");function bo(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 d=es(a);if(!d)continue;const{pause:c}=d;if(!c){a.builder?.phase!=="landing"&&n(d.kind??"claude")&&s.ask.push(a.key);continue}const u=ts(a,c,d.kind,{now:t,usageHeld:n});if(c.paused){u||r.push({key:a.key,at:c.paused});continue}!u&&c.cause!=="bumped"?s.drop.push(a.key):t-Date.parse(c.at)>=Zn&&s.stop.push(a.key)}return s.resume=r.sort((a,d)=>String(a.at).localeCompare(String(d.at))).map(a=>a.key),s}i(bo,"pauseWork");const dt={opus:"Claude Opus",sonnet:"Claude Sonnet",codex:"Codex"},ns=i(({model:e,kind:t})=>dt[e]||dt[t]||(t==="claude"?dt.opus:null),"modelName"),It=i(e=>e==="opus"||e==="sonnet"?"claude":e,"providerOf");function xe(e){const t=ns(e),{kind:n}=e,s=e.label?.replace(/\bbuilder\b/,"implementer").replace(/\bBuilder\b/,"Implementer"),r=i(d=>d[0].toLowerCase()+d.slice(1),"lower");if(t&&ee(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"}i(xe,"agentName");const qt=i((e,t)=>!!e.resolved&&(!e.resolved_at||String(e.resolved_at)>=String(t)),"resolvedSince");function ss(e,t,n=[],s=[],r=[]){const a=t.filter(O=>O.data?.id===e.id),d=a[a.length-1]||null,c=r.filter(O=>O.data?.question===e.id).at(-1),u=i((O,...N)=>!!O&&N.every(D=>String(O.ts)>String(D||"")),"after"),g=!!(e.resolved&&e.resolved_at&&d&&String(d.ts)>e.resolved_at),m=n.filter(O=>O.data?.question===e.id&&u(O,d?.ts,c?.ts)).at(-1),p=u(c,d?.ts,m?.ts,e.resolved_at),w=e.resolved&&!g&&!p,x=w?s.filter(O=>O.data?.question===e.id&&String(O.ts)>String(e.resolved_at||"")).at(-1):null,_=p?"open":w?"resolved":m?"requested":d?d.reply?"replied":"answered":"open";return{...e,state:_,reopened:p,request:m?{id:m.id,ts:m.ts,note:m.data.note||"",choice:m.data.choice||null}:null,reask:x?{id:x.id,ts:x.ts}:null,answers:a.map(O=>({ts:O.ts,choice:O.data.choice||null,note:O.data.note||"",files:O.data.files||[],reply:O.reply,replies:O.replies,acted:qt(e,O.ts)}))}}i(ss,"ownerQuestion");const fe=i(e=>e.round??(De.test(e.url||"")?1:0),"roundOf");function os(e,t){const n=i((s,r)=>s.confirm_of||(s.options||[]).some(a=>a.id===r.choice),"settles");return e.filter(s=>fe(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)}i(os,"roundSettledBy");function rs(e){const t=e.find(r=>r.request&&!e.some(a=>fe(a)>fe(r)));if(t)return{n:fe(t)+1,state:"making"};const n=Math.max(0,...e.map(fe));if(!n)return null;const s=os(e,n);return s?{n,state:"closed",take:s.choice}:e.some(r=>fe(r)===n&&r.state!=="resolved")?{n,state:"back"}:null}i(rs,"roundState");function as(e){const t=e.filter(n=>De.test(n.url||"")).map(n=>({n:fe(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}i(as,"prototypesOf");const Oe=i((e,t,n)=>{const s=e.get(t);s?s.push(n):e.set(t,[n])},"add"),$e=i((e,t)=>{const n=new Map;for(const s of e)Oe(n,t(s),s);return n},"groupBy");function ls(e,t,n=new Set){const s=new Set(e.map(d=>d.id)),r=[...e];t.some(d=>!s.has(d.topic))&&r.push({id:"",title:"Other"});const a=$e(t,d=>s.has(d.topic)?d.topic:"");return r.map(d=>{const c=a.get(d.id)||[],u=i(p=>c.filter(w=>w.state===p).length,"count"),g=c.every(p=>p.state==="resolved")||n.has(d.id)&&!u("open"),m=c.length&&g?"resolved":"open";return{...d,state:m,questions:c.map(p=>p.id),open:u("open"),answered:u("answered"),replied:u("replied"),resolved:u("resolved"),round:rs(c)}}).filter(d=>d.questions.length)}i(ls,"ownerTopics");const Qe={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"},Dt={"grill-more":"grill","prototype-request":"prototype","visual-request":"visual","reask-request":"reask"},Ct={"mark-ready":"Mark ready",...Object.fromEntries(Object.entries(Dt).map(([e,t])=>[e,Qe[t]]))},is=["grill-more","prototype-request","visual-request"],ds="answers submitted",Nt={reply:"Reply",build:"Implement"},cs=i(e=>Nt[e.data.intent],"intentLabel"),us=i((e,t)=>{if(e.kind!=="prototype-request"||!t.has(e.data.question))return e.data.text||(e.data.files?.length?"":E(Ct,e.kind))||"";const n=t.get(e.data.question),s=(n.options||[]).find(r=>r.id===e.data.choice);return[Lt(t,n),s&&`${s.id}. ${s.label}`,e.data.note].filter(Boolean).join(`
3
+ \u2192 `)},"actionText"),Tt=i((e,t)=>[...e.keys()].indexOf(t)+1,"numberOf"),Lt=i((e,t)=>`Question ${Tt(e,t.id)} \xB7 ${t.question}`,"numbered"),ps="question reopened",He=i(e=>e.data?.shared_by?.login?{by:e.data.shared_by.name||e.data.shared_by.login}:{},"byOf"),fs=i((e,t)=>{const n=t.get(e.card);return{...e,text:`${Qe[e.command]} ${n?`${n.ref}: ${n.title}`:e.card}`,link:`#selectedCard=${encodeURIComponent(e.card)}`}},"linkLine"),Pt=i(e=>({kind:"command",command:e,request:!0,mark:Qe[e]}),"commandLine"),gs=i((e,t)=>{if(e.kind==="item-message")return Nt[e.data.intent]?{status:cs(e)}:{};const n={request:!0,command:Dt[e.kind]};return is.includes(e.kind)?(e.data.question?t.has(e.data.question):String(e.data.text||"").trim()||e.data.files?.length)?{status:Ct[e.kind]}:n:e.kind==="reask-request"?n:{}},"requestOf"),ct=i(e=>[...e.filter(t=>t.who==="claude"&&!["status","agent","command",Se,qe.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 jt(e,t={}){const n=new Map,s=new Map;for(const p of t.items||[])Oe(n,p.topic,p),s.set(p.id,p.topic);const r=new Map,a=new Map,d=new Map,c=new Map,u=new Map,g=new Map,m=new Map;e.forEach((p,w)=>{m.set(p,w),p.data?.key&&fn.includes(p.kind)&&Oe(r,p.data.key,p),p.kind==="owner-answer"&&s.has(p.data?.id)&&Oe(a,s.get(p.data.id),p),p.kind===wt&&s.has(p.data?.question)&&Oe(d,s.get(p.data.question),p),p.kind==="ask"&&c.set(p.id,p)});for(const p of e.filter(w=>w.kind==="ask-edited").sort((w,x)=>String(w.ts).localeCompare(String(x.ts)))){u.set(p.data?.id,p.data?.text);for(const w of p.data?.files||[])Oe(g,p.data?.id,w)}return{byKey:r,answers:a,reopens:d,asks:c,edits:u,editFiles:g,questions:n,order:m}}i(jt,"threadIndex");const ut=i((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"),ks=/; its log is \S*\/\.claude\/kickflip\/logs\/([^/\s]+\.log)\.$/,ms=i(e=>{const t=!e.log&&typeof e.text=="string"?ks.exec(e.text):null;return t?{...e,text:`${e.text.slice(0,t.index)}.`,log:t[1]}:e},"withLog");function ws(e,t){const n=t.run?e.find(s=>s.started===t.run):e.filter(s=>ee(s)===!!t.planner&&s.started&&String(s.started)<=String(t.ts)&&(!s.done||String(t.ts)<=String(s.done))).pop();return n?{agent:xe(n),run:pt(e,n),running:!n.done}:{}}i(ws,"agentOfLine");function pt(e,t){return t.label!==Ke?t.started:e.filter(n=>V(n)&&n.label!==Ke&&n.started&&String(n.started)<String(t.started)).pop()?.started??t.started}i(pt,"sectionOf");function Ut(e,{lines:t=[],events:n=[],owner:s={},working:r={},fromAsk:a=null,links:d=[],agents:c={},moved:u=[],cards:g=new Map,index:m=jt(n,s)}){const p=e.startsWith("ask:")?[e.slice(4)]:[a,...u].filter(Boolean),w=[...new Set([e,...p.map(l=>`ask:${l}`)])],x=new Map((m.questions.get(`item:${e}`)||[]).map(l=>[l.id,l])),_=m.answers.get(`item:${e}`)||[],O=new Set([...x.values()].map(l=>l.round_of).filter(Boolean)),N=lt(c,!0).filter(V).map(l=>String(l.started||"")).filter(Boolean),D=new Set(_.filter(l=>qt(x.get(l.data.id),l.ts)||O.has(l.data.id)||N.some(A=>A>String(l.ts))).map(l=>l.id)),B=lt(c,!0),T=[...B.flatMap(l=>[...l.started?[{ts:l.started,who:"claude",kind:"agent",text:`${xe(l)} started`,agent:xe(l),run:pt(B,l),finished:!1,eta:l.done?null:l.eta,...l.log?{log:l.log}:{},...ee(l)?{planner:!0}:{}}]:[],...l.done?[{ts:l.done,who:"claude",kind:"agent",text:`${xe(l)} finished`,agent:xe(l),run:pt(B,l),finished:!0,eta:null,...ee(l)?{planner:!0}:{}}]:[],...l.calls.length?[{ts:l.done||l.calls.at(-1).at,who:"claude",kind:"calls",text:xe(l),calls:l.calls.map(A=>A.text),verified:l.verified}]:[]]),...t.map(ms).map(l=>l.card?fs(l,g):l).map(l=>({ts:l.ts,who:l.who||"claude",...l.log?{log:l.log}:{},...l.kind==="status"?{kind:"status",...l.planner?{planner:!0}:{},...ws(B,l)}:{},...l.kind===pe||l.kind===Se?{kind:l.kind}:{},...l.kind===Fe?{kind:Fe,line:l.line,...kt(l)}:{},...l.command?Pt(l.command):{},...l.card?{card:l.card}:{},...Object.values(qe).includes(l.kind)?{kind:l.kind,ask:l.ask}:{},text:l.text||"",html:l.html||null,link:l.link||null,via:l.via||null,...l.by?{by:l.by}:{}})),...ut(m,w.map(l=>m.byKey.get(l))).map(l=>({ts:l.ts,who:"love",via:"site",kind:l.kind,text:us(l,x),files:l.data.files||[],eventId:l.id,reply:l.reply,replies:l.replies,...gs(l,x),...He(l)})),..._.map(l=>{const A=[l.data.label||l.data.choice,l.data.note].filter(Boolean).join(" \xB7 ");return{ts:l.ts,who:"love",via:"questions",kind:l.kind,text:`${Lt(x,x.get(l.data.id))}
4
+ \u2192 ${A}`,files:l.data.files||[],eventId:l.id,reply:l.reply,replies:l.replies,status:ds,...He(l)}}),...(m.reopens.get(`item:${e}`)||[]).map(l=>({ts:l.ts,who:"love",kind:l.kind,request:!0,mark:ps,text:`Question ${Tt(x,l.data.question)} was reopened`,...He(l)})),...ut(m,[...new Set(p)].map(l=>m.asks.has(l)?[m.asks.get(l)]:[])).flatMap(l=>[{ts:l.ts,who:"love",via:"ask",kind:l.kind,text:l.data?.text||"",files:l.data?.files||[],eventId:l.id,reply:l.reply,replies:l.replies,...u.includes(l.id)?{moved:!0}:{},...He(l),...typeof l.data?.from?.title=="string"?{from:l.data.from.title}:{}},...l.data?.quick===!0?[{ts:l.ts,who:"love",...Pt("implement"),text:Qe.implement}]:[],...d.map(A=>({ts:l.ts,who:"claude",kind:"ask-link",text:A.folded?`Moved to ${A.ref}: ${A.title}`:`${A.became?"Became":"Added to"} ${A.ref}`,link:`#selectedCard=${encodeURIComponent(A.key)}`,html:null,via:null}))])].sort((l,A)=>String(l.ts).localeCompare(String(A.ts))),P=ct(T),{edits:y,editFiles:b}=m;for(const l of T){if(!l.eventId)continue;(l.kind==="ask"||l.kind==="item-message")&&typeof y.get(l.eventId)=="string"&&Object.assign(l,{text:y.get(l.eventId),edited:!0,files:[...l.files,...b.get(l.eventId)||[]]});const A=l.kind==="ask"&&(d.length>0||!!l.moved);l.state=l.reply?"replied":A||D.has(l.eventId)||P>String(l.ts)?"answered":E(r,l.eventId)?"working":"waiting",l.canDelete=l.kind==="item-message"&&(l.state==="working"||l.state==="waiting"),l.canEdit=l.canDelete}return hs(T)}i(Ut,"threadOf");const Wt=["waiting","working","answered","replied"];function hs(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(`
5
5
 
6
- `),files:s.flatMap(r=>r.files),state:s.map(r=>r.state).sort((r,a)=>jt.indexOf(r)-jt.indexOf(a))[0],reply:void 0,answers:s.map(r=>({eventId:r.eventId,state:r.state,reply:r.reply,text:r.text}))}]})}l(ps,"foldSubmits");const Ce=l(e=>(e.answers||[e]).filter(t=>t.eventId).map(t=>[t.eventId,t.state]),"stateEntries");function fs(e,t,n,s,r,a){const d=l((u,h)=>{const S=a.filter(v=>v.kind==="wave-triage"&&v.data?.[u]===h).pop(),_=r.filter(v=>v.topic===`${u}:${h}`&&(v.state==="open"||v.state==="answered")).length;return{running:!!(S&&!S.reply),questions:_}},"triageOf"),c=new Map(s.map(u=>[u.key,u])),p=l(u=>u.filter(h=>h.lane==="done"&&!bt(h)).length,"merged"),f=n.map(u=>({l:u,cards:u.keys.map(h=>c.get(h)).filter(Boolean)})).map(u=>({...u,open:!u.l.finished_at&&u.cards.some(h=>h.lane!=="done")})).sort((u,h)=>Number(u.open)-Number(h.open));for(const{l:u,cards:h}of f)for(const S of h)S.lineup={slug:u.slug,title:u.title};const g=f.filter(u=>u.open).map(({l:u,cards:h})=>({kind:"lineup",slug:u.slug,title:u.title,goal:u.goal,keys:h.map(S=>S.key),phases:u.phases.map(S=>S.filter(_=>c.has(_))).filter(S=>S.length),next:gs(h),merged:p(h),total:h.length,triage:d("lineup",u.slug)}));return e.fromWaves?[...g,...t.filter(u=>!u.finished).map(u=>({w:u,cards:s.filter(h=>h.wave===u.slug&&h.kind!=="ask")})).filter(({cards:u})=>u.length).map(({w:u,cards:h})=>({kind:"wave",slug:u.slug,title:u.title,goal:null,keys:h.map(S=>S.key),phases:null,next:null,merged:p(h),total:h.length,triage:d("wave",u.slug)}))]:g}l(fs,"waveBandsOf");function gs(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}}l(gs,"nextOf");function po(e,t,n,s){const r=e.waveBands.find(u=>u.kind==="lineup"&&u.slug===t);if(!r)return null;const a=new Map(e.items.map(u=>[u.key,u.lane])),d=r.keys.filter(u=>a.get(u)==="todo"),c=d.indexOf(n),p=c+s;if(c<0||p<0||p>=d.length)return null;[d[c],d[p]]=[d[p],d[c]];let f=0;const g=r.keys.map(u=>a.get(u)==="todo"?d[f++]:u);return f=0,r.phases.map(u=>g.slice(f,f+=u.length))}l(po,"lineupMoved");const ks=l(e=>e.phases||e.items.map(t=>[t]),"lineupSteps");function fo(e){const{owner:t={},topicItems:n={},events:s=[],threads:r={},prs:a={},working:d={}}=e,c=e.now??Date.now(),p=Lt(s,t),f=new Set(s.filter(o=>o.kind==="ask-withdrawn"&&!o.data?.key).map(o=>o.data?.id)),g=new Map(s.filter(o=>o.kind==="ask"&&!f.has(o.id)).map(o=>[o.id,o])),u=l((o,k)=>new Map(s.filter(b=>b.kind===o).sort((b,O)=>String(b.ts).localeCompare(String(O.ts))).map(b=>[b.data?.[k],b.ts])),"latest"),h=u("ask-bump","id"),S=u("card-unbump","key"),_=new Map([...u("card-bump","key")].filter(([o,k])=>!(String(S.get(o)||"")>String(k)))),v=u("card-done","key"),T=u("card-merge","key"),D=e.autoMerge===!0,R=e.tickets,C=new Map(s.filter(o=>o.kind==="card-hold").sort((o,k)=>String(o.ts).localeCompare(String(k.ts))).map(o=>[o.data?.key,o])),U=new Map,m=new Map(e.waves.flatMap(({slug:o,wave:k})=>k.items.map(b=>[`${o}/${b.id}`,{ref:Ge(k,b,R),title:b.title}]))),A=e.askLinks||{},i=new Map;for(const[o,k]of Object.entries(A))g.has(o)&&i.set(k,[...i.get(k)||[],o]);const E=[],y=[],ne=new Map,de=new Map,F=new Map,V=new Map,K=e.github?null:zt(e.remote);for(const{slug:o,wave:k,agents:b={}}of e.waves){const O=e.github||k.repo||null;E.push({slug:o,title:k.title||o,status:k.status||null,internal:!!k.internal,finished:!1,reviewers:(k.reviewers||[]).map(x=>x.name)}),k.items.forEach((x,q)=>{const I=`${o}/${x.id}`,ce=(i.get(I)||[]).filter($=>$!==x.from_ask),ue=[x.from_ask,...ce].filter($=>g.has($)),Fe=new Set(ue.map($=>`ask:${$}`)),Ke=[...B(r,I)||[],...ue.flatMap($=>B(r,`ask:${$}`)||[])];x.from_ask&&U.set(x.from_ask,[...U.get(x.from_ask)||[],{key:I,ref:Ge(k,x,R),became:!0}]);const Se=Pt(I,{lines:Ke,events:s,owner:t,working:d,fromAsk:x.from_ask||null,moved:ce,cards:m,index:p});for(const $ of Se)for(const[w,Z]of Ce($))ne.set(w,Z);de.set(I,dt(Se)),y.push(En({slug:o,wave:k,it:x,order:q,repo:O,remote:K,base:e.branch||"main",prs:tn(x,O).map($=>({...$,gh:B(a,sn($))||null})),...($=>({agents:$,builder:Xn($,B(r,I),c,e.moved?.[lt(B(b,x.id))]??null,B(e.alive,I)??null,!!e.commandRunning?.[lt(B(b,x.id))]),reachedPhase:Vn($,B(r,I)),eta:$.map(w=>w.eta).filter(Boolean).sort().pop()||null}))(at(B(b,x.id))),worktree:lt(B(b,x.id))??x.worktree?.path??null,thread:Ke,events:[...ct(p,[I,...Fe].map($=>p.byKey.get($))),...ue.map($=>g.get($))],working:Se.some($=>Ce($).some(([,w])=>w==="working")),said:Se.filter($=>$.who==="love"&&($.kind==="item-message"||$.kind==="owner-answer")),askedAt:(p.questions.get(`item:${I}`)||[]).filter($=>$.asked_at).map($=>$.asked_at),topicItems:n,prSlack:e.prSlack||{},boardReviewers:e.reviewers||[],now:c,bumpedAt:_.get(I),holdAsk:C.get(I),closedAt:v.get(I),mergeAt:T.get(I),autoMerge:D,skipDraft:e.skipDraft===!0,tickets:R}));const ve=y[y.length-1];g.has(x.from_ask)&&(ve.created=g.get(x.from_ask).ts),V.set(I,{parent:x.parent?Wt(o,x.parent):null,related:(x.related||[]).map($=>Wt(o,$))}),ve.lane==="done"&&F.set(I,ve.closedAt||String(ve.updatedAt||""))})}const L=new Map(y.map(o=>[o.key,o])),X=new Map,Y=e.try||{},Te=e.autoBuild===!0,W=["web","app"].includes(Y.kind)?Y.kind:e.waves.some(({wave:o})=>o.items.some(k=>k.install?.url))?"app":"web";for(const o of y){if(o.kind!=="work"||o.lane==="done")continue;const k=B(Y.cards,o.key)||{},b=k.head||o.pr?.headRefOid,O=W==="web"?k.sha:o.install?.sha,x=o.builder?.kind===pe.install?"running":k.state||(W==="app"&&o.install?"ready":null);o.try={kind:W,state:x,stale:!!(O&&b&&!String(b).toLowerCase().startsWith(String(O).toLowerCase())),url:W==="web"?null:o.install?.url||null,port:W==="web"&&x==="ready"&&k.https||null,sha:O||null,changes:k.ahead>0,script:k.script===!0,autoBuild:Te}}const j=Y.main,Le=j?.script&&j.sha?{slug:j.slug,branch:j.branch||"main",sha:j.sha.slice(0,7),at:j.at,kind:W,state:j.state||null,url:W==="web"?null:e.main?.install?.url||null,port:W==="web"&&j.state==="ready"&&j.https||null,pull:Y.pull?{running:Y.pull.running===!0,error:Y.pull.error||null}:null,script:ln(j.target)}:null,G=e.askProgress||{},me=u("ask-done","id"),Ye=Ee(s.filter(o=>o.kind==="owner-answer"),o=>o.data?.id),Pe=Ee(s.filter(o=>o.kind==="prototype-request"),o=>o.data?.question),Be=Ee(s.filter(o=>o.kind==="reask-request"),o=>o.data?.question),ze=Ee(s.filter(o=>o.kind===kt),o=>o.data?.question),Q=(t.items||[]).map(o=>zn(o,Ye.get(o.id)||[],Pe.get(o.id)||[],Be.get(o.id)||[],ze.get(o.id)||[])),z=new Map(Q.map(o=>[o.id,o])),_e=Ee(Q,o=>o.topic),we=l(o=>{const k=_e.get(o)||[];return{open:k.filter(b=>b.state==="open").length,answered:k.filter(b=>b.state==="answered").length}},"pendingOn");for(const o of g.values()){const k=`ask:${o.id}`,b=L.get(B(A,o.id)),O=[...U.get(o.id)||[]],x=b&&!O.some(I=>I.key===b.key);if(x&&O.push({key:b.key,ref:b.ref,title:b.title,became:!1,folded:!0}),O.length&&!x){X.set(k,O[0].key);continue}if(!x&&B(A,o.id)){X.set(k,B(A,o.id));continue}const q=Pt(k,{lines:B(r,k)||[],events:s,working:d,links:O,index:p});for(const I of q)for(const[ce,ue]of Ce(I))ne.set(ce,ue);de.set(k,dt(q)),y.push(Fn(o,q,h.get(o.id),O.length>0||!!B(A,o.id),B(G,o.id),me.get(o.id),we(`item:${k}`),B(e.askTitles||{},o.id)))}for(const o of E){const k=y.filter(b=>b.wave===o.slug);if(o.finished=yn(k),o.finished)for(const b of k)b.lane==="done"&&(b.fold=gn(o.slug))}for(const o of y)o.lineup=null;const he=new Set((t.topics||[]).map(o=>o.id)),je=e.waves.flatMap(({slug:o,wave:k})=>(k.lineups||[]).map(b=>{const O=ks(b).map(x=>x.map(q=>`${o}/${q}`));return{...b,phases:O,keys:O.flat()}})),J=l(()=>ts([...t.topics||[],...y.filter(o=>!he.has(`item:${o.key}`)).map(o=>({id:`item:${o.key}`,card:o.key,title:`${o.ref}: ${o.title}`,...o.kind==="ask"?{askedAt:o.ask.askedAt}:{}})),...je.filter(o=>!he.has(`lineup:${o.slug}`)).map(o=>({id:`lineup:${o.slug}`,title:o.title,summary:"Wave triage."})),...(e.fromWaves?E:[]).filter(o=>!he.has(`wave:${o.slug}`)).map(o=>({id:`wave:${o.slug}`,title:o.title,summary:"Wave triage."}))],Q,new Set(y.filter(fe).map(o=>`item:${o.key}`))),"topicsOf"),se=new Map(J().map(o=>[o.id,o]));for(const o of y){const k=se.get(`item:${o.key}`);if(!k){o.questions=null,o.prototypes=null;continue}const b=k.questions.filter(q=>z.get(q)?.state!=="resolved"),O=k.questions.find(q=>z.get(q)?.state==="open")||b[0]||k.questions[0],x=k.questions.map(q=>z.get(q)).filter(q=>q?.state==="open");o.questions={topic:k.id,state:k.state,open:k.open,answered:k.answered,replied:k.replied,resolved:k.resolved,first:O,askedAt:x.map(q=>q.asked_at).filter(Boolean).sort(),fromAsks:x.length>0&&x.every(q=>q.ask)},o.prototypes=es(k.questions.map(q=>z.get(q)))}const oe=new Map(y.map(o=>[o.key,o]));for(const o of y){const k=o.kind==="work"&&o.lane!=="done";o.blockedBy=k?o.deps.map(O=>oe.get(String(O).includes("/")?O:`${o.wave}/${O}`)).filter(O=>O&&O.lane!=="done"&&!O.reopened).map(Ut):[],o.blockedUntil=k?o.blockedUntil??null:null,o.blockReason=k?o.blockReason??null:null,o.blocked=o.blockedBy.length>0||!!o.blockedUntil,Un(o,z,D),o.lane==="todo"&&o.kind==="work"&&!o.held&&At(o.storedLane,o.agents)&&(o.lane="progress"),o.unpicked=o.kind==="work"&&o.lane==="todo"&&!!Cn(Q,o.key),o.kind==="work"&&(o.phase=js(o)),o.unpicked&&!o.action&&(o.next=Tn),o.buildable=Nn(o);const b=o.kind==="work"&&o.lane==="todo";if(o.unsorted=b&&(!!o.fromAsk||o.unfiled)&&!o.filedHeld&&o.phase==="new",o.ready=b&&o.phase==="ready"&&!o.blocked&&!o.action,o.staging=b&&o.phase==="staging",o.kind==="work"){const O=o.bumpedOut&&oe.get(o.bumpedOut.key);o.bumpedOut=b&&o.bumpedOut?{...o.bumpedOut,ref:O?.ref??o.bumpedOut.key.split("/").pop()}:null,o.hostHeld=!!e.hostBusy&&o.ready&&!!o.bumpedAt&&!o.held}}hs(y,oe,V);const ye=new Map((t.items||[]).map(o=>[o.id,o.topic])),Re=l(o=>o.kind==="owner-answer"?ye.has(o.data?.id)?/^item:(.+)$/.exec(ye.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"),Ue=l(o=>{const k=Re(o);return X.get(k)||k},"cardOf"),M=l(o=>{const k=o.startsWith("ask:")?o.slice(4):null,b=k&&B(G,k)?.state==="done"?B(G,k).at:null;return[v.get(o),k&&me.get(k),b,F.get(o)].filter(Boolean).sort().pop()||""},"closedAt"),Je=l(o=>{const k=Ue(o);return k===null?!o.reply:!oe.has(k)||!(M(k)<String(B(d,o.id)))?!1:ne.has(o.id)?ne.get(o.id)==="working":!o.reply&&!X.has(Re(o))&&!(String(de.get(k)||"")>String(o.ts))},"unanswered"),re=s.filter(o=>B(d,o.id)&&Je(o)).map(o=>({id:o.id,kind:o.kind,key:Ue(o),data:o.data,since:B(d,o.id)}));for(const o of y)o.working=re.some(k=>k.key===o.key),o.kind==="work"&&o.lane==="progress"&&!o.builder&&!o.next&&o.waitsOn!=="checking"&&!o.working&&(o.next=Et),o.sortAt=ys[o.lane](o)||(o.lane==="review"?null:o.updatedAt)||null;for(const o of y){if(o.kind!=="work")continue;const k=(_e.get(`item:${o.key}`)||[]).filter(O=>O.state==="answered").map(O=>O.answers.at(-1).ts).sort().pop(),b=re.filter(O=>O.key===o.key).map(O=>String(O.since)).sort()[0];o.orchestrator=!o.stalled&&(["progress","todo"].includes(o.lane)||o.waitsOn==="checking"||o.lane==="review"&&(o.stale||o.waitFacts.unblockedAt))?Gs(o,o.waitFacts,{answeredAt:k,workingSince:b}):null,delete o.waitFacts}Ns(y,s,d),Ds(y,e.screening||{}),y.sort(dn);const P=fs(e,E,je,y,Q,s),be=J(),Me=Jt({on:e.autoReview,incoming:e.incoming,records:e.reviewRecords,events:s,now:c,refs:new Map(y.filter(o=>o.kind==="work").map(o=>[o.key,o.ref]))}),ae=[...Ss(y,be,Q),...Zt(Me)],qe=new Map(ae.filter(o=>o.questions).map((o,k)=>[o.topic||`item:${o.key}`,k])),Ie=l(o=>qe.get(o.id)??qe.size,"rankOf");be.sort((o,k)=>Ie(o)-Ie(k));const Ze=new Set(ae.filter(o=>o.questions&&o.progress).map(o=>`item:${o.key}`));for(const o of be)Ze.has(o.id)&&(o.progress=!0);const We=y.filter(o=>o.ask?.answerAt).sort((o,k)=>k.ask.answerAt.localeCompare(o.ask.answerAt)).map(o=>({key:o.key,id:o.id,text:o.title,at:o.ask.answerAt}));return ms({kind:W,main:Le,remote:K&&{host:K.host,name:`${K.host}/${K.path}`},waves:E,waveBands:P,items:y,moved:Object.fromEntries(X),answers:We,owner:Q,ownerTopics:be,reviews:Me,needs:ae,working:re.length,workingOn:re,checks:bs(e,c)},e)}l(fo,"buildBoard");function ms(e,{listen:t,prompts:n}={}){const s=[...Os(n),...e.needs];return{...e,needs:s,needsSummary:xs(s),checks:{...e.checks,watcher:{listening:"running",asleep:"asleep",waking:"waking"}[t]||"stopped"}}}l(ms,"withHub");const Ut=l(e=>({key:e.key,ref:e.ref}),"linkOf"),Wt=l((e,t)=>String(t).includes("/")?String(t):`${e}/${t}`,"linkKey"),ws=l((e,t)=>e.ref.localeCompare(t.ref,void 0,{numeric:!0}),"byRef");function hs(e,t,n){const s=new Map,r=new Map,a=new Map,d=l((p,f,g)=>p.set(f,[...p.get(f)||[],g]),"add");for(const[p,f]of n){f.parent&&d(s,f.parent,p);for(const g of f.related)g!==p&&(d(r,p,g),d(r,g,p))}for(const p of e)for(const f of p.blockedBy||[])d(a,f.key,p.key);const c=l((p=[])=>[...new Set(p)].map(f=>t.get(f)).filter(Boolean).map(Ut).sort(ws),"cards");for(const p of e){const f=n.get(p.key)?.parent;p.parent=f?{key:f,ref:t.get(f)?.ref||f.slice(f.indexOf("/")+1)}:null,p.children=c(s.get(p.key)),p.related=c(r.get(p.key)),p.waitsOnIt=c(a.get(p.key))}}l(hs,"linkCards");const ys={todo:l(e=>e.created,"todo"),progress:l(e=>e.progressSince,"progress"),review:l(e=>e.reviewSince,"review"),done:l(e=>e.closedAt,"done"),asks:l(e=>e.ask.answerAt,"asks")},ie=l((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural");function bs({checked:e,watcher:t,replyAt:n,threads:s={},working:r={},waves:a=[]},d){const c=Number(e?.every)||30,f=[n,t?.since,...Object.values(r),...Object.values(s).flat().filter(u=>(u.who||"claude")==="claude").map(u=>u.ts),...a.flatMap(u=>Object.values(u.agents||{}).flatMap(h=>Object.values(h||{})).map(h=>h?.done||h?.started))].filter(u=>typeof u=="string"&&!Number.isNaN(Date.parse(u))).reduce((u,h)=>u&&Date.parse(u)>Date.parse(h)?u:h,null),g=!!e?.idle;return{at:e?.at||null,every:g?null:c,idle:g,late:!g&&!!e?.at&&d-Date.parse(e.at)>2*c*6e4,claudeAt:f}}l(bs,"checksOf");function Ss(e,t,n){const s=new Set(e.map(c=>c.questions?.topic).filter(Boolean)),r=l(c=>c.find(p=>n.find(f=>f.id===p)?.state==="open")||c[0],"firstOpen"),a=t.filter(c=>c.state!=="resolved"&&c.open>0&&!s.has(c.id)).map(c=>{const p=`questions.html#${r(c.questions)}`,f=/^(?:lineup|wave):(.+)$/.exec(c.id)?.[1]||null;return{kind:"Question",title:c.title,text:`${c.title} \xB7 ${ie(c.open,"question")}`,url:p,topic:c.id,band:f,questions:{open:c.open,url:p},ready:null,since:n.filter(g=>g.topic===c.id&&g.state==="open").map(g=>g.asked_at).filter(Boolean).sort()[0]||null}}),d=e.map(c=>{const p=c.questions&&c.questions.state!=="resolved"&&c.questions.open>0?{open:c.questions.open,url:`questions.html#${c.questions.first}`}:null,f=c.waitsOn==="ready"?c.pr.url:null,g=!p&&!f&&c.action?{label:c.action.label,url:c.action.url}:null;if(!p&&!f&&!g)return null;const u=`${c.ref}: ${c.title}`,h=[u,p&&ie(p.open,"question"),f&&"Ready on GitHub",g?.label].filter(Boolean).join(" \xB7 ");return{kind:p?"Question":f?"Tap Ready":"Action needed",title:u,text:h,url:`#selectedCard=${encodeURIComponent(c.key)}`,key:c.key,questions:p,ready:f,action:g,since:c.created||null,progress:c.lane==="progress"}}).filter(Boolean);return[...a,...d].sort(vs)}l(Ss,"needsOf");const vs=l((e,t)=>!!t.progress-!!e.progress||(e.since&&t.since?e.since.localeCompare(t.since):!!t.since-!!e.since),"oldestFirst");function Os(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}})}l(Os,"promptLines");function xs(e){const t=e.filter(a=>a.prompt).length,n=e.reduce((a,d)=>a+(d.questions?.open||0),0),s=e.filter(a=>a.ready).length,r=e.filter(a=>a.review).length;return[t&&ie(t,"prompt"),n&&ie(n,"question"),s&&`${ie(s,"draft")} waiting on Ready`,r&&`${ie(r,"review")} held`].filter(Boolean).join(" \xB7 ")}l(xs,"needsSummary");function go(e){const t=l((...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))}}l(go,"needsAnswer");const $s=l(e=>e.buildable&&e.phase==="ready"&&!e.held&&!e.blocked,"pullableCard"),As=10;function Es(e,{cap:t=As,pulled:n=[],hold:s=[],taken:r=0}={}){const a=e.filter(m=>!fe(m)),d=l((m,A)=>m.started&&!m.done&&te(m)&&!(m.kind===xe&&!m.writes)&&!(m.waits&&A.some(i=>i.name===m.waits&&!i.done)),"counts"),c=a.filter(m=>!m.stalled).reduce((m,A)=>m+(A.agents||[]).filter((i,E,y)=>d(i,y)).length,0),p=a.filter(m=>$s(m)&&!m.working).map(m=>m.key),f=a.filter(m=>n.includes(m.key)&&(p.includes(m.key)||m.buildable&&m.working)).map(m=>m.key),g=a.flatMap(m=>(m.agents||[]).filter(A=>A.kind===xe&&!A.started&&!A.done).map(A=>({key:m.key,name:A.name,writes:A.writes}))),u=Math.max(0,t-c-f.length-r),h=g.filter(m=>m.writes),S=[...g.filter(m=>!m.writes),...h.slice(0,u)].map(({key:m,name:A})=>({key:m,name:A})),_=Math.max(0,u-h.length),v=new Set(a.filter(m=>m.bumpedAt).map(m=>m.key)),T=p.filter(m=>!f.includes(m)&&!s.includes(m)),D=T.filter(m=>v.has(m)),R=[...D,...T.filter(m=>!v.has(m)).slice(0,Math.max(0,_-D.length))],C=D.slice(_),U=Bs(a,d).slice(0,C.length).map((m,A)=>({key:m,by:C[A]}));return{idle:!c&&!a.some(m=>m.waitsOn==="checking"),pullable:p,waiting:f,pulls:R,helpers:S,bumpOuts:U,pastCap:C,free:u}}l(Es,"pullOf");function Bs(e,t){const n=l(s=>{const r=s.agents||[],a=r.filter(p=>t(p,r)),[d]=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&&d.kind!==xe&&d.pid&&d.label!==Qe&&!r.some(p=>p.kind===xe&&p.started&&!p.done)?String(d.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)}l(Bs,"bumpOutsOf");function ko(e,t,n){return e.filter(s=>s.kind==="work"&&!fe(s)&&s.waitsOn!=="checking"&&!(s.agents||[]).some(r=>r.started&&!r.done)).flatMap(s=>{const r=(s.prs||[]).find(d=>d.state==="OPEN"&&d.mergeable==="CONFLICTING"&&d.repo===s.repo&&d.headRefOid),a=r&&`${r.headRefOid}@${n}`;return r&&B(t,s.key)!==a?[{key:s.key,pr:r.number,branch:r.headRefName,conflict:a}]:[]})}l(ko,"rebasesDue");const _s=3;function mo(e,{cap:t=_s}={}){const n=e.filter(d=>!fe(d)),s=n.filter(d=>(d.agents||[]).some(c=>ee(c)&&c.started&&!c.done)).length,r=n.filter(d=>d.buildable&&!["ready","staging"].includes(d.phase)&&!d.unsorted&&!d.blocked&&!d.held&&!d.working&&!d.grilling&&!d.prototyping&&!d.questions&&!(d.agents||[]).some(c=>ee(c)&&c.kind!==ge)),a=r.filter(d=>d.bumpedAt);return[...a,...r.filter(d=>!d.bumpedAt).slice(0,Math.max(0,t-s-a.length))].map(d=>d.key)}l(mo,"arrivalsOf");function wo(e){return e.filter(t=>t.kind==="work"&&t.lane==="todo"&&t.roundAt&&["grilling","prototyping"].includes(t.phase)&&!(t.agents||[]).some(n=>ee(n)&&n.kind!==ge&&n.started&&(String(n.started)>=String(t.roundAt)||!n.done))).map(t=>({key:t.key,kind:t.phase==="grilling"?"grill":"prototype"}))}l(wo,"roundsDue");const Rs=l(e=>`${ge}-${e.id}`,"visualAgent");function ho(e,t){const n=[];for(const s of e){const r=s.agents||[];if(r.some(c=>c.kind===ge&&c.started&&!c.done))continue;const a=new Set(r.map(c=>c.name)),d=t.find(c=>c.kind==="visual-request"&&c.data?.key===s.key&&!a.has(Rs(c)));d&&n.push({key:s.key,request:d})}return n}l(ho,"visualsDue");const Ms=l(e=>e.kind==="ask"?`ask:${e.id}`:e.kind==="card-added"?e.data?.key??null:e.kind==="item-message"&&String(e.data?.key||"").startsWith("ask:")?e.data.key:null,"intakeKeyOf");function qs(e,t,n){const s=e.get(n);return s?t.kind==="ask"?s.isNew:t.kind==="card-added"?s.kind==="work"&&s.unfiled:(s.ask?.owed||[]).includes(t.id):!1}l(qs,"unsorted");const Is={ask:"Sort the new task: file it with item add --from-ask, fold it with item relate-ask, or answer it with reply","item-message":"Answer the owner's message in the ask's thread: reply to it","card-added":"Link and file the card an agent added: item notes, then item set --relate and --phase"};function Ns(e,t,n){const s=new Map(e.map(a=>[a.key,a])),r=new Set;for(const a of t){const d=Ms(a);!d||r.has(d)||!qs(s,a,d)||(r.add(d),s.get(d).orchestrator={kind:"intake",since:String(a.ts),picked:B(n,a.id)||null,next:Is[a.kind]})}}l(Ns,"intakeWaits");function Ds(e,t){for(const n of e){const s=B(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`})}}l(Ds,"screenWaits");function Cs(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
- `)}l(Cs,"todoOf");function yo(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(`
6
+ `),files:s.flatMap(r=>r.files),state:s.map(r=>r.state).sort((r,a)=>Wt.indexOf(r)-Wt.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}))}]})}i(hs,"foldSubmits");const Ce=i(e=>(e.answers||[e]).filter(t=>t.eventId).map(t=>[t.eventId,t.state]),"stateEntries");function ys(e,t,n,s,r,a){const d=i((p,w)=>{const x=a.filter(O=>O.kind==="wave-triage"&&O.data?.[p]===w).pop(),_=r.filter(O=>O.topic===`${p}:${w}`&&(O.state==="open"||O.state==="answered")).length;return{running:!!(x&&!x.reply),questions:_}},"triageOf"),c=new Map(s.map(p=>[p.key,p])),u=i(p=>p.filter(w=>w.lane==="done"&&!vt(w)).length,"merged"),g=n.map(p=>({l:p,cards:p.keys.map(w=>c.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 g)for(const x of w)x.wave={slug:p.slug,title:p.title};const m=g.filter(p=>p.open).map(({l:p,cards:w})=>({kind:"wave",slug:p.slug,title:p.title,goal:p.goal,keys:w.map(x=>x.key),next:bs(w),merged:u(w),total:w.length,triage:d("wave",p.slug)}));return e.fromWaves?[...m,...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(x=>x.key),next:null,merged:u(w),total:w.length,triage:d("file",p.slug)}))]:m}i(ys,"waveBandsOf");function bs(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}}i(bs,"nextOf");const Ss=i(e=>e.items||e.phases.flat(),"waveItems");function So(e){const{owner:t={},topicItems:n={},events:s=[],threads:r={},prs:a={},working:d={}}=e,c=e.now??Date.now(),u=jt(s,t),g=new Set(s.filter(o=>o.kind==="ask-withdrawn"&&!o.data?.key).map(o=>o.data?.id)),m=new Map(s.filter(o=>o.kind==="ask"&&!g.has(o.id)).map(o=>[o.id,o])),p=i((o,k)=>new Map(s.filter(S=>S.kind===o).sort((S,$)=>String(S.ts).localeCompare(String($.ts))).map(S=>[S.data?.[k],S.ts])),"latest"),w=p("ask-bump","id"),x=p("card-unbump","key"),_=new Map([...p("card-bump","key")].filter(([o,k])=>!(String(x.get(o)||"")>String(k)))),O=p("card-done","key"),N=p("card-merge","key"),D=e.autoMerge===!0,B=e.tickets,T=new Map(s.filter(o=>o.kind==="card-hold").sort((o,k)=>String(o.ts).localeCompare(String(k.ts))).map(o=>[o.data?.key,o])),P=new Map,y=new Map(e.files.flatMap(({slug:o,itemFile:k})=>k.items.map(S=>[`${o}/${S.id}`,{ref:nt(k,S,B),title:S.title}]))),b=e.askLinks||{},l=new Map;for(const[o,k]of Object.entries(b))m.has(o)&&l.set(k,[...l.get(k)||[],o]);const A=[],h=[],te=new Map,ae=new Map,G=new Map,X=new Map,F=e.github?null:en(e.remote);for(const{slug:o,itemFile:k,agents:S={}}of e.files){const $=e.github||k.repo||null;A.push({slug:o,title:k.title||o,status:k.status||null,internal:!!k.internal,finished:!1,reviewers:(k.reviewers||[]).map(v=>v.name)}),k.items.forEach((v,M)=>{const I=`${o}/${v.id}`,he=(l.get(I)||[]).filter(f=>f!==v.from_ask),se=[v.from_ask,...he].filter(f=>m.has(f)),Ze=new Set(se.map(f=>`ask:${f}`)),We=[...E(r,I)||[],...se.flatMap(f=>E(r,`ask:${f}`)||[])];v.from_ask&&P.set(v.from_ask,[...P.get(v.from_ask)||[],{key:I,ref:nt(k,v,B),became:!0}]);const ye=Ut(I,{lines:We,events:s,owner:t,working:d,fromAsk:v.from_ask||null,moved:he,cards:y,index:u});for(const f of ye)for(const[W,Qt]of Ce(f))te.set(W,Qt);ae.set(I,ct(ye)),h.push(Rn({slug:o,itemFile:k,it:v,order:M,repo:$,remote:F,base:e.branch||"main",prs:on(v,$).map(f=>({...f,gh:E(a,an(f))||null})),...(f=>({agents:f,builder:Jn(f,E(r,I),c,e.moved?.[it(E(S,v.id))]??null,E(e.alive,I)??null,!!e.commandRunning?.[it(E(S,v.id))]),reachedPhase:zn(f,E(r,I)),eta:f.map(W=>W.eta).filter(Boolean).sort().pop()||null}))(lt(E(S,v.id))),worktree:it(E(S,v.id))??v.worktree?.path??null,thread:We,events:[...ut(u,[I,...Ze].map(f=>u.byKey.get(f))),...se.map(f=>m.get(f))],working:ye.some(f=>Ce(f).some(([,W])=>W==="working")),said:ye.filter(f=>f.who==="love"&&(f.kind==="item-message"||f.kind==="owner-answer")),askedAt:(u.questions.get(`item:${I}`)||[]).filter(f=>f.asked_at).map(f=>f.asked_at),topicItems:n,prSlack:e.prSlack||{},boardReviewers:e.reviewers||[],now:c,bumpedAt:_.get(I),holdAsk:T.get(I),closedAt:O.get(I),mergeAt:N.get(I),autoMerge:D,skipDraft:e.skipDraft===!0,tickets:B}));const be=h[h.length-1];m.has(v.from_ask)&&(be.created=m.get(v.from_ask).ts),X.set(I,{parent:v.parent?Kt(o,v.parent):null,related:(v.related||[]).map(f=>Kt(o,f))}),be.lane==="done"&&G.set(I,be.closedAt||String(be.updatedAt||""))})}const L=new Map(h.map(o=>[o.key,o])),Y=new Map,z=e.try||{},Ne=e.autoBuild===!0,U=["web","app"].includes(z.kind)?z.kind:e.files.some(({itemFile:o})=>o.items.some(k=>k.install?.url))?"app":"web";for(const o of h){if(o.kind!=="work"||o.lane==="done")continue;const k=E(z.cards,o.key)||{},S=k.head||o.pr?.headRefOid,$=U==="web"?k.sha:o.install?.sha,v=o.builder?.kind===ce.install?"running":k.state||(U==="app"&&o.install?"ready":null);o.try={kind:U,state:v,stale:!!($&&S&&!String(S).toLowerCase().startsWith(String($).toLowerCase())),url:U==="web"?null:o.install?.url||null,port:U==="web"&&v==="ready"&&k.https||null,sha:$||null,changes:k.ahead>0,script:k.script===!0,autoBuild:Ne}}const j=z.main,Te=j?.script&&j.sha?{slug:j.slug,branch:j.branch||"main",sha:j.sha.slice(0,7),at:j.at,kind:U,state:j.state||null,url:U==="web"?null:e.main?.install?.url||null,port:U==="web"&&j.state==="ready"&&j.https||null,pull:z.pull?{running:z.pull.running===!0,error:z.pull.error||null}:null,script:un(j.target)}:null,K=e.askProgress||{},ge=p("ask-done","id"),Ve=$e(s.filter(o=>o.kind==="owner-answer"),o=>o.data?.id),Le=$e(s.filter(o=>o.kind==="prototype-request"),o=>o.data?.question),Ae=$e(s.filter(o=>o.kind==="reask-request"),o=>o.data?.question),Xe=$e(s.filter(o=>o.kind===wt),o=>o.data?.question),Q=(t.items||[]).map(o=>ss(o,Ve.get(o.id)||[],Le.get(o.id)||[],Ae.get(o.id)||[],Xe.get(o.id)||[])),J=new Map(Q.map(o=>[o.id,o])),Ee=$e(Q,o=>o.topic),ke=i(o=>{const k=Ee.get(o)||[];return{open:k.filter(S=>S.state==="open").length,answered:k.filter(S=>S.state==="answered").length}},"pendingOn");for(const o of m.values()){const k=`ask:${o.id}`,S=L.get(E(b,o.id)),$=[...P.get(o.id)||[]],v=S&&!$.some(I=>I.key===S.key);if(v&&$.push({key:S.key,ref:S.ref,title:S.title,became:!1,folded:!0}),$.length&&!v){Y.set(k,$[0].key);continue}if(!v&&E(b,o.id)){Y.set(k,E(b,o.id));continue}const M=Ut(k,{lines:E(r,k)||[],events:s,working:d,links:$,index:u});for(const I of M)for(const[he,se]of Ce(I))te.set(he,se);ae.set(k,ct(M)),h.push(Qn(o,M,w.get(o.id),$.length>0||!!E(b,o.id),E(K,o.id),ge.get(o.id),ke(`item:${k}`),E(e.askTitles||{},o.id)))}for(const o of A){const k=h.filter(S=>S.file===o.slug);if(o.finished=vn(k),o.finished)for(const S of k)S.lane==="done"&&(S.fold=wn(o.slug))}for(const o of h)o.wave=null;const me=new Set((t.topics||[]).map(o=>o.id)),Be=e.files.flatMap(({slug:o,itemFile:k})=>(k.waves||[]).map(S=>({...S,keys:Ss(S).map($=>`${o}/${$}`)}))),Z=i(()=>ls([...t.topics||[],...h.filter(o=>!me.has(`item:${o.key}`)).map(o=>({id:`item:${o.key}`,card:o.key,title:`${o.ref}: ${o.title}`,...o.kind==="ask"?{askedAt:o.ask.askedAt}:{}})),...Be.filter(o=>!me.has(`wave:${o.slug}`)).map(o=>({id:`wave:${o.slug}`,title:o.title,summary:"Wave triage."})),...(e.fromWaves?A:[]).filter(o=>!me.has(`file:${o.slug}`)).map(o=>({id:`file:${o.slug}`,title:o.title,summary:"Wave triage."}))],Q,new Set(h.filter(ue).map(o=>`item:${o.key}`))),"topicsOf"),ne=new Map(Z().map(o=>[o.id,o]));for(const o of h){const k=ne.get(`item:${o.key}`);if(!k){o.questions=null,o.prototypes=null;continue}const S=k.questions.filter(M=>J.get(M)?.state!=="resolved"),$=k.questions.find(M=>J.get(M)?.state==="open")||S[0]||k.questions[0],v=k.questions.map(M=>J.get(M)).filter(M=>M?.state==="open");o.questions={topic:k.id,state:k.state,open:k.open,answered:k.answered,replied:k.replied,resolved:k.resolved,first:$,askedAt:v.map(M=>M.asked_at).filter(Boolean).sort(),fromAsks:v.length>0&&v.every(M=>M.ask)},o.prototypes=as(k.questions.map(M=>J.get(M)))}const le=new Map(h.map(o=>[o.key,o])),_e=new Map(Be.map(o=>[`wave:${o.slug}`,o.keys]));for(const o of h){const k=o.kind==="work"&&o.lane!=="done",S=new Set(o.deps.flatMap(v=>_e.get(v)||[String(v).includes("/")?v:`${o.file}/${v}`]));o.blockedBy=k?[...S].map(v=>le.get(v)).filter(v=>v&&v.lane!=="done"&&!v.reopened).map(Ft):[],o.blockedUntil=k?o.blockedUntil??null:null,o.blockReason=k?o.blockReason??null:null,o.blocked=o.blockedBy.length>0||!!o.blockedUntil,Kn(o,J,D),o.lane==="todo"&&o.kind==="work"&&!o.held&&Bt(o.storedLane,o.agents)&&(o.lane="progress"),o.unpicked=o.kind==="work"&&o.lane==="todo"&&!!Pn(Q,o.key),o.kind==="work"&&(o.phase=Qs(o)),o.unpicked&&!o.action&&(o.next=jn),o.buildable=Tn(o);const $=o.kind==="work"&&o.lane==="todo";o.unsorted=$&&(!!o.fromAsk||o.unfiled)&&!o.filedHeld&&o.phase==="new",o.ready=$&&o.phase==="ready"&&!o.blocked&&!o.action,o.staging=$&&o.phase==="staging",o.kind==="work"&&(o.hostHeld=!!e.hostBusy&&o.ready&&!!o.bumpedAt&&!o.held)}Os(h,le,X);const Re=new Map((t.items||[]).map(o=>[o.id,o.topic])),Pe=i(o=>o.kind==="owner-answer"?Re.has(o.data?.id)?/^item:(.+)$/.exec(Re.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"),R=i(o=>{const k=Pe(o);return Y.get(k)||k},"cardOf"),Ye=i(o=>{const k=o.startsWith("ask:")?o.slice(4):null,S=k&&E(K,k)?.state==="done"?E(K,k).at:null;return[O.get(o),k&&ge.get(k),S,G.get(o)].filter(Boolean).sort().pop()||""},"closedAt"),Me=i(o=>{const k=R(o);return k===null?!o.reply:!le.has(k)||!(Ye(k)<String(E(d,o.id)))?!1:te.has(o.id)?te.get(o.id)==="working":!o.reply&&!Y.has(Pe(o))&&!(String(ae.get(k)||"")>String(o.ts))},"unanswered"),C=s.filter(o=>E(d,o.id)&&Me(o)).map(o=>({id:o.id,kind:o.kind,key:R(o),data:o.data,since:E(d,o.id)}));for(const o of h)o.working=C.some(k=>k.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 h){if(o.kind!=="work")continue;const k=(Ee.get(`item:${o.key}`)||[]).filter($=>$.state==="answered").map($=>$.answers.at(-1).ts).sort().pop(),S=C.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))?zs(o,o.waitFacts,{answeredAt:k,workingSince:S}):null,delete o.waitFacts}js(h,s,d),Us(h,e.screening||{}),h.sort(pn);const ze=ys(e,A,Be,h,Q,s),ie=Z(),de=tn({on:e.autoReview,incoming:e.incoming,records:e.reviewRecords,events:s,now:c,refs:new Map(h.filter(o=>o.kind==="work").map(o=>[o.key,o.ref]))}),we=[...Es(h,ie,Q),...nn(de)],Ie=new Map(we.filter(o=>o.questions).map((o,k)=>[o.topic||`item:${o.key}`,k])),je=i(o=>Ie.get(o.id)??Ie.size,"rankOf");ie.sort((o,k)=>je(o)-je(k));const Ue=new Set(we.filter(o=>o.questions&&o.progress).map(o=>`item:${o.key}`));for(const o of ie)Ue.has(o.id)&&(o.progress=!0);const Je=h.filter(o=>o.ask?.answerAt).sort((o,k)=>k.ask.answerAt.localeCompare(o.ask.answerAt)).map(o=>({key:o.key,id:o.id,text:o.title,at:o.ask.answerAt}));return vs({kind:U,main:Te,remote:F&&{host:F.host,name:`${F.host}/${F.path}`},itemFiles:A,waveBands:ze,items:h,moved:Object.fromEntries(Y),answers:Je,owner:Q,ownerTopics:ie,reviews:de,needs:we,working:C.length,workingOn:C,checks:As(e,c)},e)}i(So,"buildBoard");function vs(e,{listen:t,prompts:n}={}){const s=[..._s(n),...e.needs];return{...e,needs:s,needsSummary:Rs(s),checks:{...e.checks,watcher:{listening:"running",asleep:"asleep",waking:"waking"}[t]||"stopped"}}}i(vs,"withHub");const Ft=i(e=>({key:e.key,ref:e.ref}),"linkOf"),Kt=i((e,t)=>String(t).includes("/")?String(t):`${e}/${t}`,"linkKey"),xs=i((e,t)=>e.ref.localeCompare(t.ref,void 0,{numeric:!0}),"byRef");function Os(e,t,n){const s=new Map,r=new Map,a=new Map,d=i((u,g,m)=>u.set(g,[...u.get(g)||[],m]),"add");for(const[u,g]of n){g.parent&&d(s,g.parent,u);for(const m of g.related)m!==u&&(d(r,u,m),d(r,m,u))}for(const u of e)for(const g of u.blockedBy||[])d(a,g.key,u.key);const c=i((u=[])=>[...new Set(u)].map(g=>t.get(g)).filter(Boolean).map(Ft).sort(xs),"cards");for(const u of e){const g=n.get(u.key)?.parent;u.parent=g?{key:g,ref:t.get(g)?.ref||g.slice(g.indexOf("/")+1)}:null,u.children=c(s.get(u.key)),u.related=c(r.get(u.key)),u.waitsOnIt=c(a.get(u.key))}}i(Os,"linkCards");const $s={todo:i(e=>e.created,"todo"),progress:i(e=>e.progressSince,"progress"),review:i(e=>e.reviewSince,"review"),done:i(e=>e.kind==="ask"?e.ask.answerAt:e.closedAt,"done")},re=i((e,t)=>`${e} ${t}${e===1?"":"s"}`,"plural");function As({checked:e,watcher:t,replyAt:n,threads:s={},working:r={},files:a=[]},d){const c=Number(e?.every)||30,g=[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),m=!!e?.idle;return{at:e?.at||null,every:m?null:c,idle:m,late:!m&&!!e?.at&&d-Date.parse(e.at)>2*c*6e4,claudeAt:g}}i(As,"checksOf");function Es(e,t,n){const s=new Set(e.map(c=>c.questions?.topic).filter(Boolean)),r=i(c=>c.find(u=>n.find(g=>g.id===u)?.state==="open")||c[0],"firstOpen"),a=t.filter(c=>c.state!=="resolved"&&c.open>0&&!s.has(c.id)).map(c=>{const u=`questions.html#${r(c.questions)}`,g=/^(?:wave|file):(.+)$/.exec(c.id)?.[1]||null;return{kind:"Question",title:c.title,text:`${c.title} \xB7 ${re(c.open,"question")}`,url:u,topic:c.id,band:g,questions:{open:c.open,url:u},ready:null,since:n.filter(m=>m.topic===c.id&&m.state==="open").map(m=>m.asked_at).filter(Boolean).sort()[0]||null}}),d=e.map(c=>{const u=c.questions&&c.questions.state!=="resolved"&&c.questions.open>0?{open:c.questions.open,url:`questions.html#${c.questions.first}`}:null,g=c.waitsOn==="ready"?c.pr.url:null,m=!u&&!g&&c.action?{label:c.action.label,url:c.action.url}:null;if(!u&&!g&&!m)return null;const p=`${c.ref}: ${c.title}`,w=[p,u&&re(u.open,"question"),g&&"Ready on GitHub",m?.label].filter(Boolean).join(" \xB7 ");return{kind:u?"Question":g?"Tap Ready":"Action needed",title:p,text:w,url:`#selectedCard=${encodeURIComponent(c.key)}`,key:c.key,questions:u,ready:g,action:m,since:c.created||null,progress:c.lane==="progress"}}).filter(Boolean);return[...a,...d].sort(Bs)}i(Es,"needsOf");const Bs=i((e,t)=>!!t.progress-!!e.progress||(e.since&&t.since?e.since.localeCompare(t.since):!!t.since-!!e.since),"oldestFirst");function _s(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}})}i(_s,"promptLines");function Rs(e){const t=e.filter(a=>a.prompt).length,n=e.reduce((a,d)=>a+(d.questions?.open||0),0),s=e.filter(a=>a.ready).length,r=e.filter(a=>a.review).length;return[t&&re(t,"prompt"),n&&re(n,"question"),s&&`${re(s,"draft")} waiting on Ready`,r&&`${re(r,"review")} held`].filter(Boolean).join(" \xB7 ")}i(Rs,"needsSummary");function vo(e){const t=i((...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))}}i(vo,"needsAnswer");const Ms=i(e=>e.buildable&&e.phase==="ready"&&!e.held&&!e.blocked,"pullableCard"),Is=10;function qs(e,{cap:t=Is,pulled:n=[],hold:s=[],taken:r=0}={}){const a=e.filter(y=>!ue(y)),d=i((y,b)=>y.started&&!y.done&&V(y)&&!(y.kind===ve&&!y.writes)&&!y.pause?.paused&&!(y.waits&&b.some(l=>l.name===y.waits&&!l.done)),"counts"),c=a.filter(y=>!y.stalled).reduce((y,b)=>y+(b.agents||[]).filter((l,A,h)=>d(l,h)).length,0),u=a.filter(y=>Ms(y)&&!y.working).map(y=>y.key),g=a.filter(y=>n.includes(y.key)&&(u.includes(y.key)||y.buildable&&y.working)).map(y=>y.key),m=a.flatMap(y=>(y.agents||[]).filter(b=>b.kind===ve&&!b.started&&!b.done).map(b=>({key:y.key,name:b.name,writes:b.writes}))),p=Math.max(0,t-c-g.length-r),w=m.filter(y=>y.writes),x=[...m.filter(y=>!y.writes),...w.slice(0,p)].map(({key:y,name:b})=>({key:y,name:b})),_=Math.max(0,p-w.length),O=new Set(a.filter(y=>y.bumpedAt).map(y=>y.key)),N=u.filter(y=>!g.includes(y)&&!s.includes(y)),D=N.filter(y=>O.has(y)),B=[...D,...N.filter(y=>!O.has(y)).slice(0,Math.max(0,_-D.length))],T=D.slice(_),P=Ds(a,d).slice(0,T.length).map((y,b)=>({key:y,by:T[b]}));return{idle:!c&&!a.some(y=>y.waitsOn==="checking"),pullable:u,waiting:g,pulls:B,helpers:x,bumpOuts:P,pastCap:T,free:p}}i(qs,"pullOf");function Ds(e,t){const n=i(s=>{const r=s.agents||[],a=r.filter(u=>t(u,r)),[d]=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&&d.kind!==ve&&d.pid&&d.label!==Ke&&!d.pause&&!r.some(u=>u.kind===ve&&u.started&&!u.done)?String(d.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)}i(Ds,"bumpOutsOf");function xo(e,t,n){return e.filter(s=>s.kind==="work"&&!ue(s)&&s.waitsOn!=="checking"&&!(s.agents||[]).some(r=>r.started&&!r.done)).flatMap(s=>{const r=(s.prs||[]).find(d=>d.state==="OPEN"&&d.mergeable==="CONFLICTING"&&d.repo===s.repo&&d.headRefOid),a=r&&`${r.headRefOid}@${n}`;return r&&E(t,s.key)!==a?[{key:s.key,pr:r.number,branch:r.headRefName,conflict:a}]:[]})}i(xo,"rebasesDue");const Cs=3;function Oo(e,{cap:t=Cs}={}){const n=e.filter(d=>!ue(d)),s=n.filter(d=>(d.agents||[]).some(c=>ee(c)&&c.started&&!c.done)).length,r=n.filter(d=>d.buildable&&!["ready","staging"].includes(d.phase)&&!d.unsorted&&!d.blocked&&!d.held&&!d.working&&!d.grilling&&!d.prototyping&&!d.questions&&!(d.agents||[]).some(c=>ee(c)&&c.kind!==pe)),a=r.filter(d=>d.bumpedAt);return[...a,...r.filter(d=>!d.bumpedAt).slice(0,Math.max(0,t-s-a.length))].map(d=>d.key)}i(Oo,"arrivalsOf");function $o(e){return e.filter(t=>t.kind==="work"&&t.lane==="todo"&&t.roundAt&&["grilling","prototyping"].includes(t.phase)&&!(t.agents||[]).some(n=>ee(n)&&n.kind!==pe&&n.started&&(String(n.started)>=String(t.roundAt)||!n.done))).map(t=>({key:t.key,kind:t.phase==="grilling"?"grill":"prototype"}))}i($o,"roundsDue");const Ns=i(e=>`${pe}-${e.id}`,"visualAgent");function Ao(e,t){const n=[];for(const s of e){const r=s.agents||[];if(r.some(c=>c.kind===pe&&c.started&&!c.done))continue;const a=new Set(r.map(c=>c.name)),d=t.find(c=>c.kind==="visual-request"&&c.data?.key===s.key&&!a.has(Ns(c)));d&&n.push({key:s.key,request:d})}return n}i(Ao,"visualsDue");const Ts=i(e=>e.kind==="ask"?`ask:${e.id}`:e.kind==="card-added"?e.data?.key??null:e.kind==="item-message"&&String(e.data?.key||"").startsWith("ask:")?e.data.key:null,"intakeKeyOf");function Ls(e,t,n){const s=e.get(n);return s?t.kind==="ask"?s.isNew:t.kind==="card-added"?s.kind==="work"&&s.unfiled:(s.ask?.owed||[]).includes(t.id):!1}i(Ls,"unsorted");const Ps={ask:"Sort the new task: file it with item add --from-ask, fold it with item relate-ask, or answer it with reply","item-message":"Answer the owner's message in the ask's thread: reply to it","card-added":"Link and file the card an agent added: item notes, then item set --relate and --phase"};function js(e,t,n){const s=new Map(e.map(a=>[a.key,a])),r=new Set;for(const a of t){const d=Ts(a);!d||r.has(d)||!Ls(s,a,d)||(r.add(d),s.get(d).orchestrator={kind:"intake",since:String(a.ts),picked:E(n,a.id)||null,next:Ps[a.kind]})}}i(js,"intakeWaits");function Us(e,t){for(const n of e){const s=E(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`})}}i(Us,"screenWaits");function Ws(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
+ `)}i(Ws,"todoOf");function Eo(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
- ${Cs(e)}`}}l(yo,"triageOf");const Ts=100,Ls=["key","kind","id","ref","title","lane","phase","wave","waveTitle","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"],bo=l(e=>Object.fromEntries(Ls.filter(t=>t in e).map(t=>[t,e[t]])),"slimDone");function So(e,t=Ts){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.wave}/${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"))}l(So,"archivedOf");const Ps={ready:"draft",ci:"draft",reviewers:"reviewers",merge:"merge"};function js(e){return e.lane==="todo"?e.unpicked?"prototyping":gt.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!==pe.install&&e.builder.phase||e.reachedPhase||"reading":e.lane==="review"?e.stale?"stale":e.waitsOn==="owner"&&e.pushed?"merge":Ps[e.waitsOn]??null:e.storedLane==="done"&&gt.done.includes(e.storedPhase)?e.storedPhase:e.prs.some(t=>t.status===H.merged)?"merged":"closed"}l(js,"phaseOf");function vo(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:Us(t,n)}]})}l(vo,"movesOf");function Us(e,t){return t==="todo"?e.held?"it is held":e.blocked?"it is blocked":"nothing builds it":e.reopened&&t==="progress"?"a message or question reopened it":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"}l(Us,"moveWhy");const Ws=l(e=>e.startsWith("ask:")?`ask-${e.slice(4)}`:`item-${e}`,"pushTag");function Oo(e){const t=l(a=>e.owner.filter(d=>d.topic===a&&d.state==="open").map(({id:d,question:c})=>({id:d,question:c})),"open"),n=[N.ready,N.merge],s=e.items.filter(a=>a.action).map(a=>{const d=ot.has(a.action.kind)?t(a.questions.topic):[];return{tag:Ws(a.key),kind:a.action.kind,title:`${a.ref}: ${a.action.label}`,body:d[0]?.question||a.title,url:d.length?a.action.url:`#selectedCard=${encodeURIComponent(a.key)}`,now:!n.includes(a.action.kind),questions:d}}),r=e.needs.filter(a=>a.topic).map(a=>{const d=t(a.topic);return{tag:`topic-${a.topic}`,kind:N.questions,title:a.text,body:d[0]?.question||a.title,url:a.url,now:!0,questions:d}});return[...s,...r,...en(e.reviews)]}l(Oo,"ownerActions");function xo(e,{pulled:t=[]}={}){return!e.items.filter(r=>!fe(r)).some(r=>r.waitsOn==="checking"||r.grilling||r.prototyping||(r.agents||[]).some(a=>!a.done))&&!e.working&&!Es(e.items,{pulled:t}).waiting.length}l(xo,"strictlyIdle");const Fs="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",Ks='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';function Gs(e,t,{answeredAt:n,workingSince:s}){const r=l(f=>e.agents.some(g=>g.kind===f&&g.started&&!g.done),"running"),a=[e.progressSince,...e.agents.map(f=>f.done)].filter(Boolean).map(String).sort().pop()||null,d=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:Ks}:n?{kind:"answer",since:n,next:"Act on the owner's answer"}:ot.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)+wt).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 ${Fs}`}: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.refusal&&t.refusedAt?{kind:"refused",since:t.refusedAt,next:e.refusal}:e.next===Et&&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(f=>f>t.unblockedAt)?{kind:"unblocked",since:t.unblockedAt,next:"Its block ended: act on what it waited for, or set its Next"}:null;if(!d?.since)return null;const c=String(d.since),p=[t.writes.find(f=>f>c),s].filter(Boolean).sort()[0]||null;return{kind:d.kind,since:c,picked:p,next:d.next,...d.daily?{daily:!0}:{}}}l(Gs,"orchestratorWaitOf");const $o=l((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 Ao(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)]}l(Ao,"orchestratorWaits");const Eo=30*6e4,Qs=15*6e4,Hs=60*6e4,Vs=1440*6e4;function Bo(e,t,n){const s=n.toISOString(),r=[],a=[];return{waits:t.map(c=>{const p=e.find(u=>u.key===c.key&&u.kind===c.kind&&u.since===c.since);if(!p)return c.picked||r.push(c.key),{...c,bumped:s};const f=c.picked?[c.picked,p.bumped].filter(Boolean).sort().pop():p.bumped||c.since,g=n-Date.parse(f)>=(c.picked?c.daily?Vs:Hs:Qs);return g&&a.push({key:c.key,ref:c.ref,kind:c.kind,since:c.since,next:c.next}),{...c,bumped:g?s:p.bumped||c.since,...p.pushed?{pushed:!0}:{}}}),added:r,again:a}}l(Bo,"waitsStep");function _o(e,t){const n=l(s=>{const r=Math.floor((t-Date.parse(s))/6e4),a=Math.floor(r/60),d=r%60;return a?`${a}h${d?` ${d}m`:""}`:`${d}m`},"age");return`still waiting on you: ${e.map(s=>`${s.ref} ${s.kind} for ${n(s.since)}: ${s.next}`).join("; ")}`}l(_o,"waitsAgainLine");const Xs=15;function Ro(e,{idle:t,now:n}){const s=n.toISOString(),r=e.last||s;return t?e.since?e.pushed||n-Date.parse(e.since)<Xs*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}}l(Ro,"idleStep");function Mo(e,t){const n=l(p=>String(p.closedAt||"")>t,"after"),s=e.filter(p=>p.kind==="work"&&p.lane==="done"&&!bt(p)&&n(p)),r=new Map;for(const p of e)p.lineup&&r.set(p.lineup.slug,[...r.get(p.lineup.slug)||[],p]);const a=[...r.values()].filter(p=>p.every(f=>f.lane==="done")&&p.some(n)).map(p=>p[0].lineup.title),d=s.slice(0,3).map(p=>p.ref).join(", ")+(s.length>3?` and ${s.length-3} more`:"");return[s.length&&`${s.length} ${s.length===1?"card":"cards"} landed: ${d}`,...a.map(p=>`${p} finished`)].filter(Boolean).join(" \xB7 ")||"Nothing closed since the last idle notification."}l(Mo,"idleSummary");export{N as ACTION_KIND,It as ACTION_LABELS,ss as ANSWERS_SUBMITTED,Ne as BUILDER_ASK,pe as BUILDER_KIND,pn as BUILDER_QUIET_AFTER,un as BUILDER_STALE_AFTER,mt as BUILD_REFUSED,le as BUTTON,Ve as COMMANDS,Vs as DAILY_REWAKE_AFTER,Ls as DONE_FIELDS,Ts as DONE_KEPT,xe as HELPER,Xs as IDLE_MINUTES,Nt as INTENT_LABELS,cn as ITEM_EVENTS,Qe as LANDER,lo as LANES,As as MAX_IMPLEMENTERS,_s as MAX_PLANNERS,Oe as MOVE,Et as NO_NEXT,Eo as ORCHESTRATOR_PUSH_AFTER,gt as PHASES,Hs as PICKED_REWAKE_AFTER,Gn as PLANNER_WORD,Tn as PROTOTYPE_AGAIN,co as PROTOTYPE_WAIT,H as PR_STATE,kt as QUESTION_REOPEN,Qs as REWAKE_AFTER,ge as VISUAL,So as archivedOf,mo as arrivalsOf,fo as buildBoard,te as builds,nt as handedBackAt,Ro as idleStep,Mo as idleSummary,po as lineupMoved,ks as lineupSteps,Rn as mergeBlockers,Yn as modelName,vo as movesOf,go as needsAnswer,Cn as noTakePicked,Qn as orchestratorDid,Ao as orchestratorWaits,io as owesNext,Oo as ownerActions,zn as ownerQuestion,Dn as picksNoTake,ee as plans,uo as prototypeWaits,Rt as providerOf,Es as pullOf,Ws as pushTag,ko as rebasesDue,Ge as refOf,ke as roundOf,Jn as roundSettledBy,wo as roundsDue,bo as slimDone,Ce as stateEntries,Bt as stoppedWords,xo as strictlyIdle,Lt as threadIndex,Pt as threadOf,Cs as todoOf,yo as triageOf,$o as triageWaitOf,bt as unlanded,Rs as visualAgent,ho as visualsDue,_o as waitsAgainLine,Bo as waitsStep,gn as waveFold,ms as withHub};
10
+ ${Ws(e)}`}}i(Eo,"triageOf");const Fs=100,Ks=["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"],Bo=i(e=>Object.fromEntries(Ks.filter(t=>t in e).map(t=>[t,e[t]])),"slimDone");function _o(e,t=Fs){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"))}i(_o,"archivedOf");const Gs={ready:"draft",ci:"draft",reviewers:"reviewers",merge:"merge"};function Qs(e){return e.lane==="todo"?e.unpicked?"prototyping":mt.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!==ce.install&&e.builder.phase||e.reachedPhase||"reading":e.lane==="review"?e.stale?"stale":e.waitsOn==="owner"&&e.pushed?"merge":Gs[e.waitsOn]??null:e.storedLane==="done"&&mt.done.includes(e.storedPhase)?e.storedPhase:e.prs.some(t=>t.status===H.merged)?"merged":"closed"}i(Qs,"phaseOf");function Ro(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:Hs(t,n),from:{lane:t.storedLane,phase:t.storedPhase}}]})}i(Ro,"movesOf");function Hs(e,t){return t==="todo"?e.held?"it is held":e.blocked?"it is blocked":"nothing builds it":e.reopened&&t==="progress"?"a message or question reopened it":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"}i(Hs,"moveWhy");const Vs=i(e=>e.startsWith("ask:")?`ask-${e.slice(4)}`:`item-${e}`,"pushTag");function Mo(e){const t=i(a=>e.owner.filter(d=>d.topic===a&&d.state==="open").map(({id:d,question:c})=>({id:d,question:c})),"open"),n=[q.ready,q.merge],s=e.items.filter(a=>a.action).map(a=>{const d=rt.has(a.action.kind)?t(a.questions.topic):[];return{tag:Vs(a.key),kind:a.action.kind,title:`${a.ref}: ${a.action.label}`,body:d[0]?.question||a.title,url:d.length?a.action.url:`#selectedCard=${encodeURIComponent(a.key)}`,now:!n.includes(a.action.kind),questions:d}}),r=e.needs.filter(a=>a.topic).map(a=>{const d=t(a.topic);return{tag:`topic-${a.topic}`,kind:q.questions,title:a.text,body:d[0]?.question||a.title,url:a.url,now:!0,questions:d}});return[...s,...r,...sn(e.reviews)]}i(Mo,"ownerActions");function Io(e,{pulled:t=[]}={}){return!e.items.filter(r=>!ue(r)).some(r=>r.waitsOn==="checking"||r.grilling||r.prototyping||(r.agents||[]).some(a=>!a.done))&&!e.working&&!qs(e.items,{pulled:t}).waiting.length}i(Io,"strictlyIdle");const Xs="item stall it with the reason when it can't go on",Gt="restart it once from its worktree with a thread line; if the restarted run goes stale too, item stall it with the reason",Ys='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';function zs(e,t,{answeredAt:n,workingSince:s}){const r=i(g=>e.agents.some(m=>m.kind===g&&m.started&&!m.done),"running"),a=[e.progressSince,...e.agents.map(g=>g.done)].filter(Boolean).map(String).sort().pop()||null,d=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:Ys}:n?{kind:"answer",since:n,next:"Act on the owner's answer"}:rt.has(e.action?.kind)?null:e.builder?.stopped?{kind:"stale",since:e.builder.silentSince,next:`${e.builder.stopped}: ${Gt}, 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 ${Gt}`}:e.lane==="review"&&e.stale?{kind:"stale",since:new Date(Date.parse(e.inReviewSince)+yt).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 ${Xs}`}: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.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(g=>g>t.unblockedAt)?{kind:"unblocked",since:t.unblockedAt,next:"Its block ended: act on what it waited for, or set its Next"}:null;if(!d?.since)return null;const c=String(d.since),u=[t.writes.find(g=>g>c),s].filter(Boolean).sort()[0]||null;return{kind:d.kind,since:c,picked:u,next:d.next,...d.daily?{daily:!0}:{}}}i(zs,"orchestratorWaitOf");const qo=i((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 Do(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)]}i(Do,"orchestratorWaits");const Co=30*6e4,Js=15*6e4,Zs=60*6e4,eo=1440*6e4;function No(e,t,n){const s=n.toISOString(),r=[],a=[];return{waits:t.map(c=>{const u=e.find(p=>p.key===c.key&&p.kind===c.kind&&p.since===c.since);if(!u)return c.picked||r.push(c.key),{...c,bumped:s};const g=c.picked?[c.picked,u.bumped].filter(Boolean).sort().pop():u.bumped||c.since,m=n-Date.parse(g)>=(c.picked?c.daily?eo:Zs:Js);return m&&a.push({key:c.key,ref:c.ref,kind:c.kind,since:c.since,next:c.next}),{...c,bumped:m?s:u.bumped||c.since,...u.pushed?{pushed:!0}:{}}}),added:r,again:a}}i(No,"waitsStep");function To(e,t){const n=i(s=>{const r=Math.floor((t-Date.parse(s))/6e4),a=Math.floor(r/60),d=r%60;return a?`${a}h${d?` ${d}m`:""}`:`${d}m`},"age");return`still waiting on you: ${e.map(s=>`${s.ref} ${s.kind} for ${n(s.since)}: ${s.next}`).join("; ")}`}i(To,"waitsAgainLine");const to=15;function Lo(e,{idle:t,now:n}){const s=n.toISOString(),r=e.last||s;return t?e.since?e.pushed||n-Date.parse(e.since)<to*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}}i(Lo,"idleStep");function Po(e,t){const n=i(u=>String(u.closedAt||"")>t,"after"),s=e.filter(u=>u.kind==="work"&&u.lane==="done"&&!vt(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(g=>g.lane==="done")&&u.some(n)).map(u=>u[0].wave.title),d=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: ${d}`,...a.map(u=>`${u} finished`)].filter(Boolean).join(" \xB7 ")||"Nothing closed since the last idle notification."}i(Po,"idleSummary");export{q as ACTION_KIND,Ct as ACTION_LABELS,ds as ANSWERS_SUBMITTED,qe as BUILDER_ASK,ce as BUILDER_KIND,kn as BUILDER_QUIET_AFTER,gn as BUILDER_STALE_AFTER,ht as BUILD_REFUSED,oe as BUTTON,Qe as COMMANDS,eo as DAILY_REWAKE_AFTER,Ks as DONE_FIELDS,Fs as DONE_KEPT,ve as HELPER,to as IDLE_MINUTES,Nt as INTENT_LABELS,fn as ITEM_EVENTS,Ke as LANDER,ko as LANES,Is as MAX_IMPLEMENTERS,Cs as MAX_PLANNERS,Se as MOVE,_t as NO_NEXT,Co as ORCHESTRATOR_PUSH_AFTER,yo as PAUSE_CLEARS,Zn as PAUSE_HARD_STOP,mt as PHASES,Zs as PICKED_REWAKE_AFTER,Vn as PLANNER_WORD,jn as PROTOTYPE_AGAIN,wo as PROTOTYPE_WAIT,H as PR_STATE,wt as QUESTION_REOPEN,Js as REWAKE_AFTER,pe as VISUAL,_o as archivedOf,Oo as arrivalsOf,So as buildBoard,V as builds,wn as fileFold,st as handedBackAt,Lo as idleStep,Po as idleSummary,qn as mergeBlockers,ns as modelName,Ro as movesOf,vo as needsAnswer,Pn as noTakePicked,Xn as orchestratorDid,Do as orchestratorWaits,mo as owesNext,Mo as ownerActions,ss as ownerQuestion,bo as pauseWork,Ln as picksNoTake,ee as plans,ho as prototypeWaits,It as providerOf,qs as pullOf,Vs as pushTag,xo as rebasesDue,nt as refOf,fe as roundOf,os as roundSettledBy,$o as roundsDue,Bo as slimDone,Ce as stateEntries,Rt as stoppedWords,Io as strictlyIdle,jt as threadIndex,Ut as threadOf,Ws as todoOf,Eo as triageOf,qo as triageWaitOf,vt as unlanded,Ns as visualAgent,Ao as visualsDue,To as waitsAgainLine,No as waitsStep,Ss as waveItems,vs as withHub};
package/board/finish.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var D=Object.defineProperty;var c=(t,a)=>D(t,"name",{value:a,configurable:!0});import H from"node:fs";import M from"node:path";import{spawnSync as I}from"node:child_process";import*as r from"./store.mjs";import{builderRepo as v,git as h,joiningLand as N,landInTurn as P,passTests as j,syncBase as x,worktreesDir as q}from"./worktree.mjs";import{readPermissions as F}from"./permissions.mjs";import{launchBuilder as L}from"./headless.mjs";import{boardAt as A}from"../hub/boards.mjs";import{boardRepo as B}from"../hub/board-repo.mjs";const $=c(t=>{throw new r.BoardError(t)},"fail"),W=c(t=>typeof t=="string"&&t.trim()?t.trim():$("--text must be non-empty text"),"said");async function C(t,a,{text:e,ownerStep:n,check:o,repo:i,onWait:d,merge:m=!1}){const l=a.split("/")[1],u=await r.recordedWorktree(t,a),{repo:p,base:b,remote:s}=v(t,{repo:i??u?.repo}),w={path:u?.path??M.join(q(),l),branch:u?.branch??l,repo:M.resolve(p),base:b},f=await r.cardName(t,a),T=await r.readBoardSettings(t),g=s?B(A(t).route).github:null;if(s&&(!g||T.prs))return z(t,a,{...w,ref:f,text:W(e)});const R=await N(f,()=>V(t,a,{tree:w,ref:f,base:b,remote:s,repo:p,settings:T,text:e,ownerStep:n,check:o,onWait:d}),{merge:m});return R.joined?await r.isFinished(t,a)?{said:"landed and done",lines:[]}:C(t,a,{text:e,ownerStep:n,check:o,repo:i,onWait:d,merge:m}):R}c(C,"finishCard");async function V(t,a,{tree:e,ref:n,base:o,remote:i,repo:d,settings:m,text:l,ownerStep:u,check:p,onWait:b}){const s=m.auto_merge||!!(await r.heldMerge(t,a))?.tapped,w=s&&await r.blockWords(t,a);w&&$(`${n} is blocked ${w}, so it can't land; it lands once nothing blocks it`),await r.checkClose(t,a,l,u,p),await r.checkCallsVerified(t,a),i&&(x(e.repo,o),h(e.repo,"branch","--unset-upstream",e.branch)),s&&await r.landingLine(t,a);const f={site:t,key:a,first:await r.landFirst(t,a)};if(await P({...e,ref:n},{hold:!s,onWait:b,queue:f,sync:c(()=>i&&x(e.repo,o),"sync")}),!s){const g=await r.setItem(t,a,{mergeReady:e.branch,ownerStep:u,check:p});return await r.appendThread(t,a,{text:l}),{said:"verified; waits for your Merge",lines:g.lines}}const T=await r.setItem(t,a,{done:!0,landed:!0,text:l,ownerStep:u,check:p});return{said:u===void 0?"landed and done":`landed; waits on the owner step "${u.trim()}"`,lines:[...T.lines,...await _(t,a,d,o)]}}c(V,"landCard");async function S(t,a,{launch:e=L}={}){(await r.heldMerge(t,a))?.tapped||$(`${a} isn't waiting on a Merge tap`);try{const{base:o}=v(t,{repo:(await r.recordedWorktree(t,a))?.repo}),i=c(d=>r.appendThread(t,a,{text:`Waiting for ${d} to land`,kind:"status"}),"onWait");return await C(t,a,{text:`Landed on ${o} on your Merge.`,onWait:i,merge:!0})}catch(o){if(!(o instanceof r.BoardError))throw o;const i=o.message.split(`
2
- `)[0];if(/^rebasing .+ conflicts in |^tests failed in /.test(i)){await r.appendThread(t,a,{text:`Not merged yet: ${i}. A lander fixes it and lands it.`});try{await e(t,{key:a,model:await r.builderModel(t,a)},{lander:!0})}catch(d){await r.appendThread(t,a,{text:`Couldn't launch the lander headless (${d.message}); land it with board.mjs land ${a}.`})}}else await r.appendThread(t,a,{text:`Not merged: ${i}. Tap Merge again.`});throw o}}c(S,"landHeld");async function _(t,a,e,n){if(!(await F(e)).pushMain)return[];const o=h(e,"push","--quiet","origin",n);if(o.ok)return[`pushed ${n} to origin`];const i=`${n} didn't reach origin: ${o.err}; push it with git -C ${e} push origin ${n}`;return await r.appendThread(t,a,{text:`Landed, but ${i}`}),[`landed, but ${i}`]}c(_,"pushBase");async function z(t,a,{path:e,branch:n,base:o,ref:i,text:d}){await r.checkCallsVerified(t,a),H.existsSync(e)||$(`no worktree at ${e}`),h(e,"status","--porcelain").out&&$(`${e} has uncommitted changes; commit them there first`),Number(h(e,"rev-list","--count",`refs/remotes/origin/${o}..HEAD`).out)===0&&$(`${n} has no commits beyond ${o}; nothing to send for review`),await j(e,{outcome:"nothing was pushed"});const{github:m}=B(A(t).route),l=m?await r.cardPR(t,a):null,u=l?h(e,"rev-parse",`refs/remotes/origin/${n}`).out:null,p=l?h(e,"push","--quiet",`--force-with-lease=refs/heads/${n}:${u}`,"origin",`HEAD:refs/heads/${n}`):h(e,"push","--quiet","origin",`HEAD:refs/heads/${n}`);if(p.ok||$(`could not push ${n} to origin: ${p.err}`),l){const g=c(E=>Number(h(e,"rev-list","--count",`refs/remotes/origin/${o}..${E}`).out),"ahead");await r.recordRebase(t,a,{from:u,to:h(e,"rev-parse","HEAD").out,replayed:g("HEAD")<=g(u)});const R=await r.setItem(t,a,{pr:l});return await r.appendThread(t,a,{text:d}),{said:`pushed ${n} to PR #${l}`,lines:R.lines}}if(!m){const g=await r.setItem(t,a,{pushed:n});return await r.appendThread(t,a,{text:d}),{said:`pushed ${n} for its merge`,lines:g.lines}}const{title:b}=await r.briefFacts(t,a),s=I("gh",["pr","create","--draft","--repo",m,"--base",o,"--head",n,"--title",`${i}: ${b}`,"--body",d],{cwd:e,encoding:"utf8"}),w=`${s.stdout||""}
3
- ${s.stderr||""}`,f=(s.status===0||/already exists/.test(w))&&/\/pull\/(\d+)/.exec(w)?.[1];f||$(`could not open a draft PR for ${n}: ${(s.stderr||s.error?.message||`gh exited ${s.status}`).trim().split(`
4
- `)[0]}`);const T=await r.setItem(t,a,{pr:Number(f)});return await r.appendThread(t,a,{text:d}),{said:`draft PR #${f} opened`,lines:T.lines}}c(z,"sendForReview");export{C as finishCard,S as landHeld};
1
+ var I=Object.defineProperty;var c=(t,a)=>I(t,"name",{value:a,configurable:!0});import P from"node:fs";import v from"node:path";import{spawnSync as q}from"node:child_process";import*as r from"./store.mjs";import{builderRepo as E,git as w,joiningLand as F,landInTurn as N,passTests as j,syncBase as A,worktreesDir as L}from"./worktree.mjs";import{readPermissions as S}from"./permissions.mjs";import{landByBuilder as T}from"./headless.mjs";import{boardAt as C}from"../hub/boards.mjs";import{boardRepo as D}from"../hub/board-repo.mjs";const b=c(t=>{throw new r.BoardError(t)},"fail"),W=c(t=>typeof t=="string"&&t.trim()?t.trim():b("--text must be non-empty text"),"said");async function H(t,a,{text:o,closing:n,ownerStep:e,check:s,repo:i,onWait:g,merge:d=!1}){r.messageText(o);const f=a.split("/")[1],u=await r.recordedWorktree(t,a),{repo:$,base:p,remote:l}=E(t,{repo:i??u?.repo}),m={path:u?.path??v.join(L(),f),branch:u?.branch??f,repo:v.resolve($),base:p},M=await r.cardName(t,a),h=await r.readBoardSettings(t),R=l?D(C(t).route).github:null;if(l&&(!R||h.prs))return _(t,a,{...m,ref:M,text:W(o)});const B=await F(M,()=>V(t,a,{tree:m,ref:M,base:p,remote:l,repo:$,settings:h,text:o,closing:n,ownerStep:e,check:s,onWait:g}),{merge:d});return B.joined?await r.isFinished(t,a)?{said:"landed and done",lines:[]}:H(t,a,{text:o,closing:n,ownerStep:e,check:s,repo:i,onWait:g,merge:d}):B}c(H,"finishCard");async function V(t,a,{tree:o,ref:n,base:e,remote:s,repo:i,settings:g,text:d,closing:f,ownerStep:u,check:$,onWait:p}){const l=g.auto_merge||!!(await r.heldMerge(t,a))?.tapped,m=l&&await r.blockWords(t,a);m&&b(`${n} is blocked ${m}, so it can't land; it lands once nothing blocks it`),await r.checkClose(t,a,d,u,$),await r.checkCallsVerified(t,a),s&&(A(o.repo,e),w(o.repo,"branch","--unset-upstream",o.branch)),l&&await r.landingLine(t,a);const M={site:t,key:a,first:await r.landFirst(t,a)};if(await N({...o,ref:n},{hold:!l,onWait:p,queue:M,sync:c(()=>s&&A(o.repo,e),"sync")}),!l){const R=await r.setItem(t,a,{mergeReady:o.branch,ownerStep:u,check:$});return await r.appendMessage(t,a,{text:d}),{said:"verified; waits for your Merge",lines:R.lines}}const h=await r.setItem(t,a,{done:!0,landed:!0,...f?{closing:f}:{text:d},ownerStep:u,check:$});return{said:u===void 0?"landed and done":`landed; waits on the owner step "${u.trim()}"`,lines:[...h.lines,...await x(t,a,i,e)]}}c(V,"landCard");async function Z(t,a,{launch:o=T}={}){(await r.heldMerge(t,a))?.tapped||b(`${a} isn't waiting on a Merge tap`);try{const{base:e}=E(t,{repo:(await r.recordedWorktree(t,a))?.repo}),s=c(i=>r.appendStatus(t,a,"land-waiting",{card:i}),"onWait");return await H(t,a,{text:`Landed on ${e} on your Merge.`,closing:["landed-on-merge",{base:e}],onWait:s,merge:!0})}catch(e){if(!(e instanceof r.BoardError))throw e;const s=e.message.split(`
2
+ `)[0];if(/^rebasing .+ conflicts in |^tests failed in /.test(s)){await r.appendStatus(t,a,"lander-handoff",{why:s});try{await o(t,{key:a,model:await r.builderModel(t,a)},{why:s})}catch(i){await r.appendStatus(t,a,"lander-failed",{error:i.message})}}else await r.appendStatus(t,a,"land-failed",{why:s});throw e}}c(Z,"landHeld");async function x(t,a,o,n){if(!(await S(o)).pushMain)return[];const e=w(o,"push","--quiet","origin",n);if(e.ok)return[`pushed ${n} to origin`];const s=`${n} didn't reach origin: ${e.err}; push it with git -C ${o} push origin ${n}`;return await r.appendStatus(t,a,"push-failed",{base:n,error:e.err}),[`landed, but ${s}`]}c(x,"pushBase");async function _(t,a,{path:o,branch:n,base:e,ref:s,text:i}){await r.checkCallsVerified(t,a),P.existsSync(o)||b(`no worktree at ${o}`),w(o,"status","--porcelain").out&&b(`${o} has uncommitted changes; commit them there first`),Number(w(o,"rev-list","--count",`refs/remotes/origin/${e}..HEAD`).out)===0&&b(`${n} has no commits beyond ${e}; nothing to send for review`),await j(o,{outcome:"nothing was pushed"});const{github:g}=D(C(t).route),d=g?await r.cardPR(t,a):null,f=d?w(o,"rev-parse",`refs/remotes/origin/${n}`).out:null,u=d?w(o,"push","--quiet",`--force-with-lease=refs/heads/${n}:${f}`,"origin",`HEAD:refs/heads/${n}`):w(o,"push","--quiet","origin",`HEAD:refs/heads/${n}`);if(u.ok||b(`could not push ${n} to origin: ${u.err}`),d){const h=c(B=>Number(w(o,"rev-list","--count",`refs/remotes/origin/${e}..${B}`).out),"ahead");await r.recordRebase(t,a,{from:f,to:w(o,"rev-parse","HEAD").out,replayed:h("HEAD")<=h(f)});const R=await r.setItem(t,a,{pr:d});return await r.appendMessage(t,a,{text:i}),{said:`pushed ${n} to PR #${d}`,lines:R.lines}}if(!g){const h=await r.setItem(t,a,{pushed:n});return await r.appendMessage(t,a,{text:i}),{said:`pushed ${n} for its merge`,lines:h.lines}}const{title:$}=await r.briefFacts(t,a),p=q("gh",["pr","create","--draft","--repo",g,"--base",e,"--head",n,"--title",`${s}: ${$}`,"--body",i],{cwd:o,encoding:"utf8"}),l=`${p.stdout||""}
3
+ ${p.stderr||""}`,m=(p.status===0||/already exists/.test(l))&&/\/pull\/(\d+)/.exec(l)?.[1];m||b(`could not open a draft PR for ${n}: ${(p.stderr||p.error?.message||`gh exited ${p.status}`).trim().split(`
4
+ `)[0]}`);const M=await r.setItem(t,a,{pr:Number(m)});return await r.appendMessage(t,a,{text:i}),{said:`draft PR #${m} opened`,lines:M.lines}}c(_,"sendForReview");export{H as finishCard,Z as landHeld};