@dendelion/paper-camp 0.10.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/app/assets/index-B6eOrr41.js +4 -0
  2. package/dist/app/assets/index-B6eOrr41.js.map +1 -0
  3. package/dist/app/assets/index-BajRXbXg.js +2 -0
  4. package/dist/app/assets/index-BajRXbXg.js.map +1 -0
  5. package/dist/app/assets/index-DAexv1XS.js +3 -0
  6. package/dist/app/assets/index-DAexv1XS.js.map +1 -0
  7. package/dist/app/assets/index-DFJlDY3W.js +2 -0
  8. package/dist/app/assets/index-DFJlDY3W.js.map +1 -0
  9. package/dist/app/assets/main-Bno8vU-0.js +288 -0
  10. package/dist/app/assets/main-Bno8vU-0.js.map +1 -0
  11. package/dist/app/assets/{main-BJGNGUiz.css → main-RP3LpwgH.css} +1 -1
  12. package/dist/app/assets/{sidebar-section-Ch50IaLb.js → sidebar-section-BrJbBK_b.js} +2 -2
  13. package/dist/app/assets/{sidebar-section-Ch50IaLb.js.map → sidebar-section-BrJbBK_b.js.map} +1 -1
  14. package/dist/app/index.html +2 -2
  15. package/dist/chunks/{roadmap.C0AQ6pUX.js → scaffold.B_3sY6Rg.js} +1935 -1588
  16. package/dist/chunks/scaffold.B_3sY6Rg.js.map +1 -0
  17. package/dist/cli/index.js +8604 -7494
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/core/git-pr/pr.d.ts +12 -1
  20. package/dist/core/git-pr/pr.d.ts.map +1 -1
  21. package/dist/core/git-pr/scopes.d.ts +3 -0
  22. package/dist/core/git-pr/scopes.d.ts.map +1 -1
  23. package/dist/core/index.d.ts +1 -0
  24. package/dist/core/index.d.ts.map +1 -1
  25. package/dist/core/index.js +94 -80
  26. package/dist/core/parse/parser.d.ts +2 -3
  27. package/dist/core/parse/parser.d.ts.map +1 -1
  28. package/dist/core/parse/schemas.d.ts +1 -0
  29. package/dist/core/parse/schemas.d.ts.map +1 -1
  30. package/dist/core/readers.d.ts.map +1 -1
  31. package/dist/core/roadmap.d.ts +7 -1
  32. package/dist/core/roadmap.d.ts.map +1 -1
  33. package/dist/core/run-order-file.d.ts +8 -0
  34. package/dist/core/run-order-file.d.ts.map +1 -0
  35. package/dist/core/run-order-file.test.d.ts +2 -0
  36. package/dist/core/run-order-file.test.d.ts.map +1 -0
  37. package/dist/core/run-order.d.ts +28 -9
  38. package/dist/core/run-order.d.ts.map +1 -1
  39. package/dist/core/scaffold/scaffold.d.ts.map +1 -1
  40. package/dist/core/scaffold/templates.d.ts +1 -1
  41. package/dist/core/scaffold/templates.d.ts.map +1 -1
  42. package/dist/core/sections.d.ts +3 -1
  43. package/dist/core/sections.d.ts.map +1 -1
  44. package/dist/core/serialize/serializer.d.ts +7 -3
  45. package/dist/core/serialize/serializer.d.ts.map +1 -1
  46. package/dist/core/trail.d.ts +7 -0
  47. package/dist/core/trail.d.ts.map +1 -0
  48. package/dist/core/trail.test.d.ts +2 -0
  49. package/dist/core/trail.test.d.ts.map +1 -0
  50. package/dist/types/index.d.ts +174 -10
  51. package/dist/types/index.d.ts.map +1 -1
  52. package/dist/types/index.js.map +1 -1
  53. package/package.json +4 -3
  54. package/dist/app/assets/index-BnXxehKU.js +0 -2
  55. package/dist/app/assets/index-BnXxehKU.js.map +0 -1
  56. package/dist/app/assets/index-C2kYil0S.js +0 -3
  57. package/dist/app/assets/index-C2kYil0S.js.map +0 -1
  58. package/dist/app/assets/index-CRRHTP77.js +0 -2
  59. package/dist/app/assets/index-CRRHTP77.js.map +0 -1
  60. package/dist/app/assets/index-DrNAzLuW.js +0 -2
  61. package/dist/app/assets/index-DrNAzLuW.js.map +0 -1
  62. package/dist/app/assets/main-CyxblUnu.js +0 -233
  63. package/dist/app/assets/main-CyxblUnu.js.map +0 -1
  64. package/dist/chunks/roadmap.C0AQ6pUX.js.map +0 -1
@@ -0,0 +1,4 @@
1
+ import{u as R,x as O,r as c,g as B,j as e,J as _,s as i,Y as W,b,c as z,Z as S,H as V,I as q,a as G,F as H,K as I,P,f as N,M as L,p as $,O as w,S as v,L as K,X as E,N as U,q as J,Q as X,R as Y}from"./main-Bno8vU-0.js";import{T as ve}from"./main-Bno8vU-0.js";const k="__no-subject__",Z=({horizonTitle:t,item:a,candidateName:s,onClose:o,onPromoted:l})=>{const p=R(n=>n.promoteRoadmapItem),d=R(n=>n.launchIdeaExtend),{subjects:y,available:m}=O(),[f,h]=c.useState(k),[g,j]=c.useState(!1),[x,C]=c.useState(null),{toast:A}=B();c.useEffect(()=>{a&&(h(s?a.name:k),j(!1),C(null))},[a,s]);const D=async()=>{if(!(!a||!t)){j(!0),C(null);try{const n=await p(t,a,f===k?void 0:f,s??void 0),r=R.getState().ideaEntries.find(u=>u.id===n);if(r)try{await d(n,V(r,t))}catch(u){A({title:"Idea created, but the refine agent failed to launch",description:q(u.message),variant:"error"})}l(),o()}catch(n){C(n.message)}finally{j(!1)}}};return e.jsx(_,{open:a!==null,onClose:o,title:s??(a==null?void 0:a.name)??"",size:"small",children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[4]},children:[!s&&e.jsx("p",{style:{margin:0,opacity:.8},children:a==null?void 0:a.description}),e.jsx("div",{children:e.jsx(W,{size:"small",value:f,onChange:h,disabled:g||!m,options:[{value:k,label:"No subject"},...!m&&f!==k?[{value:f,label:f}]:[],...y.map(n=>({value:n,label:n}))]})}),x&&e.jsx("p",{style:{margin:0,color:z.accentRoseDark,fontSize:b.sm},children:x}),e.jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:i[2]},children:[e.jsx(S,{type:"button",variant:"ghost",onClick:o,disabled:g,children:"Cancel"}),e.jsx(S,{type:"button",variant:"primary",onClick:D,disabled:g,children:g?"Promoting…":"Promote to idea"})]})]})})},Q=t=>({shipped:t.filter(a=>a.status==="done").length,queued:t.filter(a=>a.status!=="done"&&a.status!=="dropped").length}),T={fontFamily:N.handwritten,fontSize:b.md,fontWeight:600,opacity:.7,lineHeight:1,padding:`${i[2]} ${i[1]} 0`},M={fontFamily:N.body,fontSize:b["2xs"],fontWeight:400,opacity:.5,padding:`0 ${i[1]}`},ee=({size:t=14})=>e.jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),te=({name:t,onPromote:a})=>e.jsx($,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:i[3]},children:[e.jsx("span",{style:{flex:1},children:t}),e.jsx(S,{type:"button",variant:"ghost",size:"small",onClick:a,children:"Promote to idea"})]})}),ae=({onAdd:t})=>{const[a,s]=c.useState(""),[o,l]=c.useState(!1),p=async()=>{if(a.trim()){l(!0);try{await t(a.trim()),s("")}finally{l(!1)}}};return e.jsxs("div",{style:{display:"flex",gap:i[2]},children:[e.jsx(E,{size:"small",value:a,onChange:d=>s(d.target.value),onKeyDown:d=>{d.key==="Enter"&&p()},placeholder:"Add candidate…",disabled:o,style:{flex:1}}),e.jsx(S,{type:"button",variant:"ghost",size:"small",onClick:p,disabled:o||!a.trim(),children:"Add"})]})},se=({onAdd:t})=>{const[a,s]=c.useState(!1),[o,l]=c.useState(""),[p,d]=c.useState(""),[y,m]=c.useState(!1),f=async()=>{if(o.trim()){m(!0);try{await t(o.trim(),p.trim()),l(""),d(""),s(!1)}finally{m(!1)}}};return a?e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[2]},children:[e.jsx(E,{size:"small",value:o,onChange:h=>l(h.target.value),placeholder:"Item name…",disabled:y,autoFocus:!0}),e.jsx(E,{size:"small",value:p,onChange:h=>d(h.target.value),onKeyDown:h=>{h.key==="Enter"&&f()},placeholder:"Description…",disabled:y}),e.jsxs("div",{style:{display:"flex",justifyContent:"flex-end",gap:i[2]},children:[e.jsx(S,{type:"button",variant:"ghost",size:"small",onClick:()=>s(!1),disabled:y,children:"Cancel"}),e.jsx(S,{type:"button",variant:"secondary",size:"small",onClick:f,disabled:y||!o.trim(),children:"Add"})]})]}):e.jsx(S,{type:"button",variant:"ghost",size:"small",onClick:()=>s(!0),children:"+ Add item"})},le=(t,a)=>`${t} ${a}${t===1?"":"s"}`,ne=({link:t})=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:i[1]},children:[e.jsx(J,{content:`${le(t.taskRuns,"task run")}${t.released?" · released":""}`,children:e.jsx(w,{size:"small",fillColor:v[t.status].fill,textColor:v[t.status].text,children:t.id})}),t.pr&&e.jsx(X,{pr:t.pr})]}),ie=({plan:t,onOpen:a})=>e.jsx($,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("button",{type:"button",onClick:a,style:{display:"flex",alignItems:"center",gap:i[3],width:"100%",background:"none",border:"none",padding:0,cursor:"pointer",font:"inherit",color:"inherit",textAlign:"left"},children:[e.jsx("span",{style:{flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:t.title}),e.jsx(w,{size:"small",fillColor:v[t.status].fill,textColor:v[t.status].text,children:Y[t.status]})]})}),oe=({item:t,graduated:a,highlighted:s,onPromote:o,onPromoteCandidate:l,onAddCandidate:p,onViewGraduated:d,onOpenGraduated:y})=>{const[m,f]=c.useState(s),h=t.candidates.length>0,{shipped:g,queued:j}=Q(a);return e.jsxs("div",{className:s?"roadmap-item-highlighted":void 0,style:{display:"flex",flexDirection:"column",gap:i[1]},children:[e.jsx($,{size:"small",texture:"canvas",className:"plan-row-card",children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[1]},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:i[2]},children:[e.jsx("button",{type:"button","aria-expanded":m,"aria-label":m?"Collapse item":"Expand item",onClick:()=>f(x=>!x),style:{display:"inline-flex",alignItems:"center",background:"none",border:"none",cursor:"pointer",opacity:.5,padding:0,transform:m?"rotate(90deg)":void 0},children:e.jsx(ee,{})}),e.jsx("span",{style:{fontWeight:600,flex:1},children:t.name}),e.jsx(S,{type:"button",variant:"ghost",size:"small",onClick:o,children:"Promote to idea"})]}),e.jsx("span",{className:m?void 0:"roadmap-item-desc",style:{fontSize:b.sm,opacity:.7},children:t.description}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:i[1]},children:[(j>0||g>0)&&e.jsxs("button",{type:"button",onClick:d,style:{display:"flex",alignItems:"center",gap:i[1],background:"none",border:"none",padding:0,cursor:"pointer"},children:[j>0&&e.jsxs(w,{size:"small",fillColor:v.planned.fill,textColor:v.planned.text,children:[j," in queue"]}),g>0&&e.jsxs(w,{size:"small",fillColor:v.done.fill,textColor:v.done.text,children:[g," shipped"]})]}),h&&e.jsxs(w,{size:"small",fillColor:"rgba(0, 0, 0, 0.06)",textColor:"rgba(0, 0, 0, 0.55)",children:[t.candidates.length," candidate",t.candidates.length===1?"":"s"]}),t.rollup.total>0&&e.jsxs(w,{size:"small",fillColor:v.planned.fill,textColor:v.planned.text,children:[t.rollup.done,"/",t.rollup.total," done"]})]}),t.links.length>0&&e.jsx("div",{style:{display:"flex",alignItems:"center",gap:i[1],flexWrap:"wrap"},children:t.links.map(x=>e.jsx(ne,{link:x},x.id))})]})}),m&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[1],paddingLeft:i[6]},children:[t.candidates.map(x=>e.jsx(te,{name:x,onPromote:()=>l(x)},x)),a.map(x=>e.jsx(ie,{plan:x,onOpen:()=>y(x.title)},x.title)),e.jsx(ae,{onAdd:p})]})]})},de=({goal:t})=>{const[a,s]=c.useState(!1),[o,...l]=t.split(/\n{2,}/),p=l.length>0;return e.jsxs("div",{style:{marginBottom:i[6],paddingBottom:i[4],borderBottom:"1px solid rgba(0, 0, 0, 0.08)"},children:[e.jsx("span",{style:{fontFamily:N.handwritten,fontSize:b.xs,fontWeight:600,opacity:.55},children:"The goal"}),e.jsxs("div",{style:{fontFamily:N.serif,fontSize:b.lg,lineHeight:1.4,marginTop:i[2]},children:[e.jsx("div",{className:a?void 0:"roadmap-goal-line-clamp",children:e.jsx(L,{children:o})}),a&&p&&e.jsx(L,{children:l.join(`
2
+
3
+ `)})]}),p&&e.jsx("button",{type:"button",onClick:()=>s(d=>!d),style:{background:"none",border:"none",padding:0,marginTop:i[2],cursor:"pointer",fontSize:b["2xs"],opacity:.65,textDecoration:"underline"},children:a?"Show less":"Show more"})]})},re=[{id:"tree",label:"Tree"},{id:"map",label:"Map"},{id:"timeline",label:"Timeline"}],ce=({mode:t,onChange:a})=>e.jsx("nav",{"aria-label":"Roadmap view",style:{display:"flex",gap:i[1],marginBottom:i[4]},children:re.map(s=>e.jsx(S,{type:"button",variant:"ghost",size:"small",isActive:t===s.id,"aria-pressed":t===s.id,onClick:()=>a(s.id),children:s.label},s.id))}),F=({items:t,graduatedByItem:a})=>{const s=t.filter(l=>a(l).length>0).length,o=t.length-s;return e.jsxs("div",{style:M,children:[s," graduated · ",o," charted"]})},pe={created:z.accentSlate,"task-run":z.accentAmber},xe=({events:t,rangeStart:a,rangeEnd:s})=>{const o=s-a||1;return e.jsx("div",{className:"roadmap-timeline-track",children:t.map((l,p)=>e.jsx("button",{type:"button",className:"roadmap-timeline-dot",style:{left:`${(Date.parse(l.date)-a)/o*100}%`,background:pe[l.kind]},title:`${l.itemName} — ${l.label} (${l.date})`,"aria-label":`${l.itemName} — ${l.label} (${l.date})`},`${l.entityId}-${l.kind}-${p}`))})},me=({item:t})=>{const a=t.rollup.total>0?Math.round(t.rollup.done/t.rollup.total*100):0;return e.jsxs("div",{className:"roadmap-map-item",children:[e.jsx("div",{style:{fontWeight:600,fontSize:b.sm},children:t.name}),e.jsx("div",{className:"roadmap-map-progress-track",children:e.jsx("div",{className:"roadmap-map-progress-fill",style:{width:`${a}%`,background:t.rollup.total>0?z.accentGreen:"transparent"}})}),e.jsx("div",{style:{fontSize:b["2xs"],opacity:.5},children:t.rollup.total>0?`${t.rollup.done}/${t.rollup.total} done`:"not started"})]})},ue=({roadmap:t,graduatedByItem:a})=>e.jsx("div",{className:"roadmap-lanes",children:t.horizons.map(s=>e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[1]},children:[e.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:i[2]},children:[e.jsx("div",{style:T,children:s.title}),e.jsx(F,{items:s.items,graduatedByItem:a})]}),e.jsx("div",{className:"roadmap-lane-items",children:s.items.map(o=>e.jsx("div",{className:"roadmap-lane-item",children:e.jsx(me,{item:o})},o.name))})]},s.title))}),he=({roadmap:t})=>{if(t.events.length===0)return e.jsx("p",{style:{opacity:.5},children:"No dated events yet."});const a=t.events.map(l=>Date.parse(l.date)),s=Math.min(...a),o=Math.max(...a);return e.jsxs("div",{className:"roadmap-lanes",children:[t.horizons.map(l=>{const p=t.events.filter(d=>d.horizonTitle===l.title);return e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[1]},children:[e.jsx("div",{style:T,children:l.title}),p.length===0?e.jsx("div",{style:{...M,opacity:.4},children:"No events yet"}):e.jsx(xe,{events:p,rangeStart:s,rangeEnd:o})]},l.title)}),e.jsxs("div",{style:{display:"flex",justifyContent:"space-between",fontSize:b["2xs"],opacity:.5},children:[e.jsx("span",{children:new Date(s).toLocaleDateString()}),e.jsx("span",{children:new Date(o).toLocaleDateString()})]})]})},ye=()=>{const[t,a]=c.useState(null),[s,o]=c.useState(!0),[l,p]=c.useState(!1),[d,y]=c.useState(null),[m,f]=c.useState("tree"),h=R(n=>n.plans),g=G(),{item:j}=H({from:"/roadmap"}),x=c.useRef(null);if(c.useEffect(()=>{I().then(a).catch(()=>p(!0)).finally(()=>o(!1))},[]),c.useEffect(()=>{var r;if(!j||s)return;const n=(r=x.current)==null?void 0:r.querySelector(".roadmap-item-highlighted");n==null||n.scrollIntoView({behavior:"smooth",block:"center"})},[j,s]),s)return e.jsxs("div",{children:[e.jsx(P,{children:"Roadmap"}),e.jsx("p",{style:{opacity:.5},children:"Loading…"})]});if(l)return e.jsxs("div",{children:[e.jsx(P,{children:"Roadmap"}),e.jsx("p",{style:{opacity:.5},children:"Couldn't load the roadmap — the server may need a restart to pick up new routes."})]});if(!t||t.horizons.length===0)return e.jsxs("div",{children:[e.jsx(P,{children:"Roadmap"}),e.jsx("p",{style:{opacity:.5},children:"No `ROADMAP.md` found at the project root."})]});const C=n=>(h==null?void 0:h.entries.filter(r=>r.subject===n.name))??[],A=async(n,r,u)=>{await U(n,r,u),a(await I())},D=async(n,r,u)=>{await K(n,r,u),a(await I())};return e.jsxs("div",{ref:x,children:[e.jsx(de,{goal:t.goal}),e.jsx(ce,{mode:m,onChange:f}),m==="tree"&&e.jsx("div",{className:"roadmap-lanes",children:t.horizons.map(n=>e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:i[1]},children:[e.jsxs("div",{style:{display:"flex",alignItems:"baseline",gap:i[2]},children:[e.jsx("div",{style:T,children:n.title}),e.jsx(F,{items:n.items,graduatedByItem:C})]}),e.jsxs("div",{className:"roadmap-lane-items",children:[n.items.map(r=>e.jsx("div",{className:"roadmap-lane-item",children:e.jsx(oe,{item:r,graduated:C(r),highlighted:r.name===j,onPromote:()=>y({horizonTitle:n.title,item:r}),onPromoteCandidate:u=>y({horizonTitle:n.title,item:r,candidateName:u}),onAddCandidate:u=>D(n.title,r.name,u),onViewGraduated:()=>g({to:"/",search:{subject:r.name}}),onOpenGraduated:u=>g({to:"/plans/$planId",params:{planId:encodeURIComponent(u)}})})},r.name)),e.jsx("div",{className:"roadmap-lane-item",children:e.jsx(se,{onAdd:(r,u)=>A(n.title,r,u)})})]})]},n.title))}),m==="map"&&e.jsx(ue,{roadmap:t,graduatedByItem:C}),m==="timeline"&&e.jsx(he,{roadmap:t}),e.jsx(Z,{horizonTitle:(d==null?void 0:d.horizonTitle)??null,item:(d==null?void 0:d.item)??null,candidateName:d==null?void 0:d.candidateName,onClose:()=>y(null),onPromoted:()=>I().then(a)})]})};export{ye as RoadmapPage,ve as useRoadmapItemNames};
4
+ //# sourceMappingURL=index-B6eOrr41.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-B6eOrr41.js","sources":["../../../src/app/features/roadmap/promote-roadmap-item-modal.tsx","../../../src/app/features/roadmap/roadmap-page.tsx"],"sourcesContent":["import { buildRoadmapPromotePrompt } from '@/app/features/plans/prompts';\nimport { useSubjectVocabulary } from '@/app/hooks/use-subject-vocabulary';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontSize, space } from '@/app/styles/tokens';\nimport { oneLineErrorSummary } from '@/app/utils/error-summary';\nimport type { RoadmapItem } from '@/types/index';\nimport { Button, Modal, Select, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst NO_SUBJECT = '__no-subject__';\n\ninterface PromoteRoadmapItemModalProps {\n horizonTitle: string | null;\n item: RoadmapItem | null;\n candidateName?: string | null;\n onClose: () => void;\n onPromoted: () => void;\n}\n\nexport const PromoteRoadmapItemModal = ({\n horizonTitle,\n item,\n candidateName,\n onClose,\n onPromoted,\n}: PromoteRoadmapItemModalProps) => {\n const promoteRoadmapItem = useAppStore((s) => s.promoteRoadmapItem);\n const launchIdeaExtend = useAppStore((s) => s.launchIdeaExtend);\n const { subjects, available: subjectsAvailable } = useSubjectVocabulary();\n const [subject, setSubject] = useState(NO_SUBJECT);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const { toast } = useToast();\n\n useEffect(() => {\n if (item) {\n // A candidate defaults to its parent item's name — the \"big bet becomes a\n // Subject\" rule — but the picker still lets the user override it.\n setSubject(candidateName ? item.name : NO_SUBJECT);\n setLoading(false);\n setError(null);\n }\n }, [item, candidateName]);\n\n const handlePromote = async () => {\n if (!item || !horizonTitle) return;\n setLoading(true);\n setError(null);\n try {\n const id = await promoteRoadmapItem(\n horizonTitle,\n item,\n subject === NO_SUBJECT ? undefined : subject,\n candidateName ?? undefined,\n );\n const idea = useAppStore.getState().ideaEntries.find((e) => e.id === id);\n if (idea) {\n try {\n await launchIdeaExtend(id, buildRoadmapPromotePrompt(idea, horizonTitle));\n } catch (err) {\n // The idea was created either way — a failed refine launch just means\n // no background research ran, not that the promotion itself failed.\n toast({\n title: 'Idea created, but the refine agent failed to launch',\n description: oneLineErrorSummary((err as Error).message),\n variant: 'error',\n });\n }\n }\n onPromoted();\n onClose();\n } catch (err) {\n setError((err as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <Modal\n open={item !== null}\n onClose={onClose}\n title={candidateName ?? item?.name ?? ''}\n size=\"small\"\n >\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[4] }}>\n {!candidateName && <p style={{ margin: 0, opacity: 0.8 }}>{item?.description}</p>}\n <div>\n <Select\n size=\"small\"\n value={subject}\n onChange={setSubject}\n disabled={loading || !subjectsAvailable}\n options={[\n { value: NO_SUBJECT, label: 'No subject' },\n ...(!subjectsAvailable && subject !== NO_SUBJECT\n ? [{ value: subject, label: subject }]\n : []),\n ...subjects.map((s) => ({ value: s, label: s })),\n ]}\n />\n </div>\n {error && (\n <p style={{ margin: 0, color: color.accentRoseDark, fontSize: fontSize.sm }}>{error}</p>\n )}\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: space[2] }}>\n <Button type=\"button\" variant=\"ghost\" onClick={onClose} disabled={loading}>\n Cancel\n </Button>\n <Button type=\"button\" variant=\"primary\" onClick={handlePromote} disabled={loading}>\n {loading ? 'Promoting…' : 'Promote to idea'}\n </Button>\n </div>\n </div>\n </Modal>\n );\n};\n","import { Markdown } from '@/app/components/markdown';\nimport { PageTitle } from '@/app/components/page-title';\nimport { PrBadge } from '@/app/features/plans/components/pr-badge';\nimport { STATUS_LABEL, STATUS_STAMP } from '@/app/features/plans/constants';\nimport { addRoadmapCandidate, addRoadmapItem, fetchRoadmap } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, space } from '@/app/styles/tokens';\nimport type {\n PlanEntry,\n ResolvedRoadmap,\n ResolvedRoadmapItem,\n RoadmapEvent,\n RoadmapEventKind,\n RoadmapLink,\n} from '@/types/index';\nimport { Button, Card, Input, Stamp, Tooltip } from '@dendelion/paper-ui';\nimport { useNavigate, useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\nimport { PromoteRoadmapItemModal } from './promote-roadmap-item-modal';\n\nconst graduationCounts = (graduated: PlanEntry[]) => ({\n shipped: graduated.filter((p) => p.status === 'done').length,\n queued: graduated.filter((p) => p.status !== 'done' && p.status !== 'dropped').length,\n});\n\nconst horizonHeaderStyle: React.CSSProperties = {\n fontFamily: fontFamily.handwritten,\n fontSize: fontSize.md,\n fontWeight: 600,\n opacity: 0.7,\n lineHeight: 1,\n padding: `${space[2]} ${space[1]} 0`,\n};\n\nconst horizonPulseStyle: React.CSSProperties = {\n fontFamily: fontFamily.body,\n fontSize: fontSize['2xs'],\n fontWeight: 400,\n opacity: 0.5,\n padding: `0 ${space[1]}`,\n};\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst CandidateRow = ({\n name,\n onPromote,\n}: {\n name: string;\n onPromote: () => void;\n}) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div style={{ display: 'flex', alignItems: 'center', gap: space[3] }}>\n <span style={{ flex: 1 }}>{name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n </Card>\n);\n\nconst AddCandidateForm = ({ onAdd }: { onAdd: (name: string) => Promise<void> }) => {\n const [name, setName] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim());\n setName('');\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <div style={{ display: 'flex', gap: space[2] }}>\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Add candidate…\"\n disabled={saving}\n style={{ flex: 1 }}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n );\n};\n\nconst AddItemForm = ({\n onAdd,\n}: {\n onAdd: (name: string, description: string) => Promise<void>;\n}) => {\n const [open, setOpen] = useState(false);\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [saving, setSaving] = useState(false);\n\n const handleAdd = async () => {\n if (!name.trim()) return;\n setSaving(true);\n try {\n await onAdd(name.trim(), description.trim());\n setName('');\n setDescription('');\n setOpen(false);\n } finally {\n setSaving(false);\n }\n };\n\n if (!open) {\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={() => setOpen(true)}>\n + Add item\n </Button>\n );\n }\n\n return (\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[2] }}>\n <Input\n size=\"small\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"Item name…\"\n disabled={saving}\n autoFocus\n />\n <Input\n size=\"small\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleAdd();\n }}\n placeholder=\"Description…\"\n disabled={saving}\n />\n <div style={{ display: 'flex', justifyContent: 'flex-end', gap: space[2] }}>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n onClick={() => setOpen(false)}\n disabled={saving}\n >\n Cancel\n </Button>\n <Button\n type=\"button\"\n variant=\"secondary\"\n size=\"small\"\n onClick={handleAdd}\n disabled={saving || !name.trim()}\n >\n Add\n </Button>\n </div>\n </div>\n );\n};\n\nconst plural = (count: number, noun: string) => `${count} ${noun}${count === 1 ? '' : 's'}`;\n\nconst RoadmapLinkTrail = ({ link }: { link: RoadmapLink }) => (\n <div style={{ display: 'flex', alignItems: 'center', gap: space[1] }}>\n <Tooltip content={`${plural(link.taskRuns, 'task run')}${link.released ? ' · released' : ''}`}>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[link.status].fill}\n textColor={STATUS_STAMP[link.status].text}\n >\n {link.id}\n </Stamp>\n </Tooltip>\n {link.pr && <PrBadge pr={link.pr} />}\n </div>\n);\n\nconst GraduatedRow = ({ plan, onOpen }: { plan: PlanEntry; onOpen: () => void }) => (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <button\n type=\"button\"\n onClick={onOpen}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n width: '100%',\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n font: 'inherit',\n color: 'inherit',\n textAlign: 'left',\n }}\n >\n <span style={{ flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {plan.title}\n </span>\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP[plan.status].fill}\n textColor={STATUS_STAMP[plan.status].text}\n >\n {STATUS_LABEL[plan.status]}\n </Stamp>\n </button>\n </Card>\n);\n\nconst RoadmapItemRow = ({\n item,\n graduated,\n highlighted,\n onPromote,\n onPromoteCandidate,\n onAddCandidate,\n onViewGraduated,\n onOpenGraduated,\n}: {\n item: ResolvedRoadmapItem;\n graduated: PlanEntry[];\n highlighted: boolean;\n onPromote: () => void;\n onPromoteCandidate: (candidateName: string) => void;\n onAddCandidate: (name: string) => Promise<void>;\n onViewGraduated: () => void;\n onOpenGraduated: (title: string) => void;\n}) => {\n const [expanded, setExpanded] = useState(highlighted);\n const hasCandidates = item.candidates.length > 0;\n const { shipped, queued } = graduationCounts(graduated);\n\n return (\n <div\n className={highlighted ? 'roadmap-item-highlighted' : undefined}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2] }}>\n {/* Raw <button>: icon-only toggle, paper-ui Button doesn't offer this compact chrome. */}\n <button\n type=\"button\"\n aria-expanded={expanded}\n aria-label={expanded ? 'Collapse item' : 'Expand item'}\n onClick={() => setExpanded((v) => !v)}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n opacity: 0.5,\n padding: 0,\n transform: expanded ? 'rotate(90deg)' : undefined,\n }}\n >\n <ChevronRightIcon />\n </button>\n <span style={{ fontWeight: 600, flex: 1 }}>{item.name}</span>\n <Button type=\"button\" variant=\"ghost\" size=\"small\" onClick={onPromote}>\n Promote to idea\n </Button>\n </div>\n <span\n className={expanded ? undefined : 'roadmap-item-desc'}\n style={{ fontSize: fontSize.sm, opacity: 0.7 }}\n >\n {item.description}\n </span>\n <div style={{ display: 'flex', alignItems: 'center', gap: space[1] }}>\n {(queued > 0 || shipped > 0) && (\n <button\n type=\"button\"\n onClick={onViewGraduated}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[1],\n background: 'none',\n border: 'none',\n padding: 0,\n cursor: 'pointer',\n }}\n >\n {queued > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {queued} in queue\n </Stamp>\n )}\n {shipped > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.done.fill}\n textColor={STATUS_STAMP.done.text}\n >\n {shipped} shipped\n </Stamp>\n )}\n </button>\n )}\n {hasCandidates && (\n <Stamp size=\"small\" fillColor=\"rgba(0, 0, 0, 0.06)\" textColor=\"rgba(0, 0, 0, 0.55)\">\n {item.candidates.length} candidate{item.candidates.length === 1 ? '' : 's'}\n </Stamp>\n )}\n {item.rollup.total > 0 && (\n <Stamp\n size=\"small\"\n fillColor={STATUS_STAMP.planned.fill}\n textColor={STATUS_STAMP.planned.text}\n >\n {item.rollup.done}/{item.rollup.total} done\n </Stamp>\n )}\n </div>\n {item.links.length > 0 && (\n <div style={{ display: 'flex', alignItems: 'center', gap: space[1], flexWrap: 'wrap' }}>\n {item.links.map((link) => (\n <RoadmapLinkTrail key={link.id} link={link} />\n ))}\n </div>\n )}\n </div>\n </Card>\n {expanded && (\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: space[1],\n paddingLeft: space[6],\n }}\n >\n {item.candidates.map((candidateName) => (\n <CandidateRow\n key={candidateName}\n name={candidateName}\n onPromote={() => onPromoteCandidate(candidateName)}\n />\n ))}\n {graduated.map((plan) => (\n <GraduatedRow key={plan.title} plan={plan} onOpen={() => onOpenGraduated(plan.title)} />\n ))}\n <AddCandidateForm onAdd={onAddCandidate} />\n </div>\n )}\n </div>\n );\n};\n\nconst GoalBanner = ({ goal }: { goal: string }) => {\n const [expanded, setExpanded] = useState(false);\n const [firstParagraph, ...restParagraphs] = goal.split(/\\n{2,}/);\n const hasMore = restParagraphs.length > 0;\n\n return (\n <div\n style={{\n marginBottom: space[6],\n paddingBottom: space[4],\n borderBottom: '1px solid rgba(0, 0, 0, 0.08)',\n }}\n >\n <span\n style={{\n fontFamily: fontFamily.handwritten,\n fontSize: fontSize.xs,\n fontWeight: 600,\n opacity: 0.55,\n }}\n >\n The goal\n </span>\n <div\n style={{\n fontFamily: fontFamily.serif,\n fontSize: fontSize.lg,\n lineHeight: 1.4,\n marginTop: space[2],\n }}\n >\n <div className={expanded ? undefined : 'roadmap-goal-line-clamp'}>\n <Markdown>{firstParagraph}</Markdown>\n </div>\n {expanded && hasMore && <Markdown>{restParagraphs.join('\\n\\n')}</Markdown>}\n </div>\n {hasMore && (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n style={{\n background: 'none',\n border: 'none',\n padding: 0,\n marginTop: space[2],\n cursor: 'pointer',\n fontSize: fontSize['2xs'],\n opacity: 0.65,\n textDecoration: 'underline',\n }}\n >\n {expanded ? 'Show less' : 'Show more'}\n </button>\n )}\n </div>\n );\n};\n\ntype RoadmapViewMode = 'tree' | 'map' | 'timeline';\n\nconst VIEW_MODES: { id: RoadmapViewMode; label: string }[] = [\n { id: 'tree', label: 'Tree' },\n { id: 'map', label: 'Map' },\n { id: 'timeline', label: 'Timeline' },\n];\n\nconst RoadmapViewModeSwitch = ({\n mode,\n onChange,\n}: {\n mode: RoadmapViewMode;\n onChange: (mode: RoadmapViewMode) => void;\n}) => (\n <nav aria-label=\"Roadmap view\" style={{ display: 'flex', gap: space[1], marginBottom: space[4] }}>\n {VIEW_MODES.map((viewMode) => (\n <Button\n key={viewMode.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"small\"\n isActive={mode === viewMode.id}\n aria-pressed={mode === viewMode.id}\n onClick={() => onChange(viewMode.id)}\n >\n {viewMode.label}\n </Button>\n ))}\n </nav>\n);\n\nconst HorizonPulse = ({\n items,\n graduatedByItem,\n}: {\n items: ResolvedRoadmapItem[];\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => {\n const graduated = items.filter((item) => graduatedByItem(item).length > 0).length;\n const charted = items.length - graduated;\n return (\n <div style={horizonPulseStyle}>\n {graduated} graduated · {charted} charted\n </div>\n );\n};\n\nconst EVENT_KIND_COLOR: Record<RoadmapEventKind, string> = {\n created: color.accentSlate,\n 'task-run': color.accentAmber,\n};\n\nconst RoadmapTimelineTrack = ({\n events,\n rangeStart,\n rangeEnd,\n}: {\n events: RoadmapEvent[];\n rangeStart: number;\n rangeEnd: number;\n}) => {\n const span = rangeEnd - rangeStart || 1;\n return (\n <div className=\"roadmap-timeline-track\">\n {events.map((event, i) => (\n <button\n type=\"button\"\n key={`${event.entityId}-${event.kind}-${i}`}\n className=\"roadmap-timeline-dot\"\n style={{\n left: `${((Date.parse(event.date) - rangeStart) / span) * 100}%`,\n background: EVENT_KIND_COLOR[event.kind],\n }}\n title={`${event.itemName} — ${event.label} (${event.date})`}\n aria-label={`${event.itemName} — ${event.label} (${event.date})`}\n />\n ))}\n </div>\n );\n};\n\nconst RoadmapMapItem = ({ item }: { item: ResolvedRoadmapItem }) => {\n const percent =\n item.rollup.total > 0 ? Math.round((item.rollup.done / item.rollup.total) * 100) : 0;\n return (\n <div className=\"roadmap-map-item\">\n <div style={{ fontWeight: 600, fontSize: fontSize.sm }}>{item.name}</div>\n <div className=\"roadmap-map-progress-track\">\n <div\n className=\"roadmap-map-progress-fill\"\n style={{\n width: `${percent}%`,\n background: item.rollup.total > 0 ? color.accentGreen : 'transparent',\n }}\n />\n </div>\n <div style={{ fontSize: fontSize['2xs'], opacity: 0.5 }}>\n {item.rollup.total > 0 ? `${item.rollup.done}/${item.rollup.total} done` : 'not started'}\n </div>\n </div>\n );\n};\n\nconst RoadmapMap = ({\n roadmap,\n graduatedByItem,\n}: {\n roadmap: ResolvedRoadmap;\n graduatedByItem: (item: ResolvedRoadmapItem) => PlanEntry[];\n}) => (\n <div className=\"roadmap-lanes\">\n {roadmap.horizons.map((horizon) => (\n <div key={horizon.title} style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n <div style={{ display: 'flex', alignItems: 'baseline', gap: space[2] }}>\n <div style={horizonHeaderStyle}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"roadmap-lane-items\">\n {horizon.items.map((item) => (\n <div key={item.name} className=\"roadmap-lane-item\">\n <RoadmapMapItem item={item} />\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n);\n\nconst RoadmapTimeline = ({ roadmap }: { roadmap: ResolvedRoadmap }) => {\n if (roadmap.events.length === 0) {\n return <p style={{ opacity: 0.5 }}>No dated events yet.</p>;\n }\n\n const dates = roadmap.events.map((event) => Date.parse(event.date));\n const rangeStart = Math.min(...dates);\n const rangeEnd = Math.max(...dates);\n\n return (\n <div className=\"roadmap-lanes\">\n {roadmap.horizons.map((horizon) => {\n const events = roadmap.events.filter((event) => event.horizonTitle === horizon.title);\n return (\n <div\n key={horizon.title}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}\n >\n <div style={horizonHeaderStyle}>{horizon.title}</div>\n {events.length === 0 ? (\n <div style={{ ...horizonPulseStyle, opacity: 0.4 }}>No events yet</div>\n ) : (\n <RoadmapTimelineTrack events={events} rangeStart={rangeStart} rangeEnd={rangeEnd} />\n )}\n </div>\n );\n })}\n <div\n style={{\n display: 'flex',\n justifyContent: 'space-between',\n fontSize: fontSize['2xs'],\n opacity: 0.5,\n }}\n >\n <span>{new Date(rangeStart).toLocaleDateString()}</span>\n <span>{new Date(rangeEnd).toLocaleDateString()}</span>\n </div>\n </div>\n );\n};\n\nexport const RoadmapPage = () => {\n const [roadmap, setRoadmap] = useState<ResolvedRoadmap | null>(null);\n const [loading, setLoading] = useState(true);\n const [loadFailed, setLoadFailed] = useState(false);\n const [promoting, setPromoting] = useState<{\n horizonTitle: string;\n item: ResolvedRoadmapItem;\n candidateName?: string;\n } | null>(null);\n const [viewMode, setViewMode] = useState<RoadmapViewMode>('tree');\n const plans = useAppStore((s) => s.plans);\n const navigate = useNavigate();\n const { item: highlightedItem } = useSearch({ from: '/roadmap' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n fetchRoadmap()\n .then(setRoadmap)\n .catch(() => setLoadFailed(true))\n .finally(() => setLoading(false));\n }, []);\n\n useEffect(() => {\n if (!highlightedItem || loading) return;\n const row = containerRef.current?.querySelector('.roadmap-item-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [highlightedItem, loading]);\n\n if (loading) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p style={{ opacity: 0.5 }}>Loading…</p>\n </div>\n );\n }\n\n if (loadFailed) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p style={{ opacity: 0.5 }}>\n Couldn't load the roadmap — the server may need a restart to pick up new routes.\n </p>\n </div>\n );\n }\n\n if (!roadmap || roadmap.horizons.length === 0) {\n return (\n <div>\n <PageTitle>Roadmap</PageTitle>\n <p style={{ opacity: 0.5 }}>No `ROADMAP.md` found at the project root.</p>\n </div>\n );\n }\n\n const graduatedByItem = (item: ResolvedRoadmapItem) =>\n plans?.entries.filter((p) => p.subject === item.name) ?? [];\n\n const handleAddItem = async (horizonTitle: string, name: string, description: string) => {\n await addRoadmapItem(horizonTitle, name, description);\n setRoadmap(await fetchRoadmap());\n };\n\n const handleAddCandidate = async (horizonTitle: string, itemName: string, name: string) => {\n await addRoadmapCandidate(horizonTitle, itemName, name);\n setRoadmap(await fetchRoadmap());\n };\n\n return (\n <div ref={containerRef}>\n <GoalBanner goal={roadmap.goal} />\n <RoadmapViewModeSwitch mode={viewMode} onChange={setViewMode} />\n {viewMode === 'tree' && (\n <div className=\"roadmap-lanes\">\n {roadmap.horizons.map((horizon) => (\n <div\n key={horizon.title}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}\n >\n <div style={{ display: 'flex', alignItems: 'baseline', gap: space[2] }}>\n <div style={horizonHeaderStyle}>{horizon.title}</div>\n <HorizonPulse items={horizon.items} graduatedByItem={graduatedByItem} />\n </div>\n <div className=\"roadmap-lane-items\">\n {horizon.items.map((item) => (\n <div key={item.name} className=\"roadmap-lane-item\">\n <RoadmapItemRow\n item={item}\n graduated={graduatedByItem(item)}\n highlighted={item.name === highlightedItem}\n onPromote={() => setPromoting({ horizonTitle: horizon.title, item })}\n onPromoteCandidate={(candidateName) =>\n setPromoting({ horizonTitle: horizon.title, item, candidateName })\n }\n onAddCandidate={(name) => handleAddCandidate(horizon.title, item.name, name)}\n onViewGraduated={() => navigate({ to: '/', search: { subject: item.name } })}\n onOpenGraduated={(title) =>\n navigate({\n to: '/plans/$planId',\n params: { planId: encodeURIComponent(title) },\n })\n }\n />\n </div>\n ))}\n <div className=\"roadmap-lane-item\">\n <AddItemForm\n onAdd={(name, description) => handleAddItem(horizon.title, name, description)}\n />\n </div>\n </div>\n </div>\n ))}\n </div>\n )}\n {viewMode === 'map' && <RoadmapMap roadmap={roadmap} graduatedByItem={graduatedByItem} />}\n {viewMode === 'timeline' && <RoadmapTimeline roadmap={roadmap} />}\n <PromoteRoadmapItemModal\n horizonTitle={promoting?.horizonTitle ?? null}\n item={promoting?.item ?? null}\n candidateName={promoting?.candidateName}\n onClose={() => setPromoting(null)}\n onPromoted={() => fetchRoadmap().then(setRoadmap)}\n />\n </div>\n );\n};\n"],"names":["NO_SUBJECT","PromoteRoadmapItemModal","horizonTitle","item","candidateName","onClose","onPromoted","promoteRoadmapItem","useAppStore","s","launchIdeaExtend","subjects","subjectsAvailable","useSubjectVocabulary","subject","setSubject","useState","loading","setLoading","error","setError","toast","useToast","useEffect","handlePromote","id","idea","e","buildRoadmapPromotePrompt","err","oneLineErrorSummary","jsx","Modal","jsxs","space","Select","color","fontSize","Button","graduationCounts","graduated","p","horizonHeaderStyle","fontFamily","horizonPulseStyle","ChevronRightIcon","size","CandidateRow","name","onPromote","Card","AddCandidateForm","onAdd","setName","saving","setSaving","handleAdd","Input","AddItemForm","open","setOpen","description","setDescription","plural","count","noun","RoadmapLinkTrail","link","Tooltip","Stamp","STATUS_STAMP","PrBadge","GraduatedRow","plan","onOpen","STATUS_LABEL","RoadmapItemRow","highlighted","onPromoteCandidate","onAddCandidate","onViewGraduated","onOpenGraduated","expanded","setExpanded","hasCandidates","shipped","queued","v","GoalBanner","goal","firstParagraph","restParagraphs","hasMore","Markdown","VIEW_MODES","RoadmapViewModeSwitch","mode","onChange","viewMode","HorizonPulse","items","graduatedByItem","charted","EVENT_KIND_COLOR","RoadmapTimelineTrack","events","rangeStart","rangeEnd","span","event","i","RoadmapMapItem","percent","RoadmapMap","roadmap","horizon","RoadmapTimeline","dates","RoadmapPage","setRoadmap","loadFailed","setLoadFailed","promoting","setPromoting","setViewMode","plans","navigate","useNavigate","highlightedItem","useSearch","containerRef","useRef","fetchRoadmap","row","_a","PageTitle","handleAddItem","addRoadmapItem","handleAddCandidate","itemName","addRoadmapCandidate","title"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{r as p,g as G,j as e,s as n,i as z,O as N,p as P,Z as T,k,m as $,n as V,q as se,b as v,t as te,v as R,w as ne,x as ae,a as Z,y as X,P as ie,z as le,X as O,c as oe,D,A as re,B as L,Y as _,C as ce,E as de,o as M}from"./main-Bno8vU-0.js";import{S as W}from"./sidebar-section-BrJbBK_b.js";const me=async()=>{try{const s=await fetch("/api/merge-policy");return s.ok?await s.json():null}catch{return null}},pe=async()=>{try{const s=await fetch("/api/merge-policy/apply",{method:"POST"});return s.ok?await s.json():null}catch{return null}},K={allowSquashMerge:!0,allowMergeCommit:!1,allowRebaseMerge:!1,squashMergeCommitTitle:"PR_TITLE",squashMergeCommitMessage:"PR_BODY"},U=[{key:"allowSquashMerge",label:"Allow squash merge"},{key:"allowMergeCommit",label:"Allow merge commit"},{key:"allowRebaseMerge",label:"Allow rebase merge"},{key:"squashMergeCommitTitle",label:"Squash commit title"},{key:"squashMergeCommitMessage",label:"Squash commit message"}];function Y(s){return typeof s=="boolean"?s?"Yes":"No":s}function he(s){return U.every(t=>s[t.key]===K[t.key])}const ge=({label:s,current:t,recommended:o,isLast:i})=>{const m=t===o;return e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3],paddingBottom:n[2],paddingTop:n[2]},children:[e.jsx("span",{style:{flex:1},children:s}),e.jsx("span",{style:{opacity:m?.65:1,fontWeight:m?400:600},children:Y(t)}),!m&&e.jsxs("span",{style:{opacity:.45},children:["→ ",Y(o)]})]}),!i&&e.jsx(k,{})]})},ue=()=>{const[s,t]=p.useState(void 0),[o,i]=p.useState(!1),{toast:m}=G();p.useEffect(()=>{me().then(t)},[]);const g=async()=>{i(!0);const r=await pe();i(!1),(r==null?void 0:r.status)==="ok"?(t(r),m({title:"Merge policy applied",variant:"success"})):m({title:"Failed to apply merge policy",description:(r==null?void 0:r.status)==="unavailable"?r.reason:void 0,variant:"error"})},h=(s==null?void 0:s.status)==="ok"&&he(s.policy);return e.jsxs("div",{children:[e.jsxs("div",{style:{marginBottom:n[6]},children:[e.jsx("h2",{style:{margin:0},children:"Merge Policy"}),e.jsx("p",{style:{opacity:.5,marginTop:n[1]},children:"Paper Camp's canonical policy: squash-only merges, with the commit title and body taken from the PR."})]}),s===void 0&&e.jsx("p",{children:"Loading…"}),s===null&&e.jsx(z,{variant:"warning",children:"Failed to load merge policy."}),(s==null?void 0:s.status)==="unavailable"&&e.jsx(z,{variant:"warning",children:s.reason}),(s==null?void 0:s.status)==="ok"&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3],marginBottom:n[3]},children:[e.jsx("span",{style:{fontWeight:500},children:s.repo}),e.jsx(N,{size:"small",fillColor:h?"rgba(143, 185, 150, 0.25)":"rgba(212, 163, 115, 0.25)",textColor:h?"#5E8A66":"#A67B4F",children:h?"Matches recommended policy":"Differs from recommended policy"})]}),e.jsx(P,{size:"small",children:U.map((r,y)=>e.jsx(ge,{label:r.label,current:s.policy[r.key],recommended:K[r.key],isLast:y===U.length-1},r.key))}),e.jsx("div",{style:{marginTop:n[4]},children:e.jsx(T,{size:"small",onClick:g,disabled:o||h,children:o?"Applying…":"Apply recommended policy"})})]})]})},xe={ok:{fill:"rgba(143, 185, 150, 0.25)",text:"#5E8A66",label:"Ready"},warn:{fill:"rgba(212, 163, 115, 0.25)",text:"#A67B4F",label:"Needs attention"},missing:{fill:"rgba(201, 139, 139, 0.25)",text:"#6E3A3A",label:"Missing"}},ye=({connection:s,onConnect:t,connecting:o})=>{const{connect:i}=s;return i?i.kind==="command"&&i.runnable?e.jsx(T,{size:"small",variant:"secondary",onClick:()=>t(s.id),disabled:o,children:o?"Running…":`Run \`${i.command}\``}):i.kind==="command"?e.jsx("div",{style:{marginTop:n[2]},children:e.jsx(ne,{code:i.command})}):i.kind==="link"?e.jsx(T,{size:"small",variant:"secondary",onClick:()=>window.open(i.url,"_blank","noopener,noreferrer"),children:i.label}):e.jsx("p",{style:{opacity:.65,fontSize:v.sm,margin:`${n[2]} 0 0`},children:i.message}):null},je=({connection:s,isLast:t,onRecheck:o,rechecking:i,onConnect:m,connecting:g})=>{const h=xe[s.status];return e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{paddingBottom:n[3],paddingTop:n[3]},children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3]},children:[e.jsx("span",{style:{flex:1,fontWeight:500},children:s.label}),s.authenticated===!1&&e.jsx(se,{content:"Installed, but not signed in",children:e.jsx(N,{size:"small",variant:"warning",children:"Not signed in"})}),e.jsx(N,{size:"small",fillColor:h.fill,textColor:h.text,children:h.label}),e.jsx(T,{size:"small",variant:"secondary",onClick:()=>o(s.id),disabled:i,children:i?"Checking…":"Recheck"})]}),e.jsxs("p",{style:{opacity:.65,fontSize:v.sm,margin:`${n[1]} 0 0`},children:["Unlocks: ",s.unlocks]}),e.jsx("p",{style:{opacity:.5,fontSize:v.sm,margin:`${n[1]} 0 0`},children:s.detail}),e.jsx("div",{style:{marginTop:n[2]},children:e.jsx(ye,{connection:s,onConnect:m,connecting:g})})]}),!t&&e.jsx(k,{})]})},fe=()=>{const[s,t]=p.useState(null),[o,i]=p.useState(!1),[m,g]=p.useState(null),[h,r]=p.useState(null),[y,w]=p.useState(!1),{toast:S}=G(),b=p.useCallback(l=>{if(l===null){i(!0);return}i(!1),t(l)},[]);p.useEffect(()=>{$().then(b),V().then(l=>w((l==null?void 0:l.setupDismissed)??!1))},[b]);const C=async l=>{g(l),b(await $()),g(null)},d=async l=>{r(l);const j=await te(l);j?t(I=>(I==null?void 0:I.map(a=>a.id===l?j:a))??I):S({title:"Failed to connect",variant:"error"}),r(null)},u=async()=>{const l=!y,{ok:j}=await R({setupDismissed:l});j?(w(l),S({title:"Saved",variant:"success"})):S({title:"Failed to save",variant:"error"})},A=(s==null?void 0:s.every(l=>l.status==="ok"))??!0;return e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:n[6]},children:e.jsx("h2",{style:{margin:0},children:"Setup"})}),s===null&&!o&&e.jsx("p",{children:"Loading…"}),o&&e.jsx("div",{style:{marginBottom:n[4]},children:e.jsx(z,{variant:"warning",children:"Failed to load connections. Try refreshing."})}),s&&e.jsxs(e.Fragment,{children:[!A&&e.jsx("div",{style:{marginBottom:n[4]},children:e.jsx(z,{variant:"warning",children:"Some connections are incomplete — features that depend on them stay disabled until fixed. Run the connect command below, then recheck."})}),e.jsx(P,{size:"small",children:s.map((l,j)=>e.jsx(je,{connection:l,isLast:j===s.length-1,onRecheck:C,rechecking:m===l.id,onConnect:d,connecting:h===l.id},l.id))}),e.jsx("div",{style:{marginTop:n[4]},children:e.jsx(T,{variant:"secondary",size:"small",onClick:u,children:y?"Show Setup on open again":"Don't show Setup on open"})})]})]})},ve=()=>{const{subjects:s,loading:t,available:o}=ae(),i=Z();return e.jsxs("div",{children:[e.jsxs("div",{style:{marginBottom:n[6]},children:[e.jsx("h2",{style:{margin:0},children:"Subjects"}),e.jsx("p",{style:{opacity:.5,marginTop:n[1]},children:"Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap page."})]}),t&&e.jsx("p",{children:"Loading…"}),!t&&!o&&e.jsx("p",{style:{opacity:.6,margin:0},children:"Couldn't load subjects — check the server config."}),!t&&o&&e.jsxs(P,{size:"small",children:[s.length===0&&e.jsx("p",{style:{opacity:.45,margin:0,paddingBottom:n[2]},children:"No subjects yet."}),s.map((m,g)=>e.jsxs("div",{children:[e.jsx("div",{style:{paddingBottom:n[2],paddingTop:n[2]},children:m}),g<s.length-1&&e.jsx(k,{})]},m)),s.length>0&&e.jsx(k,{}),e.jsx("div",{style:{paddingTop:n[3]},children:e.jsx(T,{variant:"secondary",size:"small",onClick:()=>i({to:"/roadmap"}),children:"Go to Roadmap"})})]})]})},H=["phase","planDraft","ideaExtend","commitSuggest"],Se={phase:"Phase run",planDraft:"Plan draft",ideaExtend:"Idea extend",commitSuggest:"Commit suggest"},J=110,Q=140,q=160,ee=110,be=()=>e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3],paddingBottom:n[1]},children:[e.jsx("span",{style:{width:J,flexShrink:0,fontSize:v.sm,opacity:.45},children:"Task"}),e.jsx("span",{style:{width:Q,flexShrink:0,fontSize:v.sm,opacity:.45},children:"Agent"}),e.jsx("span",{style:{width:q,flexShrink:0,fontSize:v.sm,opacity:.45},children:"Model"}),e.jsx("span",{style:{width:ee,flexShrink:0,fontSize:v.sm,opacity:.45},children:"Effort"})]}),ke=({taskKey:s,agentConfig:t,isLast:o,onSave:i})=>{const m=L[t.agent]??L["claude-code"],g=m.model,h=m.effort,[r,y]=p.useState(t.model??"");p.useEffect(()=>{y(t.model??"")},[t.model]);const w=d=>{var j;const u=d,A=L[u],l={agent:u};t.model&&(A.model===null||(j=A.model)!=null&&j.includes(t.model))&&(l.model=t.model),t.effort&&Array.isArray(A.effort)&&(l.effort=t.effort),i(s,l)},S=d=>{i(s,{...t,model:d||void 0})},b=()=>{i(s,{...t,model:r||void 0})},C=d=>{i(s,{...t,effort:d||void 0})};return e.jsxs(e.Fragment,{children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3],paddingBottom:n[2],paddingTop:n[2]},children:[e.jsx("span",{style:{width:J,flexShrink:0,fontSize:v.sm,opacity:.65},children:Se[s]}),e.jsx(_,{size:"small",width:Q,value:t.agent,onChange:w,options:ce.map(d=>({value:d,label:de[d]}))}),Array.isArray(g)?e.jsx(_,{size:"small",width:q,value:t.model??"",onChange:S,options:[{value:"",label:"Default"},...g.map(d=>({value:d,label:d}))]}):g===null?e.jsx(O,{size:"small",style:{width:q},value:r,placeholder:"Default model",onChange:d=>y(d.target.value),onBlur:b}):null,e.jsx("div",{style:{visibility:Array.isArray(h)?"visible":"hidden"},children:e.jsx(_,{size:"small",width:ee,value:t.effort??"",onChange:C,options:[{value:"",label:"Default"},...(Array.isArray(h)?h:[]).map(d=>({value:d,label:d}))]})})]}),!o&&e.jsx(k,{})]})},we=()=>{const s=p.useRef(null),[t,o]=p.useState(void 0),{iconDataUri:i,loading:m}=le(),[g,h]=p.useState(null),r=g??i,[y,w]=p.useState(!1),[S,b]=p.useState(""),[C,d]=p.useState(""),{toast:u}=G();p.useEffect(()=>{V().then(a=>{o(a),(a==null?void 0:a.port)!==void 0&&b(String(a.port)),(a==null?void 0:a.projectName)!==void 0&&d(a.projectName)})},[]);const A=async(a,f)=>{const c=t==null?void 0:t.defaultAgents,x={phase:(c==null?void 0:c.phase)??D.phase,planDraft:(c==null?void 0:c.planDraft)??D.planDraft,ideaExtend:(c==null?void 0:c.ideaExtend)??D.ideaExtend,commitSuggest:(c==null?void 0:c.commitSuggest)??D.commitSuggest,[a]:f},{ok:E,error:B}=await R({defaultAgents:x});E?(o(F=>F&&{...F,defaultAgents:x}),u({title:"Saved",variant:"success"})):u({title:"Failed to save",description:B,variant:"error"})},l=async()=>{const a=Number(S);if(!t||!Number.isInteger(a)||a<=0||a===t.port)return;const{ok:f,error:c}=await R({port:a});f?(o(x=>x&&{...x,port:a}),u({title:"Saved",variant:"success"})):u({title:"Failed to save",description:c,variant:"error"})},j=async()=>{const a=C.trim();if(!t||!a||a===t.projectName)return;const{ok:f,error:c}=await R({projectName:a});f?(o(x=>x&&{...x,projectName:a}),d(a),u({title:"Saved",variant:"success"})):u({title:"Failed to save",description:c,variant:"error"})},I=async a=>{var x;const f=(x=a.target.files)==null?void 0:x[0];if(!f)return;w(!0);const c=new FileReader;c.onloadend=async()=>{const E=c.result,B=await re(E);w(!1),B?(h(E),u({title:"Saved",variant:"success"})):u({title:"Failed to save",variant:"error"})},c.readAsDataURL(f)};return e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:n[6]},children:e.jsx("h2",{style:{margin:0},children:"Project Info"})}),t===void 0&&e.jsx("p",{children:"Loading…"}),t===null&&e.jsxs(z,{variant:"warning",children:["No papercamp/config.json found — run ",e.jsx("code",{children:"paper-camp init"})," in this directory first."]}),t&&e.jsxs(P,{size:"small",children:[e.jsxs("div",{style:{display:"flex",alignItems:"flex-end",gap:n[3],paddingBottom:n[3]},children:[e.jsx(O,{value:C,onChange:a=>d(a.target.value),onBlur:j,label:"Project Name"}),e.jsxs(N,{size:"small",fillColor:"rgba(143, 185, 150, 0.25)",textColor:oe.accentGreenDark,children:["v",t.version]})]}),e.jsx(k,{}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:n[3],paddingBottom:n[3],paddingTop:n[3]},children:[r&&e.jsx("img",{src:r,alt:"Project icon",style:{width:40,height:40,objectFit:"contain",flexShrink:0,borderRadius:4}}),e.jsxs("div",{children:[e.jsx("input",{ref:s,type:"file",accept:".svg,.png,.jpg,.jpeg,.gif,.webp",onChange:I,style:{display:"none"}}),e.jsx(T,{variant:"secondary",size:"small",onClick:()=>{var a;return(a=s.current)==null?void 0:a.click()},disabled:y,children:y?"Uploading…":"Choose File"}),m&&e.jsx("p",{className:"text-sm",style:{opacity:.5,margin:`${n[1]} 0 0`},children:"Loading…"}),!m&&!r&&!y&&e.jsx("p",{className:"text-sm",style:{opacity:.45,margin:`${n[1]} 0 0`},children:"No icon set."})]})]}),e.jsx(k,{}),e.jsx("div",{style:{display:"flex",alignItems:"flex-end",gap:n[3],paddingBottom:n[3],paddingTop:n[3]},children:e.jsx(O,{type:"number",value:S,onChange:a=>b(a.target.value),onBlur:l,label:"Port",helperText:"Default for `paper-camp dev`. Does not affect the running server."})}),e.jsx(k,{}),e.jsx(be,{}),H.map((a,f)=>{var c;return e.jsx(ke,{taskKey:a,agentConfig:((c=t.defaultAgents)==null?void 0:c[a])??D[a],isLast:f===H.length-1,onSave:A},a)})]}),e.jsxs("p",{style:{opacity:.45,fontSize:v.sm,marginTop:n[4]},children:[e.jsx("strong",{children:"Initialized:"})," ",t?new Date(t.initializedAt).toLocaleString():"—"]})]})},Ce=()=>{const s=X();return e.jsxs("div",{children:[e.jsx(ie,{children:"Settings"}),s==="subjects"?e.jsx(ve,{}):s==="setup"?e.jsx(fe,{}):s==="merge-policy"?e.jsx(ue,{}):e.jsx(we,{})]})},Ie=()=>{const s=X(),t=Z();return e.jsxs(e.Fragment,{children:[e.jsxs(W,{label:"General",children:[e.jsx(M,{size:"small",active:s===null,onClick:()=>t({to:"/settings"}),children:"Project Info"}),e.jsx(M,{size:"small",active:s==="setup",onClick:()=>t({to:"/settings/$section",params:{section:"setup"}}),children:"Setup"}),e.jsx(M,{size:"small",active:s==="merge-policy",onClick:()=>t({to:"/settings/$section",params:{section:"merge-policy"}}),children:"Merge Policy"})]}),e.jsx(W,{label:"Ideas",children:e.jsx(M,{size:"small",active:s==="subjects",onClick:()=>t({to:"/settings/$section",params:{section:"subjects"}}),children:"Subjects"})})]})};export{Ce as SettingsPage,Ie as SettingsSidebar};
2
+ //# sourceMappingURL=index-BajRXbXg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-BajRXbXg.js","sources":["../../../src/app/services/system/merge-policy-api.ts","../../../src/app/features/settings/components/merge-policy-section.tsx","../../../src/app/features/settings/components/setup-section.tsx","../../../src/app/features/settings/components/subjects-section.tsx","../../../src/app/features/settings/settings-page.tsx","../../../src/app/features/settings/components/settings-sidebar.tsx"],"sourcesContent":["import type { MergePolicyResult } from '@/types/index';\n\nexport const fetchMergePolicy = async (): Promise<MergePolicyResult | null> => {\n try {\n const response = await fetch('/api/merge-policy');\n if (!response.ok) return null;\n return (await response.json()) as MergePolicyResult;\n } catch {\n return null;\n }\n};\n\nexport const applyMergePolicy = async (): Promise<MergePolicyResult | null> => {\n try {\n const response = await fetch('/api/merge-policy/apply', { method: 'POST' });\n if (!response.ok) return null;\n return (await response.json()) as MergePolicyResult;\n } catch {\n return null;\n }\n};\n","import { applyMergePolicy, fetchMergePolicy } from '@/app/services/system';\nimport { space } from '@/app/styles/tokens';\nimport type { MergePolicy, MergePolicyResult } from '@/types/index';\nimport { Alert, Button, Card, Divider, Stamp, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useState } from 'react';\n\nconst RECOMMENDED: MergePolicy = {\n allowSquashMerge: true,\n allowMergeCommit: false,\n allowRebaseMerge: false,\n squashMergeCommitTitle: 'PR_TITLE',\n squashMergeCommitMessage: 'PR_BODY',\n};\n\nconst POLICY_ROWS: { key: keyof MergePolicy; label: string }[] = [\n { key: 'allowSquashMerge', label: 'Allow squash merge' },\n { key: 'allowMergeCommit', label: 'Allow merge commit' },\n { key: 'allowRebaseMerge', label: 'Allow rebase merge' },\n { key: 'squashMergeCommitTitle', label: 'Squash commit title' },\n { key: 'squashMergeCommitMessage', label: 'Squash commit message' },\n];\n\nfunction formatValue(value: boolean | string): string {\n return typeof value === 'boolean' ? (value ? 'Yes' : 'No') : value;\n}\n\nfunction matchesRecommended(policy: MergePolicy): boolean {\n return POLICY_ROWS.every((row) => policy[row.key] === RECOMMENDED[row.key]);\n}\n\ninterface PolicyRowProps {\n label: string;\n current: boolean | string;\n recommended: boolean | string;\n isLast: boolean;\n}\n\nconst PolicyRow = ({ label, current, recommended, isLast }: PolicyRowProps) => {\n const matches = current === recommended;\n return (\n <>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[2],\n paddingTop: space[2],\n }}\n >\n <span style={{ flex: 1 }}>{label}</span>\n <span style={{ opacity: matches ? 0.65 : 1, fontWeight: matches ? 400 : 600 }}>\n {formatValue(current)}\n </span>\n {!matches && <span style={{ opacity: 0.45 }}>→ {formatValue(recommended)}</span>}\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nexport const MergePolicySection = () => {\n const [result, setResult] = useState<MergePolicyResult | null | undefined>(undefined);\n const [applying, setApplying] = useState(false);\n const { toast } = useToast();\n\n useEffect(() => {\n fetchMergePolicy().then(setResult);\n }, []);\n\n const handleApply = async () => {\n setApplying(true);\n const applied = await applyMergePolicy();\n setApplying(false);\n if (applied?.status === 'ok') {\n setResult(applied);\n toast({ title: 'Merge policy applied', variant: 'success' });\n } else {\n toast({\n title: 'Failed to apply merge policy',\n description: applied?.status === 'unavailable' ? applied.reason : undefined,\n variant: 'error',\n });\n }\n };\n\n const upToDate = result?.status === 'ok' && matchesRecommended(result.policy);\n\n return (\n <div>\n <div style={{ marginBottom: space[6] }}>\n <h2 style={{ margin: 0 }}>Merge Policy</h2>\n <p style={{ opacity: 0.5, marginTop: space[1] }}>\n Paper Camp's canonical policy: squash-only merges, with the commit title and body taken\n from the PR.\n </p>\n </div>\n {result === undefined && <p>Loading…</p>}\n {result === null && <Alert variant=\"warning\">Failed to load merge policy.</Alert>}\n {result?.status === 'unavailable' && <Alert variant=\"warning\">{result.reason}</Alert>}\n {result?.status === 'ok' && (\n <>\n <div\n style={{ display: 'flex', alignItems: 'center', gap: space[3], marginBottom: space[3] }}\n >\n <span style={{ fontWeight: 500 }}>{result.repo}</span>\n <Stamp\n size=\"small\"\n fillColor={upToDate ? 'rgba(143, 185, 150, 0.25)' : 'rgba(212, 163, 115, 0.25)'}\n textColor={upToDate ? '#5E8A66' : '#A67B4F'}\n >\n {upToDate ? 'Matches recommended policy' : 'Differs from recommended policy'}\n </Stamp>\n </div>\n <Card size=\"small\">\n {POLICY_ROWS.map((row, idx) => (\n <PolicyRow\n key={row.key}\n label={row.label}\n current={result.policy[row.key]}\n recommended={RECOMMENDED[row.key]}\n isLast={idx === POLICY_ROWS.length - 1}\n />\n ))}\n </Card>\n <div style={{ marginTop: space[4] }}>\n <Button size=\"small\" onClick={handleApply} disabled={applying || upToDate}>\n {applying ? 'Applying…' : 'Apply recommended policy'}\n </Button>\n </div>\n </>\n )}\n </div>\n );\n};\n","import { connectService, fetchConfig, fetchConnections, saveConfig } from '@/app/services/system';\nimport { fontSize, space } from '@/app/styles/tokens';\nimport type { CapabilityStatus, ConnectionResult } from '@/types/index';\nimport {\n Alert,\n Button,\n Card,\n CodeBlock,\n Divider,\n Stamp,\n Tooltip,\n useToast,\n} from '@dendelion/paper-ui';\nimport { useCallback, useEffect, useState } from 'react';\n\nconst STATUS_STAMP: Record<CapabilityStatus, { fill: string; text: string; label: string }> = {\n ok: { fill: 'rgba(143, 185, 150, 0.25)', text: '#5E8A66', label: 'Ready' },\n warn: { fill: 'rgba(212, 163, 115, 0.25)', text: '#A67B4F', label: 'Needs attention' },\n missing: { fill: 'rgba(201, 139, 139, 0.25)', text: '#6E3A3A', label: 'Missing' },\n};\n\nconst ConnectActionView = ({\n connection,\n onConnect,\n connecting,\n}: {\n connection: ConnectionResult;\n onConnect: (id: string) => void;\n connecting: boolean;\n}) => {\n const { connect } = connection;\n if (!connect) return null;\n if (connect.kind === 'command' && connect.runnable) {\n return (\n <Button\n size=\"small\"\n variant=\"secondary\"\n onClick={() => onConnect(connection.id)}\n disabled={connecting}\n >\n {connecting ? 'Running…' : `Run \\`${connect.command}\\``}\n </Button>\n );\n }\n if (connect.kind === 'command') {\n return (\n <div style={{ marginTop: space[2] }}>\n <CodeBlock code={connect.command} />\n </div>\n );\n }\n if (connect.kind === 'link') {\n return (\n <Button\n size=\"small\"\n variant=\"secondary\"\n onClick={() => window.open(connect.url, '_blank', 'noopener,noreferrer')}\n >\n {connect.label}\n </Button>\n );\n }\n return (\n <p style={{ opacity: 0.65, fontSize: fontSize.sm, margin: `${space[2]} 0 0` }}>\n {connect.message}\n </p>\n );\n};\n\nconst ConnectionRow = ({\n connection,\n isLast,\n onRecheck,\n rechecking,\n onConnect,\n connecting,\n}: {\n connection: ConnectionResult;\n isLast: boolean;\n onRecheck: (id: string) => void;\n rechecking: boolean;\n onConnect: (id: string) => void;\n connecting: boolean;\n}) => {\n const stamp = STATUS_STAMP[connection.status];\n return (\n <>\n <div style={{ paddingBottom: space[3], paddingTop: space[3] }}>\n <div style={{ display: 'flex', alignItems: 'center', gap: space[3] }}>\n <span style={{ flex: 1, fontWeight: 500 }}>{connection.label}</span>\n {connection.authenticated === false && (\n <Tooltip content=\"Installed, but not signed in\">\n <Stamp size=\"small\" variant=\"warning\">\n Not signed in\n </Stamp>\n </Tooltip>\n )}\n <Stamp size=\"small\" fillColor={stamp.fill} textColor={stamp.text}>\n {stamp.label}\n </Stamp>\n <Button\n size=\"small\"\n variant=\"secondary\"\n onClick={() => onRecheck(connection.id)}\n disabled={rechecking}\n >\n {rechecking ? 'Checking…' : 'Recheck'}\n </Button>\n </div>\n <p style={{ opacity: 0.65, fontSize: fontSize.sm, margin: `${space[1]} 0 0` }}>\n Unlocks: {connection.unlocks}\n </p>\n <p style={{ opacity: 0.5, fontSize: fontSize.sm, margin: `${space[1]} 0 0` }}>\n {connection.detail}\n </p>\n <div style={{ marginTop: space[2] }}>\n <ConnectActionView\n connection={connection}\n onConnect={onConnect}\n connecting={connecting}\n />\n </div>\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nexport const SetupSection = () => {\n const [connections, setConnections] = useState<ConnectionResult[] | null>(null);\n const [loadFailed, setLoadFailed] = useState(false);\n const [reloadingId, setReloadingId] = useState<string | null>(null);\n const [connectingId, setConnectingId] = useState<string | null>(null);\n const [setupDismissed, setSetupDismissed] = useState(false);\n const { toast } = useToast();\n\n const applyConnections = useCallback((result: ConnectionResult[] | null) => {\n if (result === null) {\n setLoadFailed(true);\n return;\n }\n setLoadFailed(false);\n setConnections(result);\n }, []);\n\n useEffect(() => {\n fetchConnections().then(applyConnections);\n fetchConfig().then((c) => setSetupDismissed(c?.setupDismissed ?? false));\n }, [applyConnections]);\n\n const handleRecheck = async (id: string) => {\n setReloadingId(id);\n applyConnections(await fetchConnections());\n setReloadingId(null);\n };\n\n const handleConnect = async (id: string) => {\n setConnectingId(id);\n const updated = await connectService(id);\n if (updated) {\n setConnections((prev) => prev?.map((c) => (c.id === id ? updated : c)) ?? prev);\n } else {\n toast({ title: 'Failed to connect', variant: 'error' });\n }\n setConnectingId(null);\n };\n\n const handleDismissToggle = async () => {\n const next = !setupDismissed;\n const { ok } = await saveConfig({ setupDismissed: next });\n if (ok) {\n setSetupDismissed(next);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', variant: 'error' });\n }\n };\n\n const allOk = connections?.every((c) => c.status === 'ok') ?? true;\n\n return (\n <div>\n <div style={{ marginBottom: space[6] }}>\n <h2 style={{ margin: 0 }}>Setup</h2>\n </div>\n {connections === null && !loadFailed && <p>Loading…</p>}\n {loadFailed && (\n <div style={{ marginBottom: space[4] }}>\n <Alert variant=\"warning\">Failed to load connections. Try refreshing.</Alert>\n </div>\n )}\n {connections && (\n <>\n {!allOk && (\n <div style={{ marginBottom: space[4] }}>\n <Alert variant=\"warning\">\n Some connections are incomplete — features that depend on them stay disabled until\n fixed. Run the connect command below, then recheck.\n </Alert>\n </div>\n )}\n <Card size=\"small\">\n {connections.map((c, idx) => (\n <ConnectionRow\n key={c.id}\n connection={c}\n isLast={idx === connections.length - 1}\n onRecheck={handleRecheck}\n rechecking={reloadingId === c.id}\n onConnect={handleConnect}\n connecting={connectingId === c.id}\n />\n ))}\n </Card>\n <div style={{ marginTop: space[4] }}>\n <Button variant=\"secondary\" size=\"small\" onClick={handleDismissToggle}>\n {setupDismissed ? 'Show Setup on open again' : \"Don't show Setup on open\"}\n </Button>\n </div>\n </>\n )}\n </div>\n );\n};\n","import { useSubjectVocabulary } from '@/app/hooks';\nimport { space } from '@/app/styles/tokens';\nimport { Button, Card, Divider } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\nexport const SubjectsSection = () => {\n const { subjects, loading, available } = useSubjectVocabulary();\n const navigate = useNavigate();\n\n return (\n <div>\n <div style={{ marginBottom: space[6] }}>\n <h2 style={{ margin: 0 }}>Subjects</h2>\n <p style={{ opacity: 0.5, marginTop: space[1] }}>\n Subjects are the roadmap's bets and standing concerns. Edit the vocabulary on the Roadmap\n page.\n </p>\n </div>\n {loading && <p>Loading…</p>}\n {!loading && !available && (\n <p style={{ opacity: 0.6, margin: 0 }}>Couldn't load subjects — check the server config.</p>\n )}\n {!loading && available && (\n <Card size=\"small\">\n {subjects.length === 0 && (\n <p style={{ opacity: 0.45, margin: 0, paddingBottom: space[2] }}>No subjects yet.</p>\n )}\n {subjects.map((name, idx) => (\n <div key={name}>\n <div style={{ paddingBottom: space[2], paddingTop: space[2] }}>{name}</div>\n {idx < subjects.length - 1 && <Divider />}\n </div>\n ))}\n {subjects.length > 0 && <Divider />}\n <div style={{ paddingTop: space[3] }}>\n <Button variant=\"secondary\" size=\"small\" onClick={() => navigate({ to: '/roadmap' })}>\n Go to Roadmap\n </Button>\n </div>\n </Card>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useActiveSettingsSection, useProjectIdentity } from '@/app/hooks';\nimport { fetchConfig, saveConfig, uploadIcon } from '@/app/services/system';\nimport { color, fontFamily, fontSize, space } from '@/app/styles/tokens';\nimport {\n AGENT_IDS,\n AGENT_LABELS,\n AGENT_OPTIONS,\n type AgentConfig,\n type AgentId,\n DEFAULT_AGENTS,\n type DefaultAgentsMap,\n type PaperCampConfig,\n} from '@/types/index';\nimport { Alert, Button, Card, Divider, Input, Select, Stamp, useToast } from '@dendelion/paper-ui';\nimport { useEffect, useRef, useState } from 'react';\nimport { MergePolicySection } from './components/merge-policy-section';\nimport { SetupSection } from './components/setup-section';\nimport { SubjectsSection } from './components/subjects-section';\n\nconst TASK_TYPE_KEYS = ['phase', 'planDraft', 'ideaExtend', 'commitSuggest'] as const;\ntype TaskTypeKey = (typeof TASK_TYPE_KEYS)[number];\n\nconst TASK_TYPE_LABELS: Record<TaskTypeKey, string> = {\n phase: 'Phase run',\n planDraft: 'Plan draft',\n ideaExtend: 'Idea extend',\n commitSuggest: 'Commit suggest',\n};\n\ninterface AgentTaskRowProps {\n taskKey: TaskTypeKey;\n agentConfig: AgentConfig;\n isLast: boolean;\n onSave: (key: TaskTypeKey, config: AgentConfig) => Promise<void>;\n}\n\nconst TASK_COLUMN_WIDTH = 110;\nconst AGENT_COLUMN_WIDTH = 140;\nconst MODEL_COLUMN_WIDTH = 160;\nconst EFFORT_COLUMN_WIDTH = 110;\n\nconst AgentTaskRowHeader = () => (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[1],\n }}\n >\n <span style={{ width: TASK_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}>\n Task\n </span>\n <span\n style={{ width: AGENT_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Agent\n </span>\n <span\n style={{ width: MODEL_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Model\n </span>\n <span\n style={{ width: EFFORT_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.45 }}\n >\n Effort\n </span>\n </div>\n);\n\nconst AgentTaskRow = ({ taskKey, agentConfig, isLast, onSave }: AgentTaskRowProps) => {\n // Fall back if the config carries an unknown agent id — never white-screen the page.\n const opts = AGENT_OPTIONS[agentConfig.agent] ?? AGENT_OPTIONS['claude-code'];\n const modelOpts = opts.model;\n const effortOpts = opts.effort;\n const [localModel, setLocalModel] = useState(agentConfig.model ?? '');\n\n useEffect(() => {\n setLocalModel(agentConfig.model ?? '');\n }, [agentConfig.model]);\n\n const handleAgentChange = (v: string) => {\n const newId = v as AgentId;\n const newOpts = AGENT_OPTIONS[newId];\n const newConfig: AgentConfig = { agent: newId };\n // Only carry the model over if the new agent accepts it — otherwise a claude\n // model like 'opus' would leak into opencode and fail at launch.\n if (\n agentConfig.model &&\n (newOpts.model === null || newOpts.model?.includes(agentConfig.model))\n ) {\n newConfig.model = agentConfig.model;\n }\n if (agentConfig.effort && Array.isArray(newOpts.effort)) newConfig.effort = agentConfig.effort;\n onSave(taskKey, newConfig);\n };\n\n const handleModelSelectChange = (v: string) => {\n onSave(taskKey, { ...agentConfig, model: v || undefined });\n };\n\n const handleModelInputBlur = () => {\n onSave(taskKey, { ...agentConfig, model: localModel || undefined });\n };\n\n const handleEffortChange = (v: string) => {\n onSave(taskKey, { ...agentConfig, effort: v || undefined });\n };\n\n return (\n <>\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[2],\n paddingTop: space[2],\n }}\n >\n <span\n style={{ width: TASK_COLUMN_WIDTH, flexShrink: 0, fontSize: fontSize.sm, opacity: 0.65 }}\n >\n {TASK_TYPE_LABELS[taskKey]}\n </span>\n <Select\n size=\"small\"\n width={AGENT_COLUMN_WIDTH}\n value={agentConfig.agent}\n onChange={handleAgentChange}\n options={AGENT_IDS.map((id) => ({ value: id, label: AGENT_LABELS[id] }))}\n />\n {Array.isArray(modelOpts) ? (\n <Select\n size=\"small\"\n width={MODEL_COLUMN_WIDTH}\n value={agentConfig.model ?? ''}\n onChange={handleModelSelectChange}\n options={[\n { value: '', label: 'Default' },\n ...modelOpts.map((m) => ({ value: m, label: m })),\n ]}\n />\n ) : modelOpts === null ? (\n <Input\n size=\"small\"\n style={{ width: MODEL_COLUMN_WIDTH }}\n value={localModel}\n placeholder=\"Default model\"\n onChange={(e) => setLocalModel(e.target.value)}\n onBlur={handleModelInputBlur}\n />\n ) : null}\n {/* Reserve the effort slot even when the agent has no effort options, so\n switching agents doesn't change the control count and shift the row. */}\n <div style={{ visibility: Array.isArray(effortOpts) ? 'visible' : 'hidden' }}>\n <Select\n size=\"small\"\n width={EFFORT_COLUMN_WIDTH}\n value={agentConfig.effort ?? ''}\n onChange={handleEffortChange}\n options={[\n { value: '', label: 'Default' },\n ...(Array.isArray(effortOpts) ? effortOpts : []).map((e) => ({ value: e, label: e })),\n ]}\n />\n </div>\n </div>\n {!isLast && <Divider />}\n </>\n );\n};\n\nconst GeneralSection = () => {\n const fileRef = useRef<HTMLInputElement>(null);\n const [config, setConfig] = useState<PaperCampConfig | null | undefined>(undefined);\n const { iconDataUri: fetchedIconDataUri, loading: identityLoading } = useProjectIdentity();\n const [uploadedIconDataUri, setUploadedIconDataUri] = useState<string | null>(null);\n const iconDataUri = uploadedIconDataUri ?? fetchedIconDataUri;\n const [uploading, setUploading] = useState(false);\n const [portInput, setPortInput] = useState('');\n const [nameInput, setNameInput] = useState('');\n const { toast } = useToast();\n\n useEffect(() => {\n fetchConfig().then((c) => {\n setConfig(c);\n if (c?.port !== undefined) setPortInput(String(c.port));\n if (c?.projectName !== undefined) setNameInput(c.projectName);\n });\n }, []);\n\n const handleSaveAgentConfig = async (key: TaskTypeKey, newEntry: AgentConfig) => {\n const current = config?.defaultAgents;\n const updated: DefaultAgentsMap = {\n phase: current?.phase ?? DEFAULT_AGENTS.phase,\n planDraft: current?.planDraft ?? DEFAULT_AGENTS.planDraft,\n ideaExtend: current?.ideaExtend ?? DEFAULT_AGENTS.ideaExtend,\n commitSuggest: current?.commitSuggest ?? DEFAULT_AGENTS.commitSuggest,\n [key]: newEntry,\n };\n const { ok, error } = await saveConfig({ defaultAgents: updated });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, defaultAgents: updated } : prev));\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleSavePort = async () => {\n const port = Number(portInput);\n if (!config || !Number.isInteger(port) || port <= 0 || port === config.port) return;\n const { ok, error } = await saveConfig({ port });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, port } : prev));\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleSaveName = async () => {\n const projectName = nameInput.trim();\n if (!config || !projectName || projectName === config.projectName) return;\n const { ok, error } = await saveConfig({ projectName });\n if (ok) {\n setConfig((prev) => (prev ? { ...prev, projectName } : prev));\n setNameInput(projectName);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', description: error, variant: 'error' });\n }\n };\n\n const handleFile = async (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (!file) return;\n setUploading(true);\n const reader = new FileReader();\n reader.onloadend = async () => {\n const dataUri = reader.result as string;\n const ok = await uploadIcon(dataUri);\n setUploading(false);\n if (ok) {\n setUploadedIconDataUri(dataUri);\n toast({ title: 'Saved', variant: 'success' });\n } else {\n toast({ title: 'Failed to save', variant: 'error' });\n }\n };\n reader.readAsDataURL(file);\n };\n\n return (\n <div>\n <div style={{ marginBottom: space[6] }}>\n <h2 style={{ margin: 0 }}>Project Info</h2>\n </div>\n {config === undefined && <p>Loading…</p>}\n {config === null && (\n <Alert variant=\"warning\">\n No papercamp/config.json found — run <code>paper-camp init</code> in this directory first.\n </Alert>\n )}\n {config && (\n <Card size=\"small\">\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n gap: space[3],\n paddingBottom: space[3],\n }}\n >\n <Input\n value={nameInput}\n onChange={(e) => setNameInput(e.target.value)}\n onBlur={handleSaveName}\n label=\"Project Name\"\n />\n <Stamp\n size=\"small\"\n fillColor=\"rgba(143, 185, 150, 0.25)\"\n textColor={color.accentGreenDark}\n >\n v{config.version}\n </Stamp>\n </div>\n <Divider />\n\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: space[3],\n paddingBottom: space[3],\n paddingTop: space[3],\n }}\n >\n {iconDataUri && (\n <img\n src={iconDataUri}\n alt=\"Project icon\"\n style={{\n width: 40,\n height: 40,\n objectFit: 'contain',\n flexShrink: 0,\n borderRadius: 4,\n }}\n />\n )}\n <div>\n {/* paper-ui has no file-input component, so this raw input is intentional */}\n <input\n ref={fileRef}\n type=\"file\"\n accept=\".svg,.png,.jpg,.jpeg,.gif,.webp\"\n onChange={handleFile}\n style={{ display: 'none' }}\n />\n <Button\n variant=\"secondary\"\n size=\"small\"\n onClick={() => fileRef.current?.click()}\n disabled={uploading}\n >\n {uploading ? 'Uploading…' : 'Choose File'}\n </Button>\n {identityLoading && (\n <p className=\"text-sm\" style={{ opacity: 0.5, margin: `${space[1]} 0 0` }}>\n Loading…\n </p>\n )}\n {!identityLoading && !iconDataUri && !uploading && (\n <p className=\"text-sm\" style={{ opacity: 0.45, margin: `${space[1]} 0 0` }}>\n No icon set.\n </p>\n )}\n </div>\n </div>\n <Divider />\n\n <div\n style={{\n display: 'flex',\n alignItems: 'flex-end',\n gap: space[3],\n paddingBottom: space[3],\n paddingTop: space[3],\n }}\n >\n <Input\n type=\"number\"\n value={portInput}\n onChange={(e) => setPortInput(e.target.value)}\n onBlur={handleSavePort}\n label=\"Port\"\n helperText=\"Default for `paper-camp dev`. Does not affect the running server.\"\n />\n </div>\n <Divider />\n\n <AgentTaskRowHeader />\n {TASK_TYPE_KEYS.map((key, idx) => (\n <AgentTaskRow\n key={key}\n taskKey={key}\n agentConfig={config.defaultAgents?.[key] ?? DEFAULT_AGENTS[key]}\n isLast={idx === TASK_TYPE_KEYS.length - 1}\n onSave={handleSaveAgentConfig}\n />\n ))}\n </Card>\n )}\n\n <p style={{ opacity: 0.45, fontSize: fontSize.sm, marginTop: space[4] }}>\n <strong>Initialized:</strong>{' '}\n {config ? new Date(config.initializedAt).toLocaleString() : '—'}\n </p>\n </div>\n );\n};\n\nexport const SettingsPage = () => {\n const section = useActiveSettingsSection();\n return (\n <div>\n <PageTitle>Settings</PageTitle>\n {section === 'subjects' ? (\n <SubjectsSection />\n ) : section === 'setup' ? (\n <SetupSection />\n ) : section === 'merge-policy' ? (\n <MergePolicySection />\n ) : (\n <GeneralSection />\n )}\n </div>\n );\n};\n","import { useActiveSettingsSection } from '@/app/hooks';\nimport { ListItem } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\n\nexport const SettingsSidebar = () => {\n const section = useActiveSettingsSection();\n const navigate = useNavigate();\n\n return (\n <>\n <SidebarSection label=\"General\">\n <ListItem\n size=\"small\"\n active={section === null}\n onClick={() => navigate({ to: '/settings' })}\n >\n Project Info\n </ListItem>\n <ListItem\n size=\"small\"\n active={section === 'setup'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'setup' } })}\n >\n Setup\n </ListItem>\n <ListItem\n size=\"small\"\n active={section === 'merge-policy'}\n onClick={() =>\n navigate({ to: '/settings/$section', params: { section: 'merge-policy' } })\n }\n >\n Merge Policy\n </ListItem>\n </SidebarSection>\n <SidebarSection label=\"Ideas\">\n <ListItem\n size=\"small\"\n active={section === 'subjects'}\n onClick={() => navigate({ to: '/settings/$section', params: { section: 'subjects' } })}\n >\n Subjects\n </ListItem>\n </SidebarSection>\n </>\n );\n};\n"],"names":["fetchMergePolicy","response","applyMergePolicy","RECOMMENDED","POLICY_ROWS","formatValue","value","matchesRecommended","policy","row","PolicyRow","label","current","recommended","isLast","matches","jsxs","Fragment","space","jsx","Divider","MergePolicySection","result","setResult","useState","applying","setApplying","toast","useToast","useEffect","handleApply","applied","upToDate","Alert","Stamp","Card","idx","Button","STATUS_STAMP","ConnectActionView","connection","onConnect","connecting","connect","CodeBlock","fontSize","ConnectionRow","onRecheck","rechecking","stamp","Tooltip","SetupSection","connections","setConnections","loadFailed","setLoadFailed","reloadingId","setReloadingId","connectingId","setConnectingId","setupDismissed","setSetupDismissed","applyConnections","useCallback","fetchConnections","fetchConfig","c","handleRecheck","id","handleConnect","updated","connectService","prev","handleDismissToggle","next","ok","saveConfig","allOk","SubjectsSection","subjects","loading","available","useSubjectVocabulary","navigate","useNavigate","name","TASK_TYPE_KEYS","TASK_TYPE_LABELS","TASK_COLUMN_WIDTH","AGENT_COLUMN_WIDTH","MODEL_COLUMN_WIDTH","EFFORT_COLUMN_WIDTH","AgentTaskRowHeader","AgentTaskRow","taskKey","agentConfig","onSave","opts","AGENT_OPTIONS","modelOpts","effortOpts","localModel","setLocalModel","handleAgentChange","v","newId","newOpts","newConfig","_a","handleModelSelectChange","handleModelInputBlur","handleEffortChange","Select","AGENT_IDS","AGENT_LABELS","m","Input","e","GeneralSection","fileRef","useRef","config","setConfig","fetchedIconDataUri","identityLoading","useProjectIdentity","uploadedIconDataUri","setUploadedIconDataUri","iconDataUri","uploading","setUploading","portInput","setPortInput","nameInput","setNameInput","handleSaveAgentConfig","key","newEntry","DEFAULT_AGENTS","error","handleSavePort","port","handleSaveName","projectName","handleFile","file","reader","dataUri","uploadIcon","color","SettingsPage","section","useActiveSettingsSection","PageTitle","SettingsSidebar","SidebarSection","ListItem"],"mappings":"oSAEO,MAAMA,GAAmB,SAA+C,CAC7E,GAAI,CACF,MAAMC,EAAW,MAAM,MAAM,mBAAmB,EAChD,OAAKA,EAAS,GACN,MAAMA,EAAS,KAAA,EADE,IAE3B,MAAQ,CACN,OAAO,IACT,CACF,EAEaC,GAAmB,SAA+C,CAC7E,GAAI,CACF,MAAMD,EAAW,MAAM,MAAM,0BAA2B,CAAE,OAAQ,OAAQ,EAC1E,OAAKA,EAAS,GACN,MAAMA,EAAS,KAAA,EADE,IAE3B,MAAQ,CACN,OAAO,IACT,CACF,ECdME,EAA2B,CAC/B,iBAAkB,GAClB,iBAAkB,GAClB,iBAAkB,GAClB,uBAAwB,WACxB,yBAA0B,SAC5B,EAEMC,EAA2D,CAC/D,CAAE,IAAK,mBAAoB,MAAO,oBAAA,EAClC,CAAE,IAAK,mBAAoB,MAAO,oBAAA,EAClC,CAAE,IAAK,mBAAoB,MAAO,oBAAA,EAClC,CAAE,IAAK,yBAA0B,MAAO,qBAAA,EACxC,CAAE,IAAK,2BAA4B,MAAO,uBAAA,CAC5C,EAEA,SAASC,EAAYC,EAAiC,CACpD,OAAO,OAAOA,GAAU,UAAaA,EAAQ,MAAQ,KAAQA,CAC/D,CAEA,SAASC,GAAmBC,EAA8B,CACxD,OAAOJ,EAAY,MAAOK,GAAQD,EAAOC,EAAI,GAAG,IAAMN,EAAYM,EAAI,GAAG,CAAC,CAC5E,CASA,MAAMC,GAAY,CAAC,CAAE,MAAAC,EAAO,QAAAC,EAAS,YAAAC,EAAa,OAAAC,KAA6B,CAC7E,MAAMC,EAAUH,IAAYC,EAC5B,OACEG,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAKE,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,EACtB,WAAYA,EAAM,CAAC,CAAA,EAGrB,SAAA,CAAAC,MAAC,QAAK,MAAO,CAAE,KAAM,CAAA,EAAM,SAAAR,EAAM,EACjCQ,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,QAASJ,EAAU,IAAO,EAAG,WAAYA,EAAU,IAAM,GAAA,EACrE,SAAAV,EAAYO,CAAO,EACtB,EACC,CAACG,GAAWC,EAAAA,KAAC,OAAA,CAAK,MAAO,CAAE,QAAS,KAAQ,SAAA,CAAA,KAAGX,EAAYQ,CAAW,CAAA,CAAA,CAAE,CAAA,CAAA,CAAA,EAE1E,CAACC,GAAUK,MAACC,EAAA,CAAA,CAAQ,CAAA,EACvB,CAEJ,EAEaC,GAAqB,IAAM,CACtC,KAAM,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAA+C,MAAS,EAC9E,CAACC,EAAUC,CAAW,EAAIF,EAAAA,SAAS,EAAK,EACxC,CAAE,MAAAG,CAAA,EAAUC,EAAA,EAElBC,EAAAA,UAAU,IAAM,CACd7B,GAAA,EAAmB,KAAKuB,CAAS,CACnC,EAAG,CAAA,CAAE,EAEL,MAAMO,EAAc,SAAY,CAC9BJ,EAAY,EAAI,EAChB,MAAMK,EAAU,MAAM7B,GAAA,EACtBwB,EAAY,EAAK,GACbK,GAAA,YAAAA,EAAS,UAAW,MACtBR,EAAUQ,CAAO,EACjBJ,EAAM,CAAE,MAAO,uBAAwB,QAAS,UAAW,GAE3DA,EAAM,CACJ,MAAO,+BACP,aAAaI,GAAA,YAAAA,EAAS,UAAW,cAAgBA,EAAQ,OAAS,OAClE,QAAS,OAAA,CACV,CAEL,EAEMC,GAAWV,GAAA,YAAAA,EAAQ,UAAW,MAAQf,GAAmBe,EAAO,MAAM,EAE5E,cACG,MAAA,CACC,SAAA,CAAAN,OAAC,OAAI,MAAO,CAAE,aAAcE,EAAM,CAAC,GACjC,SAAA,CAAAC,MAAC,MAAG,MAAO,CAAE,OAAQ,CAAA,EAAK,SAAA,eAAY,EACtCA,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAE,QAAS,GAAK,UAAWD,EAAM,CAAC,GAAK,SAAA,sGAAA,CAGjD,CAAA,EACF,EACCI,IAAW,QAAaH,EAAAA,IAAC,IAAA,CAAE,SAAA,WAAQ,EACnCG,IAAW,MAAQH,EAAAA,IAACc,EAAA,CAAM,QAAQ,UAAU,SAAA,+BAA4B,GACxEX,GAAA,YAAAA,EAAQ,UAAW,eAAiBH,EAAAA,IAACc,GAAM,QAAQ,UAAW,WAAO,MAAA,CAAO,GAC5EX,GAAA,YAAAA,EAAQ,UAAW,MAClBN,EAAAA,KAAAC,EAAAA,SAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,MAAA,CACC,MAAO,CAAE,QAAS,OAAQ,WAAY,SAAU,IAAKE,EAAM,CAAC,EAAG,aAAcA,EAAM,CAAC,CAAA,EAEpF,SAAA,CAAAC,MAAC,QAAK,MAAO,CAAE,WAAY,GAAA,EAAQ,WAAO,KAAK,EAC/CA,EAAAA,IAACe,EAAA,CACC,KAAK,QACL,UAAWF,EAAW,4BAA8B,4BACpD,UAAWA,EAAW,UAAY,UAEjC,WAAW,6BAA+B,iCAAA,CAAA,CAC7C,CAAA,CAAA,EAEFb,EAAAA,IAACgB,GAAK,KAAK,QACR,WAAY,IAAI,CAAC1B,EAAK2B,IACrBjB,EAAAA,IAACT,GAAA,CAEC,MAAOD,EAAI,MACX,QAASa,EAAO,OAAOb,EAAI,GAAG,EAC9B,YAAaN,EAAYM,EAAI,GAAG,EAChC,OAAQ2B,IAAQhC,EAAY,OAAS,CAAA,EAJhCK,EAAI,GAAA,CAMZ,EACH,EACAU,EAAAA,IAAC,OAAI,MAAO,CAAE,UAAWD,EAAM,CAAC,GAC9B,SAAAC,EAAAA,IAACkB,GAAO,KAAK,QAAQ,QAASP,EAAa,SAAUL,GAAYO,EAC9D,SAAAP,EAAW,YAAc,0BAAA,CAC5B,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EAEJ,CAEJ,ECvHMa,GAAwF,CAC5F,GAAI,CAAE,KAAM,4BAA6B,KAAM,UAAW,MAAO,OAAA,EACjE,KAAM,CAAE,KAAM,4BAA6B,KAAM,UAAW,MAAO,iBAAA,EACnE,QAAS,CAAE,KAAM,4BAA6B,KAAM,UAAW,MAAO,SAAA,CACxE,EAEMC,GAAoB,CAAC,CACzB,WAAAC,EACA,UAAAC,EACA,WAAAC,CACF,IAIM,CACJ,KAAM,CAAE,QAAAC,GAAYH,EACpB,OAAKG,EACDA,EAAQ,OAAS,WAAaA,EAAQ,SAEtCxB,EAAAA,IAACkB,EAAA,CACC,KAAK,QACL,QAAQ,YACR,QAAS,IAAMI,EAAUD,EAAW,EAAE,EACtC,SAAUE,EAET,SAAAA,EAAa,WAAa,SAASC,EAAQ,OAAO,IAAA,CAAA,EAIrDA,EAAQ,OAAS,UAEjBxB,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,UAAWD,EAAM,CAAC,CAAA,EAC9B,SAAAC,EAAAA,IAACyB,GAAA,CAAU,KAAMD,EAAQ,QAAS,EACpC,EAGAA,EAAQ,OAAS,OAEjBxB,EAAAA,IAACkB,EAAA,CACC,KAAK,QACL,QAAQ,YACR,QAAS,IAAM,OAAO,KAAKM,EAAQ,IAAK,SAAU,qBAAqB,EAEtE,SAAAA,EAAQ,KAAA,CAAA,QAKZ,IAAA,CAAE,MAAO,CAAE,QAAS,IAAM,SAAUE,EAAS,GAAI,OAAQ,GAAG3B,EAAM,CAAC,CAAC,MAAA,EAClE,WAAQ,QACX,EAlCmB,IAoCvB,EAEM4B,GAAgB,CAAC,CACrB,WAAAN,EACA,OAAA1B,EACA,UAAAiC,EACA,WAAAC,EACA,UAAAP,EACA,WAAAC,CACF,IAOM,CACJ,MAAMO,EAAQX,GAAaE,EAAW,MAAM,EAC5C,OACExB,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,MAAA,CAAI,MAAO,CAAE,cAAeE,EAAM,CAAC,EAAG,WAAYA,EAAM,CAAC,CAAA,EACxD,SAAA,CAAAF,EAAAA,KAAC,MAAA,CAAI,MAAO,CAAE,QAAS,OAAQ,WAAY,SAAU,IAAKE,EAAM,CAAC,CAAA,EAC/D,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,KAAM,EAAG,WAAY,GAAA,EAAQ,SAAAqB,EAAW,KAAA,CAAM,EAC5DA,EAAW,gBAAkB,IAC5BrB,EAAAA,IAAC+B,IAAQ,QAAQ,+BACf,SAAA/B,EAAAA,IAACe,EAAA,CAAM,KAAK,QAAQ,QAAQ,UAAU,yBAEtC,EACF,EAEFf,EAAAA,IAACe,EAAA,CAAM,KAAK,QAAQ,UAAWe,EAAM,KAAM,UAAWA,EAAM,KACzD,SAAAA,EAAM,KAAA,CACT,EACA9B,EAAAA,IAACkB,EAAA,CACC,KAAK,QACL,QAAQ,YACR,QAAS,IAAMU,EAAUP,EAAW,EAAE,EACtC,SAAUQ,EAET,WAAa,YAAc,SAAA,CAAA,CAC9B,EACF,EACAhC,EAAAA,KAAC,IAAA,CAAE,MAAO,CAAE,QAAS,IAAM,SAAU6B,EAAS,GAAI,OAAQ,GAAG3B,EAAM,CAAC,CAAC,QAAU,SAAA,CAAA,YACnEsB,EAAW,OAAA,EACvB,QACC,IAAA,CAAE,MAAO,CAAE,QAAS,GAAK,SAAUK,EAAS,GAAI,OAAQ,GAAG3B,EAAM,CAAC,CAAC,MAAA,EACjE,WAAW,OACd,EACAC,MAAC,OAAI,MAAO,CAAE,UAAWD,EAAM,CAAC,GAC9B,SAAAC,EAAAA,IAACoB,GAAA,CACC,WAAAC,EACA,UAAAC,EACA,WAAAC,CAAA,CAAA,CACF,CACF,CAAA,EACF,EACC,CAAC5B,GAAUK,MAACC,EAAA,CAAA,CAAQ,CAAA,EACvB,CAEJ,EAEa+B,GAAe,IAAM,CAChC,KAAM,CAACC,EAAaC,CAAc,EAAI7B,EAAAA,SAAoC,IAAI,EACxE,CAAC8B,EAAYC,CAAa,EAAI/B,EAAAA,SAAS,EAAK,EAC5C,CAACgC,EAAaC,CAAc,EAAIjC,EAAAA,SAAwB,IAAI,EAC5D,CAACkC,EAAcC,CAAe,EAAInC,EAAAA,SAAwB,IAAI,EAC9D,CAACoC,EAAgBC,CAAiB,EAAIrC,EAAAA,SAAS,EAAK,EACpD,CAAE,MAAAG,CAAA,EAAUC,EAAA,EAEZkC,EAAmBC,cAAazC,GAAsC,CAC1E,GAAIA,IAAW,KAAM,CACnBiC,EAAc,EAAI,EAClB,MACF,CACAA,EAAc,EAAK,EACnBF,EAAe/B,CAAM,CACvB,EAAG,CAAA,CAAE,EAELO,EAAAA,UAAU,IAAM,CACdmC,EAAA,EAAmB,KAAKF,CAAgB,EACxCG,EAAA,EAAc,KAAMC,GAAML,GAAkBK,GAAA,YAAAA,EAAG,iBAAkB,EAAK,CAAC,CACzE,EAAG,CAACJ,CAAgB,CAAC,EAErB,MAAMK,EAAgB,MAAOC,GAAe,CAC1CX,EAAeW,CAAE,EACjBN,EAAiB,MAAME,GAAkB,EACzCP,EAAe,IAAI,CACrB,EAEMY,EAAgB,MAAOD,GAAe,CAC1CT,EAAgBS,CAAE,EAClB,MAAME,EAAU,MAAMC,GAAeH,CAAE,EACnCE,EACFjB,EAAgBmB,IAASA,GAAA,YAAAA,EAAM,IAAKN,GAAOA,EAAE,KAAOE,EAAKE,EAAUJ,KAAOM,CAAI,EAE9E7C,EAAM,CAAE,MAAO,oBAAqB,QAAS,QAAS,EAExDgC,EAAgB,IAAI,CACtB,EAEMc,EAAsB,SAAY,CACtC,MAAMC,EAAO,CAACd,EACR,CAAE,GAAAe,GAAO,MAAMC,EAAW,CAAE,eAAgBF,EAAM,EACpDC,GACFd,EAAkBa,CAAI,EACtB/C,EAAM,CAAE,MAAO,QAAS,QAAS,UAAW,GAE5CA,EAAM,CAAE,MAAO,iBAAkB,QAAS,QAAS,CAEvD,EAEMkD,GAAQzB,GAAA,YAAAA,EAAa,MAAOc,GAAMA,EAAE,SAAW,QAAS,GAE9D,cACG,MAAA,CACC,SAAA,CAAA/C,MAAC,OAAI,MAAO,CAAE,aAAcD,EAAM,CAAC,CAAA,EACjC,SAAAC,EAAAA,IAAC,KAAA,CAAG,MAAO,CAAE,OAAQ,CAAA,EAAK,iBAAK,EACjC,EACCiC,IAAgB,MAAQ,CAACE,GAAcnC,EAAAA,IAAC,KAAE,SAAA,WAAQ,EAClDmC,GACCnC,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,aAAcD,EAAM,CAAC,CAAA,EACjC,SAAAC,EAAAA,IAACc,EAAA,CAAM,QAAQ,UAAU,uDAA2C,EACtE,EAEDmB,GACCpC,EAAAA,KAAAC,WAAA,CACG,SAAA,CAAA,CAAC4D,GACA1D,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,aAAcD,EAAM,CAAC,CAAA,EACjC,SAAAC,EAAAA,IAACc,EAAA,CAAM,QAAQ,UAAU,kJAGzB,EACF,EAEFd,EAAAA,IAACgB,GAAK,KAAK,QACR,WAAY,IAAI,CAAC+B,EAAG9B,IACnBjB,EAAAA,IAAC2B,GAAA,CAEC,WAAYoB,EACZ,OAAQ9B,IAAQgB,EAAY,OAAS,EACrC,UAAWe,EACX,WAAYX,IAAgBU,EAAE,GAC9B,UAAWG,EACX,WAAYX,IAAiBQ,EAAE,EAAA,EAN1BA,EAAE,EAAA,CAQV,EACH,EACA/C,EAAAA,IAAC,OAAI,MAAO,CAAE,UAAWD,EAAM,CAAC,GAC9B,SAAAC,EAAAA,IAACkB,GAAO,QAAQ,YAAY,KAAK,QAAQ,QAASoC,EAC/C,SAAAb,EAAiB,2BAA6B,2BACjD,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EAEJ,CAEJ,EC1NakB,GAAkB,IAAM,CACnC,KAAM,CAAE,SAAAC,EAAU,QAAAC,EAAS,UAAAC,CAAA,EAAcC,GAAA,EACnCC,EAAWC,EAAA,EAEjB,cACG,MAAA,CACC,SAAA,CAAApE,OAAC,OAAI,MAAO,CAAE,aAAcE,EAAM,CAAC,GACjC,SAAA,CAAAC,MAAC,MAAG,MAAO,CAAE,OAAQ,CAAA,EAAK,SAAA,WAAQ,EAClCA,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAE,QAAS,GAAK,UAAWD,EAAM,CAAC,GAAK,SAAA,iGAAA,CAGjD,CAAA,EACF,EACC8D,GAAW7D,EAAAA,IAAC,IAAA,CAAE,SAAA,UAAA,CAAQ,EACtB,CAAC6D,GAAW,CAACC,GACZ9D,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAE,QAAS,GAAK,OAAQ,CAAA,EAAK,SAAA,mDAAA,CAAiD,EAEzF,CAAC6D,GAAWC,GACXjE,EAAAA,KAACmB,EAAA,CAAK,KAAK,QACR,SAAA,CAAA4C,EAAS,SAAW,GACnB5D,EAAAA,IAAC,IAAA,CAAE,MAAO,CAAE,QAAS,IAAM,OAAQ,EAAG,cAAeD,EAAM,CAAC,GAAK,SAAA,mBAAgB,EAElF6D,EAAS,IAAI,CAACM,EAAMjD,WAClB,MAAA,CACC,SAAA,CAAAjB,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,cAAeD,EAAM,CAAC,EAAG,WAAYA,EAAM,CAAC,CAAA,EAAM,SAAAmE,CAAA,CAAK,EACpEjD,EAAM2C,EAAS,OAAS,SAAM3D,EAAA,CAAA,CAAQ,CAAA,CAAA,EAF/BiE,CAGV,CACD,EACAN,EAAS,OAAS,GAAK5D,EAAAA,IAACC,EAAA,CAAA,CAAQ,EACjCD,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,WAAYD,EAAM,CAAC,GAC/B,SAAAC,EAAAA,IAACkB,EAAA,CAAO,QAAQ,YAAY,KAAK,QAAQ,QAAS,IAAM8C,EAAS,CAAE,GAAI,WAAY,EAAG,SAAA,eAAA,CAEtF,CAAA,CACF,CAAA,CAAA,CACF,CAAA,EAEJ,CAEJ,ECvBMG,EAAiB,CAAC,QAAS,YAAa,aAAc,eAAe,EAGrEC,GAAgD,CACpD,MAAO,YACP,UAAW,aACX,WAAY,cACZ,cAAe,gBACjB,EASMC,EAAoB,IACpBC,EAAqB,IACrBC,EAAqB,IACrBC,GAAsB,IAEtBC,GAAqB,IACzB5E,EAAAA,KAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAKE,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,CAAA,EAGxB,SAAA,CAAAC,EAAAA,IAAC,OAAA,CAAK,MAAO,CAAE,MAAOqE,EAAmB,WAAY,EAAG,SAAU3C,EAAS,GAAI,QAAS,GAAA,EAAQ,SAAA,OAEhG,EACA1B,EAAAA,IAAC,OAAA,CACC,MAAO,CAAE,MAAOsE,EAAoB,WAAY,EAAG,SAAU5C,EAAS,GAAI,QAAS,GAAA,EACpF,SAAA,OAAA,CAAA,EAGD1B,EAAAA,IAAC,OAAA,CACC,MAAO,CAAE,MAAOuE,EAAoB,WAAY,EAAG,SAAU7C,EAAS,GAAI,QAAS,GAAA,EACpF,SAAA,OAAA,CAAA,EAGD1B,EAAAA,IAAC,OAAA,CACC,MAAO,CAAE,MAAOwE,GAAqB,WAAY,EAAG,SAAU9C,EAAS,GAAI,QAAS,GAAA,EACrF,SAAA,QAAA,CAAA,CAED,CAAA,CACF,EAGIgD,GAAe,CAAC,CAAE,QAAAC,EAAS,YAAAC,EAAa,OAAAjF,EAAQ,OAAAkF,KAAgC,CAEpF,MAAMC,EAAOC,EAAcH,EAAY,KAAK,GAAKG,EAAc,aAAa,EACtEC,EAAYF,EAAK,MACjBG,EAAaH,EAAK,OAClB,CAACI,EAAYC,CAAa,EAAI9E,EAAAA,SAASuE,EAAY,OAAS,EAAE,EAEpElE,EAAAA,UAAU,IAAM,CACdyE,EAAcP,EAAY,OAAS,EAAE,CACvC,EAAG,CAACA,EAAY,KAAK,CAAC,EAEtB,MAAMQ,EAAqBC,GAAc,OACvC,MAAMC,EAAQD,EACRE,EAAUR,EAAcO,CAAK,EAC7BE,EAAyB,CAAE,MAAOF,CAAA,EAItCV,EAAY,QACXW,EAAQ,QAAU,OAAQE,EAAAF,EAAQ,QAAR,MAAAE,EAAe,SAASb,EAAY,UAE/DY,EAAU,MAAQZ,EAAY,OAE5BA,EAAY,QAAU,MAAM,QAAQW,EAAQ,MAAM,IAAGC,EAAU,OAASZ,EAAY,QACxFC,EAAOF,EAASa,CAAS,CAC3B,EAEME,EAA2BL,GAAc,CAC7CR,EAAOF,EAAS,CAAE,GAAGC,EAAa,MAAOS,GAAK,OAAW,CAC3D,EAEMM,EAAuB,IAAM,CACjCd,EAAOF,EAAS,CAAE,GAAGC,EAAa,MAAOM,GAAc,OAAW,CACpE,EAEMU,EAAsBP,GAAc,CACxCR,EAAOF,EAAS,CAAE,GAAGC,EAAa,OAAQS,GAAK,OAAW,CAC5D,EAEA,OACExF,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAKE,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,EACtB,WAAYA,EAAM,CAAC,CAAA,EAGrB,SAAA,CAAAC,EAAAA,IAAC,OAAA,CACC,MAAO,CAAE,MAAOqE,EAAmB,WAAY,EAAG,SAAU3C,EAAS,GAAI,QAAS,GAAA,EAEjF,YAAiBiD,CAAO,CAAA,CAAA,EAE3B3E,EAAAA,IAAC6F,EAAA,CACC,KAAK,QACL,MAAOvB,EACP,MAAOM,EAAY,MACnB,SAAUQ,EACV,QAASU,GAAU,IAAK7C,IAAQ,CAAE,MAAOA,EAAI,MAAO8C,GAAa9C,CAAE,CAAA,EAAI,CAAA,CAAA,EAExE,MAAM,QAAQ+B,CAAS,EACtBhF,EAAAA,IAAC6F,EAAA,CACC,KAAK,QACL,MAAOtB,EACP,MAAOK,EAAY,OAAS,GAC5B,SAAUc,EACV,QAAS,CACP,CAAE,MAAO,GAAI,MAAO,SAAA,EACpB,GAAGV,EAAU,IAAKgB,IAAO,CAAE,MAAOA,EAAG,MAAOA,GAAI,CAAA,CAClD,CAAA,EAEAhB,IAAc,KAChBhF,EAAAA,IAACiG,EAAA,CACC,KAAK,QACL,MAAO,CAAE,MAAO1B,CAAA,EAChB,MAAOW,EACP,YAAY,gBACZ,SAAWgB,GAAMf,EAAce,EAAE,OAAO,KAAK,EAC7C,OAAQP,CAAA,CAAA,EAER,KAGJ3F,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,WAAY,MAAM,QAAQiF,CAAU,EAAI,UAAY,QAAA,EAChE,SAAAjF,EAAAA,IAAC6F,EAAA,CACC,KAAK,QACL,MAAOrB,GACP,MAAOI,EAAY,QAAU,GAC7B,SAAUgB,EACV,QAAS,CACP,CAAE,MAAO,GAAI,MAAO,SAAA,EACpB,IAAI,MAAM,QAAQX,CAAU,EAAIA,EAAa,CAAA,GAAI,IAAKiB,IAAO,CAAE,MAAOA,EAAG,MAAOA,GAAI,CAAA,CACtF,CAAA,CACF,CACF,CAAA,CAAA,CAAA,EAED,CAACvG,GAAUK,MAACC,EAAA,CAAA,CAAQ,CAAA,EACvB,CAEJ,EAEMkG,GAAiB,IAAM,CAC3B,MAAMC,EAAUC,EAAAA,OAAyB,IAAI,EACvC,CAACC,EAAQC,CAAS,EAAIlG,EAAAA,SAA6C,MAAS,EAC5E,CAAE,YAAamG,EAAoB,QAASC,CAAA,EAAoBC,GAAA,EAChE,CAACC,EAAqBC,CAAsB,EAAIvG,EAAAA,SAAwB,IAAI,EAC5EwG,EAAcF,GAAuBH,EACrC,CAACM,EAAWC,CAAY,EAAI1G,EAAAA,SAAS,EAAK,EAC1C,CAAC2G,EAAWC,CAAY,EAAI5G,EAAAA,SAAS,EAAE,EACvC,CAAC6G,EAAWC,CAAY,EAAI9G,EAAAA,SAAS,EAAE,EACvC,CAAE,MAAAG,CAAA,EAAUC,EAAA,EAElBC,EAAAA,UAAU,IAAM,CACdoC,EAAA,EAAc,KAAMC,GAAM,CACxBwD,EAAUxD,CAAC,GACPA,GAAA,YAAAA,EAAG,QAAS,UAAwB,OAAOA,EAAE,IAAI,CAAC,GAClDA,GAAA,YAAAA,EAAG,eAAgB,QAAWoE,EAAapE,EAAE,WAAW,CAC9D,CAAC,CACH,EAAG,CAAA,CAAE,EAEL,MAAMqE,EAAwB,MAAOC,EAAkBC,IAA0B,CAC/E,MAAM7H,EAAU6G,GAAA,YAAAA,EAAQ,cAClBnD,EAA4B,CAChC,OAAO1D,GAAA,YAAAA,EAAS,QAAS8H,EAAe,MACxC,WAAW9H,GAAA,YAAAA,EAAS,YAAa8H,EAAe,UAChD,YAAY9H,GAAA,YAAAA,EAAS,aAAc8H,EAAe,WAClD,eAAe9H,GAAA,YAAAA,EAAS,gBAAiB8H,EAAe,cACxD,CAACF,CAAG,EAAGC,CAAA,EAEH,CAAE,GAAA9D,EAAI,MAAAgE,CAAA,EAAU,MAAM/D,EAAW,CAAE,cAAeN,EAAS,EAC7DK,GACF+C,EAAWlD,GAAUA,GAAO,CAAE,GAAGA,EAAM,cAAeF,CAAA,CAAiB,EACvE3C,EAAM,CAAE,MAAO,QAAS,QAAS,UAAW,GAE5CA,EAAM,CAAE,MAAO,iBAAkB,YAAagH,EAAO,QAAS,QAAS,CAE3E,EAEMC,EAAiB,SAAY,CACjC,MAAMC,EAAO,OAAOV,CAAS,EAC7B,GAAI,CAACV,GAAU,CAAC,OAAO,UAAUoB,CAAI,GAAKA,GAAQ,GAAKA,IAASpB,EAAO,KAAM,OAC7E,KAAM,CAAE,GAAA9C,EAAI,MAAAgE,CAAA,EAAU,MAAM/D,EAAW,CAAE,KAAAiE,EAAM,EAC3ClE,GACF+C,EAAWlD,GAAUA,GAAO,CAAE,GAAGA,EAAM,KAAAqE,CAAA,CAAc,EACrDlH,EAAM,CAAE,MAAO,QAAS,QAAS,UAAW,GAE5CA,EAAM,CAAE,MAAO,iBAAkB,YAAagH,EAAO,QAAS,QAAS,CAE3E,EAEMG,EAAiB,SAAY,CACjC,MAAMC,EAAcV,EAAU,KAAA,EAC9B,GAAI,CAACZ,GAAU,CAACsB,GAAeA,IAAgBtB,EAAO,YAAa,OACnE,KAAM,CAAE,GAAA9C,EAAI,MAAAgE,CAAA,EAAU,MAAM/D,EAAW,CAAE,YAAAmE,EAAa,EAClDpE,GACF+C,EAAWlD,GAAUA,GAAO,CAAE,GAAGA,EAAM,YAAAuE,CAAA,CAAqB,EAC5DT,EAAaS,CAAW,EACxBpH,EAAM,CAAE,MAAO,QAAS,QAAS,UAAW,GAE5CA,EAAM,CAAE,MAAO,iBAAkB,YAAagH,EAAO,QAAS,QAAS,CAE3E,EAEMK,EAAa,MAAO3B,GAA2C,OACnE,MAAM4B,GAAOrC,EAAAS,EAAE,OAAO,QAAT,YAAAT,EAAiB,GAC9B,GAAI,CAACqC,EAAM,OACXf,EAAa,EAAI,EACjB,MAAMgB,EAAS,IAAI,WACnBA,EAAO,UAAY,SAAY,CAC7B,MAAMC,EAAUD,EAAO,OACjBvE,EAAK,MAAMyE,GAAWD,CAAO,EACnCjB,EAAa,EAAK,EACdvD,GACFoD,EAAuBoB,CAAO,EAC9BxH,EAAM,CAAE,MAAO,QAAS,QAAS,UAAW,GAE5CA,EAAM,CAAE,MAAO,iBAAkB,QAAS,QAAS,CAEvD,EACAuH,EAAO,cAAcD,CAAI,CAC3B,EAEA,cACG,MAAA,CACC,SAAA,CAAA9H,MAAC,OAAI,MAAO,CAAE,aAAcD,EAAM,CAAC,CAAA,EACjC,SAAAC,EAAAA,IAAC,KAAA,CAAG,MAAO,CAAE,OAAQ,CAAA,EAAK,wBAAY,EACxC,EACCsG,IAAW,QAAatG,EAAAA,IAAC,IAAA,CAAE,SAAA,WAAQ,EACnCsG,IAAW,MACVzG,OAACiB,EAAA,CAAM,QAAQ,UAAU,SAAA,CAAA,wCACcd,EAAAA,IAAC,QAAK,SAAA,iBAAA,CAAe,EAAO,2BAAA,EACnE,EAEDsG,GACCzG,EAAAA,KAACmB,EAAA,CAAK,KAAK,QACT,SAAA,CAAAnB,EAAAA,KAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,WACZ,IAAKE,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,CAAA,EAGxB,SAAA,CAAAC,EAAAA,IAACiG,EAAA,CACC,MAAOiB,EACP,SAAWhB,GAAMiB,EAAajB,EAAE,OAAO,KAAK,EAC5C,OAAQyB,EACR,MAAM,cAAA,CAAA,EAER9H,EAAAA,KAACkB,EAAA,CACC,KAAK,QACL,UAAU,4BACV,UAAWmH,GAAM,gBAClB,SAAA,CAAA,IACG5B,EAAO,OAAA,CAAA,CAAA,CACX,CAAA,CAAA,QAEDrG,EAAA,EAAQ,EAETJ,EAAAA,KAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,SACZ,IAAKE,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,EACtB,WAAYA,EAAM,CAAC,CAAA,EAGpB,SAAA,CAAA8G,GACC7G,EAAAA,IAAC,MAAA,CACC,IAAK6G,EACL,IAAI,eACJ,MAAO,CACL,MAAO,GACP,OAAQ,GACR,UAAW,UACX,WAAY,EACZ,aAAc,CAAA,CAChB,CAAA,SAGH,MAAA,CAEC,SAAA,CAAA7G,EAAAA,IAAC,QAAA,CACC,IAAKoG,EACL,KAAK,OACL,OAAO,kCACP,SAAUyB,EACV,MAAO,CAAE,QAAS,MAAA,CAAO,CAAA,EAE3B7H,EAAAA,IAACkB,EAAA,CACC,QAAQ,YACR,KAAK,QACL,QAAS,IAAA,OAAM,OAAAuE,EAAAW,EAAQ,UAAR,YAAAX,EAAiB,SAChC,SAAUqB,EAET,WAAY,aAAe,aAAA,CAAA,EAE7BL,GACCzG,EAAAA,IAAC,IAAA,CAAE,UAAU,UAAU,MAAO,CAAE,QAAS,GAAK,OAAQ,GAAGD,EAAM,CAAC,CAAC,QAAU,SAAA,WAE3E,EAED,CAAC0G,GAAmB,CAACI,GAAe,CAACC,GACpC9G,EAAAA,IAAC,KAAE,UAAU,UAAU,MAAO,CAAE,QAAS,IAAM,OAAQ,GAAGD,EAAM,CAAC,CAAC,MAAA,EAAU,SAAA,cAAA,CAE5E,CAAA,CAAA,CAEJ,CAAA,CAAA,CAAA,QAEDE,EAAA,EAAQ,EAETD,EAAAA,IAAC,MAAA,CACC,MAAO,CACL,QAAS,OACT,WAAY,WACZ,IAAKD,EAAM,CAAC,EACZ,cAAeA,EAAM,CAAC,EACtB,WAAYA,EAAM,CAAC,CAAA,EAGrB,SAAAC,EAAAA,IAACiG,EAAA,CACC,KAAK,SACL,MAAOe,EACP,SAAWd,GAAMe,EAAaf,EAAE,OAAO,KAAK,EAC5C,OAAQuB,EACR,MAAM,OACN,WAAW,mEAAA,CAAA,CACb,CAAA,QAEDxH,EAAA,EAAQ,QAERwE,GAAA,EAAmB,EACnBN,EAAe,IAAI,CAACkD,EAAKpG,IAAA,OACxBjB,OAAAA,EAAAA,IAAC0E,GAAA,CAEC,QAAS2C,EACT,cAAa5B,EAAAa,EAAO,gBAAP,YAAAb,EAAuB4B,KAAQE,EAAeF,CAAG,EAC9D,OAAQpG,IAAQkD,EAAe,OAAS,EACxC,OAAQiD,CAAA,EAJHC,CAAA,EAMR,CAAA,EACH,EAGFxH,EAAAA,KAAC,IAAA,CAAE,MAAO,CAAE,QAAS,IAAM,SAAU6B,EAAS,GAAI,UAAW3B,EAAM,CAAC,GAClE,SAAA,CAAAC,EAAAA,IAAC,UAAO,SAAA,cAAA,CAAY,EAAU,IAC7BsG,EAAS,IAAI,KAAKA,EAAO,aAAa,EAAE,iBAAmB,GAAA,CAAA,CAC9D,CAAA,EACF,CAEJ,EAEa6B,GAAe,IAAM,CAChC,MAAMC,EAAUC,EAAA,EAChB,cACG,MAAA,CACC,SAAA,CAAArI,EAAAA,IAACsI,IAAU,SAAA,UAAA,CAAQ,EAClBF,IAAY,WACXpI,EAAAA,IAAC2D,GAAA,CAAA,CAAgB,EACfyE,IAAY,QACdpI,MAACgC,GAAA,CAAA,CAAa,EACZoG,IAAY,eACdpI,EAAAA,IAACE,GAAA,EAAmB,QAEnBiG,GAAA,CAAA,CAAe,CAAA,EAEpB,CAEJ,EC9YaoC,GAAkB,IAAM,CACnC,MAAMH,EAAUC,EAAA,EACVrE,EAAWC,EAAA,EAEjB,OACEpE,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC2I,EAAA,CAAe,MAAM,UACpB,SAAA,CAAAxI,EAAAA,IAACyI,EAAA,CACC,KAAK,QACL,OAAQL,IAAY,KACpB,QAAS,IAAMpE,EAAS,CAAE,GAAI,YAAa,EAC5C,SAAA,cAAA,CAAA,EAGDhE,EAAAA,IAACyI,EAAA,CACC,KAAK,QACL,OAAQL,IAAY,QACpB,QAAS,IAAMpE,EAAS,CAAE,GAAI,qBAAsB,OAAQ,CAAE,QAAS,OAAA,EAAW,EACnF,SAAA,OAAA,CAAA,EAGDhE,EAAAA,IAACyI,EAAA,CACC,KAAK,QACL,OAAQL,IAAY,eACpB,QAAS,IACPpE,EAAS,CAAE,GAAI,qBAAsB,OAAQ,CAAE,QAAS,cAAA,EAAkB,EAE7E,SAAA,cAAA,CAAA,CAED,EACF,EACAhE,EAAAA,IAACwI,EAAA,CAAe,MAAM,QACpB,SAAAxI,EAAAA,IAACyI,EAAA,CACC,KAAK,QACL,OAAQL,IAAY,WACpB,QAAS,IAAMpE,EAAS,CAAE,GAAI,qBAAsB,OAAQ,CAAE,QAAS,UAAA,EAAc,EACtF,SAAA,UAAA,CAAA,CAED,CACF,CAAA,EACF,CAEJ"}
@@ -0,0 +1,3 @@
1
+ import{u as m,F as L,r,j as e,P as T,s as x,p as f,b as g,E as A,f as v,O as D,c as j,G as N,Z as E}from"./main-Bno8vU-0.js";const b={phase:"Phase run",audit:"Audit","batch-reconcile":"Batch reconcile","run-all":"Run all phases",draft:"Draft",extend:"Extend",suggest:"Suggest ideas","commit-suggest":"Commit suggest","overlap-check":"Overlap check",prioritise:"Prioritise queue",sync:"Sync",reconcile:"Reconcile",rework:"Apply notes","fix-review":"Fix review","review-split":"Split review"},h=s=>String(s).padStart(2,"0"),R=s=>{const a=new Date(s);return`${a.getFullYear()}-${h(a.getMonth()+1)}-${h(a.getDate())}`},I=s=>new Date(s).toLocaleDateString(void 0,{weekday:"long",year:"numeric",month:"long",day:"numeric"}),w=s=>{const a=new Date(s);return`${h(a.getHours())}:${h(a.getMinutes())}:${h(a.getSeconds())}`},p={fontSize:g.sm,fontWeight:600,opacity:.6,whiteSpace:"nowrap",overflow:"hidden"},z=({id:s})=>{const[a,l]=r.useState(null),[o,c]=r.useState(!1),[i,u]=r.useState(0);r.useEffect(()=>{let n=!1,d;l(null),c(!1);const y=k=>{N(s).then(S=>{n||l(S.lines??[])}).catch(()=>{if(!n){if(k>0){d=setTimeout(()=>y(k-1),700);return}c(!0),l([])}})};return y(3),()=>{n=!0,d&&clearTimeout(d)}},[s,i]);const t=e.jsx(E,{variant:"ghost",size:"small",onClick:()=>u(n=>n+1),children:"Retry"});return a===null?e.jsx("p",{style:{opacity:.5,margin:0},children:"Loading…"}):o?e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:x[2]},children:[e.jsx("p",{style:{opacity:.5,margin:0},children:"Couldn't load this task's output."}),t]}):a.length===0?e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:x[2]},children:[e.jsx("p",{style:{opacity:.5,margin:0},children:"No output recorded."}),t]}):e.jsx("pre",{style:{fontFamily:v.mono,fontSize:g.xs,margin:0,maxHeight:320,overflowY:"auto",whiteSpace:"pre-wrap"},children:a.join(`
2
+ `)})},C=({size:s=14})=>e.jsx("svg",{width:s,height:s,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:e.jsx("polyline",{points:"9 18 15 12 9 6"})}),F=({entry:s,highlighted:a})=>{const[l,o]=r.useState(a);r.useEffect(()=>{a&&o(!0)},[a]);const c=()=>o(i=>!i);return e.jsxs("div",{className:a?"task-row-highlighted":void 0,style:{display:"flex",flexDirection:"column",gap:x[1],borderRadius:10},children:[e.jsx("div",{role:"button",tabIndex:0,onClick:c,onKeyDown:i=>{(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),c())},style:{cursor:"pointer",borderRadius:10},children:e.jsx(f,{size:"small",texture:"canvas",className:"plan-row-card",children:e.jsxs("div",{className:"task-rows-grid",children:[e.jsx("span",{className:"task-rows-chevron","aria-expanded":l,style:{display:"inline-flex",alignItems:"center",opacity:.5},children:e.jsx(C,{})}),e.jsx("span",{style:{fontWeight:600,whiteSpace:"nowrap",overflow:"hidden"},children:b[s.taskKind]}),e.jsx("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",opacity:.7},children:s.planTitle}),e.jsx("span",{className:"text-sm",style:{opacity:.5,whiteSpace:"nowrap"},children:A[s.agentId]}),e.jsxs("span",{className:"task-rows-cell-time",style:{fontFamily:v.mono,fontSize:g.xs,opacity:.55,whiteSpace:"nowrap"},children:[w(s.startedAt),"–",w(s.endedAt)]}),e.jsx("div",{style:{display:"flex",alignItems:"center"},children:e.jsx(D,{size:"small",fillColor:s.outcome==="done"?"rgba(143, 185, 150, 0.25)":"rgba(201, 139, 139, 0.25)",textColor:s.outcome==="done"?j.accentGreenDark:j.accentRoseDark,children:s.outcome})})]})})}),l&&e.jsx(f,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsx(z,{id:s.id})})]})},$=()=>{const s=m(t=>t.taskLog),a=m(t=>t.taskLogLoading),l=m(t=>t.loadTaskLog),{taskId:o}=L({from:"/tasks"}),c=r.useRef(null);r.useEffect(()=>{l()},[l]),r.useEffect(()=>{var n;if(!o)return;const t=(n=c.current)==null?void 0:n.querySelector(".task-row-highlighted");t==null||t.scrollIntoView({behavior:"smooth",block:"center"})},[o]);const i=[...s].sort((t,n)=>n.endedAt.localeCompare(t.endedAt)),u=[];for(const t of i){const n=R(t.endedAt),d=u.at(-1);(d==null?void 0:d.key)===n?d.entries.push(t):u.push({key:n,entries:[t]})}return e.jsxs("div",{ref:c,children:[e.jsx(T,{children:"Tasks"}),a&&e.jsx("p",{style:{opacity:.5},children:"Loading…"}),!a&&i.length===0&&e.jsx("p",{style:{opacity:.5},children:"No tasks have run yet."}),!a&&i.length>0&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:x[1]},children:[e.jsx(f,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsxs("div",{className:"task-rows-grid",children:[e.jsx("span",{}),e.jsx("span",{style:p,children:"Task"}),e.jsx("span",{style:p,children:"Plan"}),e.jsx("span",{style:p,children:"Agent"}),e.jsx("span",{className:"task-rows-cell-time",style:p,children:"Time"}),e.jsx("span",{style:p,children:"Outcome"})]})}),u.map(t=>e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:x[1]},children:[e.jsx(f,{size:"small",texture:"kraft",className:"plan-row-card",children:e.jsx("span",{style:{...p,opacity:.75},children:I(t.entries[0].endedAt)})}),t.entries.map(n=>e.jsx(F,{entry:n,highlighted:n.id===o},n.id))]},t.key))]})]})};export{$ as TasksPage};
3
+ //# sourceMappingURL=index-DAexv1XS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DAexv1XS.js","sources":["../../../src/app/features/tasks/tasks-page.tsx"],"sourcesContent":["import { PageTitle } from '@/app/components/page-title';\nimport { fetchTaskLogLines } from '@/app/services/content/docs-api';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, space } from '@/app/styles/tokens';\nimport { AGENT_LABELS, type TaskKind, type TaskLogEntry } from '@/types/index';\nimport { Button, Card, Stamp } from '@dendelion/paper-ui';\nimport { useSearch } from '@tanstack/react-router';\nimport { useEffect, useRef, useState } from 'react';\n\nconst TASK_KIND_LABELS: Record<TaskKind, string> = {\n phase: 'Phase run',\n audit: 'Audit',\n 'batch-reconcile': 'Batch reconcile',\n 'run-all': 'Run all phases',\n draft: 'Draft',\n extend: 'Extend',\n suggest: 'Suggest ideas',\n 'commit-suggest': 'Commit suggest',\n 'overlap-check': 'Overlap check',\n prioritise: 'Prioritise queue',\n sync: 'Sync',\n reconcile: 'Reconcile',\n rework: 'Apply notes',\n 'fix-review': 'Fix review',\n 'review-split': 'Split review',\n};\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\nconst dayKey = (iso: string) => {\n const d = new Date(iso);\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n};\n\nconst formatDayHeader = (iso: string) =>\n new Date(iso).toLocaleDateString(undefined, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n\nconst formatTime = (iso: string) => {\n const d = new Date(iso);\n return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;\n};\n\nconst headerLabelStyle: React.CSSProperties = {\n fontSize: fontSize.sm,\n fontWeight: 600,\n opacity: 0.6,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n};\n\nconst TaskLogLines = ({ id }: { id: string }) => {\n const [lines, setLines] = useState<string[] | null>(null);\n const [failed, setFailed] = useState(false);\n const [attempt, setAttempt] = useState(0);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: attempt is the retry trigger (re-runs the fetch), not a value read in the body.\n useEffect(() => {\n let cancelled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n setLines(null);\n setFailed(false);\n // Auto-retry first (dev server briefly drops requests on hot reload); manual Retry only if it stays down.\n const load = (remaining: number) => {\n fetchTaskLogLines(id)\n .then((data) => {\n if (cancelled) return;\n setLines(data.lines ?? []);\n })\n .catch(() => {\n if (cancelled) return;\n if (remaining > 0) {\n timer = setTimeout(() => load(remaining - 1), 700);\n return;\n }\n // Empty result != failed request: conflating them mislabels a fetch error as \"no output\".\n setFailed(true);\n setLines([]);\n });\n };\n load(3);\n return () => {\n cancelled = true;\n if (timer) clearTimeout(timer);\n };\n }, [id, attempt]);\n\n const retry = (\n <Button variant=\"ghost\" size=\"small\" onClick={() => setAttempt((n) => n + 1)}>\n Retry\n </Button>\n );\n\n if (lines === null) return <p style={{ opacity: 0.5, margin: 0 }}>Loading…</p>;\n if (failed)\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2] }}>\n <p style={{ opacity: 0.5, margin: 0 }}>Couldn't load this task's output.</p>\n {retry}\n </div>\n );\n if (lines.length === 0)\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: space[2] }}>\n <p style={{ opacity: 0.5, margin: 0 }}>No output recorded.</p>\n {retry}\n </div>\n );\n return (\n <pre\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n margin: 0,\n maxHeight: 320,\n overflowY: 'auto',\n whiteSpace: 'pre-wrap',\n }}\n >\n {lines.join('\\n')}\n </pre>\n );\n};\n\nconst ChevronRightIcon = ({ size = 14 }: { size?: number }) => (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <polyline points=\"9 18 15 12 9 6\" />\n </svg>\n);\n\nconst TaskRow = ({ entry, highlighted }: { entry: TaskLogEntry; highlighted: boolean }) => {\n const [expanded, setExpanded] = useState(highlighted);\n useEffect(() => {\n if (highlighted) setExpanded(true);\n }, [highlighted]);\n const toggle = () => setExpanded((v) => !v);\n\n return (\n <div\n className={highlighted ? 'task-row-highlighted' : undefined}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1], borderRadius: 10 }}\n >\n {/* biome-ignore lint/a11y/useSemanticElements: the clickable row wraps a Card whose block layout a native <button> would break; keyboard toggling is wired on the div. */}\n <div\n role=\"button\"\n tabIndex={0}\n onClick={toggle}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n toggle();\n }\n }}\n style={{ cursor: 'pointer', borderRadius: 10 }}\n >\n <Card size=\"small\" texture=\"canvas\" className=\"plan-row-card\">\n <div className=\"task-rows-grid\">\n <span\n className=\"task-rows-chevron\"\n aria-expanded={expanded}\n style={{ display: 'inline-flex', alignItems: 'center', opacity: 0.5 }}\n >\n <ChevronRightIcon />\n </span>\n <span style={{ fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden' }}>\n {TASK_KIND_LABELS[entry.taskKind]}\n </span>\n <span\n style={{\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n opacity: 0.7,\n }}\n >\n {entry.planTitle}\n </span>\n <span className=\"text-sm\" style={{ opacity: 0.5, whiteSpace: 'nowrap' }}>\n {AGENT_LABELS[entry.agentId]}\n </span>\n <span\n className=\"task-rows-cell-time\"\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n opacity: 0.55,\n whiteSpace: 'nowrap',\n }}\n >\n {formatTime(entry.startedAt)}–{formatTime(entry.endedAt)}\n </span>\n <div style={{ display: 'flex', alignItems: 'center' }}>\n <Stamp\n size=\"small\"\n fillColor={\n entry.outcome === 'done'\n ? 'rgba(143, 185, 150, 0.25)'\n : 'rgba(201, 139, 139, 0.25)'\n }\n textColor={entry.outcome === 'done' ? color.accentGreenDark : color.accentRoseDark}\n >\n {entry.outcome}\n </Stamp>\n </div>\n </div>\n </Card>\n </div>\n {expanded && (\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <TaskLogLines id={entry.id} />\n </Card>\n )}\n </div>\n );\n};\n\nexport const TasksPage = () => {\n const taskLog = useAppStore((s) => s.taskLog);\n const taskLogLoading = useAppStore((s) => s.taskLogLoading);\n const loadTaskLog = useAppStore((s) => s.loadTaskLog);\n const { taskId } = useSearch({ from: '/tasks' });\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n loadTaskLog();\n }, [loadTaskLog]);\n\n useEffect(() => {\n if (!taskId) return;\n const row = containerRef.current?.querySelector('.task-row-highlighted');\n row?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }, [taskId]);\n\n const sorted = [...taskLog].sort((a, b) => b.endedAt.localeCompare(a.endedAt));\n\n const groups: { key: string; entries: TaskLogEntry[] }[] = [];\n for (const entry of sorted) {\n const key = dayKey(entry.endedAt);\n const group = groups.at(-1);\n if (group?.key === key) group.entries.push(entry);\n else groups.push({ key, entries: [entry] });\n }\n\n return (\n <div ref={containerRef}>\n <PageTitle>Tasks</PageTitle>\n {taskLogLoading && <p style={{ opacity: 0.5 }}>Loading…</p>}\n {!taskLogLoading && sorted.length === 0 && (\n <p style={{ opacity: 0.5 }}>No tasks have run yet.</p>\n )}\n {!taskLogLoading && sorted.length > 0 && (\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <div className=\"task-rows-grid\">\n <span />\n <span style={headerLabelStyle}>Task</span>\n <span style={headerLabelStyle}>Plan</span>\n <span style={headerLabelStyle}>Agent</span>\n <span className=\"task-rows-cell-time\" style={headerLabelStyle}>\n Time\n </span>\n <span style={headerLabelStyle}>Outcome</span>\n </div>\n </Card>\n {groups.map((group) => (\n <div\n key={group.key}\n style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}\n >\n <Card size=\"small\" texture=\"kraft\" className=\"plan-row-card\">\n <span style={{ ...headerLabelStyle, opacity: 0.75 }}>\n {formatDayHeader(group.entries[0].endedAt)}\n </span>\n </Card>\n {group.entries.map((entry) => (\n <TaskRow key={entry.id} entry={entry} highlighted={entry.id === taskId} />\n ))}\n </div>\n ))}\n </div>\n )}\n </div>\n );\n};\n"],"names":["TASK_KIND_LABELS","pad","n","dayKey","iso","d","formatDayHeader","formatTime","headerLabelStyle","fontSize","TaskLogLines","id","lines","setLines","useState","failed","setFailed","attempt","setAttempt","useEffect","cancelled","timer","load","remaining","fetchTaskLogLines","data","retry","jsx","Button","jsxs","space","fontFamily","ChevronRightIcon","size","TaskRow","entry","highlighted","expanded","setExpanded","toggle","v","e","Card","AGENT_LABELS","Stamp","color","TasksPage","taskLog","useAppStore","s","taskLogLoading","loadTaskLog","taskId","useSearch","containerRef","useRef","row","_a","sorted","a","b","groups","key","group","PageTitle"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{u as a,a as m,j as e,s as d,Z as j,f as p,d as v,c as S,l as x,b as f,M as b,e as D,h as w,P as T,r as C,X as k,o as L}from"./main-Bno8vU-0.js";import{S as $}from"./sidebar-section-BrJbBK_b.js";const g=(t,r)=>t.toLowerCase().includes(r.toLowerCase()),Q=(t,r,c=120)=>{const l=t.toLowerCase().indexOf(r.toLowerCase());if(l===-1)return t.slice(0,c);const n=Math.max(0,l-40),i=Math.min(t.length,l+r.length+40);let h=t.slice(n,i);return n>0&&(h=`…${h}`),i<t.length&&(h=`${h}…`),h},z=({query:t})=>{const r=a(o=>o.repoDocs),c=a(o=>o.setActiveDocTitle),l=a(o=>o.setDocSearchQuery),n=m(),i=[];for(const o of r)(g(o.name,t)||g(o.content,t))&&i.push({title:o.name,snippet:Q(o.content,t)});const h=o=>{n({to:"/docs/$section",params:{section:"repo-docs"}}),c(o),l("")};return i.length===0?e.jsxs("p",{style:{opacity:.5},children:['No results found for "',t,'".']}):e.jsxs("div",{children:[e.jsxs("p",{className:"text-sm",style:{opacity:.5,marginBottom:d[3]},children:[i.length," result",i.length===1?"":"s",' for "',t,'"']}),e.jsx("div",{style:{display:"flex",flexDirection:"column",gap:d[1]},children:i.map(o=>e.jsx(j,{variant:"ghost",size:"small",fullWidth:!0,onClick:()=>h(o.title),style:{justifyContent:"flex-start",padding:`${d[2]} ${d[3]}`},children:e.jsxs("span",{style:{textAlign:"left"},children:[e.jsx("span",{style:{fontFamily:p.serif,fontWeight:600,fontSize:"0.95rem",display:"block",marginBottom:"0.2rem"},children:o.title}),e.jsx("span",{className:"text-sm",style:{opacity:.6},children:o.snippet})]})},o.title))})]})},A=()=>{const t=a(n=>n.repoDocs),r=a(n=>n.activeDocTitle),c=t.find(n=>n.name===r);if(!c)return null;const l=c.name.endsWith(".md");return e.jsxs("div",{children:[e.jsx("h2",{style:{...v,margin:`0 0 ${d[4]}`},children:c.name}),l?e.jsx("div",{style:{fontFamily:p.body,fontSize:f.base,lineHeight:x.relaxed,color:S.textProse},children:e.jsx(b,{children:c.content})}):e.jsx("pre",{style:{fontFamily:p.mono,fontSize:f.xs,background:"rgba(0,0,0,0.04)",borderRadius:6,padding:d[4],overflowX:"auto",lineHeight:x.normal,whiteSpace:"pre-wrap"},children:c.content})]})},F=()=>{const t=a(i=>i.docSearchQuery),r=a(i=>i.activeDocTitle),c=m(),l=D(),n=()=>c({to:"/docs"});return t.trim()?e.jsx("div",{children:e.jsx(z,{query:t})}):l==="repo-docs"&&r?e.jsxs("div",{children:[e.jsx("div",{style:{marginBottom:d[4]},children:e.jsx(w,{items:[{id:"docs",label:"Docs",onClick:n},{id:"repo-doc",label:r}]})}),e.jsx(A,{})]}):e.jsxs("div",{children:[e.jsx(T,{children:"Docs"}),e.jsx("p",{style:{opacity:.5},children:"Pick a doc from the sidebar — start with a repo doc if you're new here."})]})},R=t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase(),u=({children:t})=>e.jsx("span",{className:"text-sm",style:{display:"block",padding:`${d[1]} ${d[3]}`,opacity:.35,fontStyle:"italic"},children:t}),M=()=>{const t=a(s=>s.repoDocs),r=a(s=>s.repoDocsLoading),c=a(s=>s.loadRepoDocs),l=a(s=>s.activeDocTitle),n=a(s=>s.setActiveDocTitle),i=a(s=>s.docSearchQuery),h=a(s=>s.setDocSearchQuery),o=D(),y=m();return C.useEffect(()=>{c()},[c]),e.jsxs(e.Fragment,{children:[e.jsx("div",{style:{marginBottom:d[4]},children:e.jsx(k,{size:"small","aria-label":"Search docs",placeholder:"Search docs…",value:i,onChange:s=>h(s.target.value)})}),e.jsx($,{label:"Repo Docs",children:r&&t.length===0?e.jsx(u,{children:"Loading…"}):t.length>0?t.map(s=>e.jsx(L,{size:"small",active:o==="repo-docs"&&l===s.name,onClick:()=>{y({to:"/docs/$section",params:{section:"repo-docs"}}),n(s.name)},children:R(s.name)},s.name)):e.jsx(u,{children:"No repo docs found"})})]})};export{F as DocsPage,M as DocsSidebar};
2
+ //# sourceMappingURL=index-DFJlDY3W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-DFJlDY3W.js","sources":["../../../src/app/features/docs/components/docs-search.tsx","../../../src/app/features/docs/components/repo-doc-detail.tsx","../../../src/app/features/docs/docs-page.tsx","../../../src/app/features/docs/components/docs-sidebar.tsx"],"sourcesContent":["import { useAppStore } from '@/app/stores/app-store';\nimport { fontFamily, space } from '@/app/styles/tokens';\nimport { Button } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\n\ninterface SearchMatch {\n title: string;\n snippet: string;\n}\n\ninterface DocsSearchProps {\n query: string;\n}\n\nconst searchIn = (text: string, query: string): boolean =>\n text.toLowerCase().includes(query.toLowerCase());\n\nconst snippet = (text: string, query: string, maxLen = 120): string => {\n const idx = text.toLowerCase().indexOf(query.toLowerCase());\n if (idx === -1) return text.slice(0, maxLen);\n const start = Math.max(0, idx - 40);\n const end = Math.min(text.length, idx + query.length + 40);\n let s = text.slice(start, end);\n if (start > 0) s = `…${s}`;\n if (end < text.length) s = `${s}…`;\n return s;\n};\n\nexport const DocsSearch = ({ query }: DocsSearchProps) => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const navigate = useNavigate();\n\n const results: SearchMatch[] = [];\n\n for (const f of repoDocs) {\n if (searchIn(f.name, query) || searchIn(f.content, query)) {\n results.push({\n title: f.name,\n snippet: snippet(f.content, query),\n });\n }\n }\n\n const handleSelect = (title: string) => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(title);\n setDocSearchQuery('');\n };\n\n if (results.length === 0) {\n return <p style={{ opacity: 0.5 }}>No results found for \"{query}\".</p>;\n }\n\n return (\n <div>\n <p className=\"text-sm\" style={{ opacity: 0.5, marginBottom: space[3] }}>\n {results.length} result{results.length === 1 ? '' : 's'} for \"{query}\"\n </p>\n <div style={{ display: 'flex', flexDirection: 'column', gap: space[1] }}>\n {results.map((m) => (\n <Button\n key={m.title}\n variant=\"ghost\"\n size=\"small\"\n fullWidth\n onClick={() => handleSelect(m.title)}\n style={{ justifyContent: 'flex-start', padding: `${space[2]} ${space[3]}` }}\n >\n <span style={{ textAlign: 'left' }}>\n <span\n style={{\n fontFamily: fontFamily.serif,\n fontWeight: 600,\n fontSize: '0.95rem',\n display: 'block',\n marginBottom: '0.2rem',\n }}\n >\n {m.title}\n </span>\n <span className=\"text-sm\" style={{ opacity: 0.6 }}>\n {m.snippet}\n </span>\n </span>\n </Button>\n ))}\n </div>\n </div>\n );\n};\n","import { detailHeadingStyle } from '@/app/components/detail-heading-style';\nimport { Markdown } from '@/app/components/markdown';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { color, fontFamily, fontSize, lineHeight, space } from '@/app/styles/tokens';\n\nexport const RepoDocDetail = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n\n const file = repoDocs.find((f) => f.name === activeDocTitle);\n if (!file) return null;\n\n const isMarkdown = file.name.endsWith('.md');\n\n return (\n <div>\n <h2 style={{ ...detailHeadingStyle, margin: `0 0 ${space[4]}` }}>{file.name}</h2>\n\n {isMarkdown ? (\n <div\n style={{\n fontFamily: fontFamily.body,\n fontSize: fontSize.base,\n lineHeight: lineHeight.relaxed,\n color: color.textProse,\n }}\n >\n <Markdown>{file.content}</Markdown>\n </div>\n ) : (\n <pre\n style={{\n fontFamily: fontFamily.mono,\n fontSize: fontSize.xs,\n background: 'rgba(0,0,0,0.04)',\n borderRadius: 6,\n padding: space[4],\n overflowX: 'auto',\n lineHeight: lineHeight.normal,\n whiteSpace: 'pre-wrap',\n }}\n >\n {file.content}\n </pre>\n )}\n </div>\n );\n};\n","import { PageTitle } from '@/app/components/page-title';\nimport { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { space } from '@/app/styles/tokens';\nimport { Breadcrumb } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { DocsSearch } from './components/docs-search';\nimport { RepoDocDetail } from './components/repo-doc-detail';\n\nexport const DocsPage = () => {\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const navigate = useNavigate();\n const activeDocSection = useResolvedDocSection();\n\n const handleBackToDocs = () => navigate({ to: '/docs' });\n\n if (docSearchQuery.trim()) {\n return (\n <div>\n <DocsSearch query={docSearchQuery} />\n </div>\n );\n }\n\n if (activeDocSection === 'repo-docs' && activeDocTitle) {\n return (\n <div>\n <div style={{ marginBottom: space[4] }}>\n <Breadcrumb\n items={[\n { id: 'docs', label: 'Docs', onClick: handleBackToDocs },\n { id: 'repo-doc', label: activeDocTitle },\n ]}\n />\n </div>\n <RepoDocDetail />\n </div>\n );\n }\n\n return (\n <div>\n <PageTitle>Docs</PageTitle>\n <p style={{ opacity: 0.5 }}>\n Pick a doc from the sidebar — start with a repo doc if you're new here.\n </p>\n </div>\n );\n};\n","import { useResolvedDocSection } from '@/app/hooks';\nimport { useAppStore } from '@/app/stores/app-store';\nimport { space } from '@/app/styles/tokens';\nimport { Input, ListItem } from '@dendelion/paper-ui';\nimport { useNavigate } from '@tanstack/react-router';\nimport { useEffect } from 'react';\nimport { SidebarSection } from '../../plans/components/sidebar-section';\n\nconst simplecaseLabel = (name: string) =>\n name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();\n\nconst EmptyState = ({ children }: { children: React.ReactNode }) => (\n <span\n className=\"text-sm\"\n style={{\n display: 'block',\n padding: `${space[1]} ${space[3]}`,\n opacity: 0.35,\n fontStyle: 'italic',\n }}\n >\n {children}\n </span>\n);\n\nexport const DocsSidebar = () => {\n const repoDocs = useAppStore((s) => s.repoDocs);\n const repoDocsLoading = useAppStore((s) => s.repoDocsLoading);\n const loadRepoDocs = useAppStore((s) => s.loadRepoDocs);\n const activeDocTitle = useAppStore((s) => s.activeDocTitle);\n const setActiveDocTitle = useAppStore((s) => s.setActiveDocTitle);\n const docSearchQuery = useAppStore((s) => s.docSearchQuery);\n const setDocSearchQuery = useAppStore((s) => s.setDocSearchQuery);\n const activeDocSection = useResolvedDocSection();\n const navigate = useNavigate();\n\n useEffect(() => {\n loadRepoDocs();\n }, [loadRepoDocs]);\n\n return (\n <>\n <div style={{ marginBottom: space[4] }}>\n <Input\n size=\"small\"\n aria-label=\"Search docs\"\n placeholder=\"Search docs…\"\n value={docSearchQuery}\n onChange={(e) => setDocSearchQuery(e.target.value)}\n />\n </div>\n\n <SidebarSection label=\"Repo Docs\">\n {repoDocsLoading && repoDocs.length === 0 ? (\n <EmptyState>Loading…</EmptyState>\n ) : repoDocs.length > 0 ? (\n repoDocs.map((f) => (\n <ListItem\n key={f.name}\n size=\"small\"\n active={activeDocSection === 'repo-docs' && activeDocTitle === f.name}\n onClick={() => {\n navigate({ to: '/docs/$section', params: { section: 'repo-docs' } });\n setActiveDocTitle(f.name);\n }}\n >\n {simplecaseLabel(f.name)}\n </ListItem>\n ))\n ) : (\n <EmptyState>No repo docs found</EmptyState>\n )}\n </SidebarSection>\n </>\n );\n};\n"],"names":["searchIn","text","query","snippet","maxLen","idx","start","end","s","DocsSearch","repoDocs","useAppStore","setActiveDocTitle","setDocSearchQuery","navigate","useNavigate","results","f","handleSelect","title","jsxs","space","m","jsx","Button","fontFamily","RepoDocDetail","activeDocTitle","file","isMarkdown","detailHeadingStyle","fontSize","lineHeight","color","Markdown","DocsPage","docSearchQuery","activeDocSection","useResolvedDocSection","handleBackToDocs","Breadcrumb","PageTitle","simplecaseLabel","name","EmptyState","children","DocsSidebar","repoDocsLoading","loadRepoDocs","useEffect","Fragment","Input","e","SidebarSection","ListItem"],"mappings":"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"}