fifony 0.1.25 → 0.1.26

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.
@@ -13,7 +13,7 @@
13
13
  <link rel="manifest" href="/assets/manifest.webmanifest" />
14
14
  <link rel="icon" href="/assets/icon.svg" type="image/svg+xml" />
15
15
  <link rel="apple-touch-icon" href="/assets/icon.svg" />
16
- <script type="module" crossorigin src="/assets/assets/index-Dau_ep-t.js"></script>
16
+ <script type="module" crossorigin src="/assets/assets/index-fVSxs9d5.js"></script>
17
17
  <link rel="modulepreload" crossorigin href="/assets/assets/rolldown-runtime-DF2fYuay.js">
18
18
  <link rel="modulepreload" crossorigin href="/assets/assets/vendor-BTlTWMUF.js">
19
19
  <link rel="modulepreload" crossorigin href="/assets/assets/createLucideIcon-BWC-guQt.js">
@@ -1,4 +1,4 @@
1
- const CACHE_VERSION = "1774027021751";
1
+ const CACHE_VERSION = "1774027644110";
2
2
  const CORE_CACHE = `fifony-core-${CACHE_VERSION}`;
3
3
  const ASSET_CACHE = `fifony-assets-${CACHE_VERSION}`;
4
4
  const APP_SHELL_ROUTES = ["/kanban", "/issues", "/agents", "/settings", "/onboarding"];
package/package.json CHANGED
@@ -1,21 +1,31 @@
1
1
  {
2
2
  "name": "fifony",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "private": false,
5
5
  "type": "module",
6
- "description": "Filesystem-backed local fifony orchestrator with a TypeScript CLI, MCP mode, and multi-agent Codex or Claude workflows.",
6
+ "license": "Apache-2.0",
7
+ "author": "Filipe Forattini <filipe@forattini.com.br>",
8
+ "description": "Filesystem-backed local orchestrator with a TypeScript CLI, MCP mode, and multi-agent Codex or Claude workflows.",
9
+ "keywords": [
10
+ "ai",
11
+ "agent",
12
+ "orchestrator",
13
+ "codex",
14
+ "claude",
15
+ "gemini",
16
+ "mcp",
17
+ "cli",
18
+ "automation"
19
+ ],
7
20
  "bin": {
8
21
  "fifony": "./bin/fifony.js",
9
22
  "fifony-wrap": "./bin/fifony-wrap.js"
10
23
  },
11
24
  "files": [
12
25
  "bin/",
13
- "dist/",
26
+ "dist/**/*.js",
14
27
  "app/dist/",
15
- "app/public/",
16
- "src/fixtures/",
17
28
  "README.md",
18
- "FIFONY.md",
19
29
  "LICENSE",
20
30
  "NOTICE"
21
31
  ],
@@ -34,25 +44,25 @@
34
44
  "node": ">=23"
35
45
  },
36
46
  "dependencies": {
37
- "@tanstack/react-query": "^5.91.2",
38
- "@tanstack/react-router": "^1.167.5",
39
47
  "cli-args-parser": "^1.0.6",
40
- "lucide-react": "^0.577.0",
41
48
  "node-cron": "^4.2.1",
42
49
  "pino": "^10.3.1",
43
50
  "pino-pretty": "^13.1.3",
44
51
  "raffel": "^1.0.18",
45
- "react": "^19.2.4",
46
- "react-dom": "^19.2.4",
47
52
  "recker": "^1.0.86",
48
53
  "s3db.js": "21.3.2",
49
54
  "yaml": "^2.8.2"
50
55
  },
51
56
  "devDependencies": {
52
57
  "@tailwindcss/vite": "^4.2.2",
58
+ "@tanstack/react-query": "^5.91.2",
59
+ "@tanstack/react-router": "^1.167.5",
53
60
  "@tanstack/router-plugin": "^1.166.14",
54
61
  "@vitejs/plugin-react": "^6.0.1",
55
62
  "daisyui": "^5.5.19",
63
+ "lucide-react": "^0.577.0",
64
+ "react": "^19.2.4",
65
+ "react-dom": "^19.2.4",
56
66
  "tailwindcss": "^4.2.2",
57
67
  "tsup": "^8.5.1",
58
68
  "tsx": "^4.21.0",
@@ -1 +0,0 @@
1
- import{n as e}from"./rolldown-runtime-DF2fYuay.js";import{I as t,h as n,m as r}from"./vendor-BTlTWMUF.js";import{t as i}from"./createLucideIcon-BWC-guQt.js";import{A as a,B as o,C as s,E as c,F as l,M as u,N as d,O as f,P as p,R as m,S as h,T as g,_,a as v,c as y,d as b,f as x,g as S,i as C,j as w,k as T,l as E,n as D,p as O,t as k,u as A,v as j,w as M,x as N}from"./index-Dau_ep-t.js";var P=i(`brain`,[[`path`,{d:`M12 18V5`,key:`adv99a`}],[`path`,{d:`M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4`,key:`1e3is1`}],[`path`,{d:`M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5`,key:`1gqd8o`}],[`path`,{d:`M17.997 5.125a4 4 0 0 1 2.526 5.77`,key:`iwvgf7`}],[`path`,{d:`M18 18a4 4 0 0 0 2-7.464`,key:`efp6ie`}],[`path`,{d:`M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517`,key:`1gq6am`}],[`path`,{d:`M6 18a4 4 0 0 1-2-7.464`,key:`k1g0md`}],[`path`,{d:`M6.003 5.125a4 4 0 0 0-2.526 5.77`,key:`q97ue3`}]]),ee=i(`chevron-left`,[[`path`,{d:`m15 18-6-6 6-6`,key:`1wnfg3`}]]),F=i(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),I=i(`flame`,[[`path`,{d:`M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4`,key:`1slcih`}]]),L=i(`folder-root`,[[`path`,{d:`M4 20h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.93a2 2 0 0 1-1.66-.9l-.82-1.2A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13c0 1.1.9 2 2 2Z`,key:`1fr9dc`}],[`circle`,{cx:`12`,cy:`13`,r:`2`,key:`1c1ljs`}],[`path`,{d:`M12 15v5`,key:`11xva1`}]]),R=i(`pencil-line`,[[`path`,{d:`M13 21h8`,key:`1jsn5i`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}],[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}]]),z=i(`rocket`,[[`path`,{d:`M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5`,key:`qeys4`}],[`path`,{d:`M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09`,key:`u4xsad`}],[`path`,{d:`M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z`,key:`676m9`}],[`path`,{d:`M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05`,key:`92ym6u`}]]),te=i(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),B=e(t(),1),V=n();function ne(){let e=(0,B.useRef)(null),t=(0,B.useRef)([]),n=(0,B.useRef)(null);return(0,B.useEffect)(()=>{let r=e.current;if(!r)return;let i=r.getContext(`2d`),a=[`♪`,`♫`,`♩`,`♬`],o=[`oklch(0.75 0.18 250)`,`oklch(0.80 0.16 200)`,`oklch(0.70 0.20 330)`,`oklch(0.85 0.14 85)`,`oklch(0.75 0.18 145)`,`oklch(0.80 0.12 280)`,`oklch(0.78 0.15 30)`],s=o.length,c=a.length,l=document.createElement(`canvas`);l.width=s*56,l.height=c*56;let u=l.getContext(`2d`);u.textAlign=`center`,u.textBaseline=`middle`,u.font=`48px serif`;let d=[];for(let e=0;e<c;e++){d[e]=[];for(let t=0;t<s;t++){let n=t*56+56/2,r=e*56+56/2;u.fillStyle=o[t],u.fillText(a[e],n,r),d[e][t]={x:t*56,y:e*56}}}let f=0,p=0,m=()=>{let e=window.devicePixelRatio||1;f=window.innerWidth,p=window.innerHeight,r.width=f*e,r.height=p*e,r.style.width=f+`px`,r.style.height=p+`px`,i.setTransform(e,0,0,e,0,0)};m();function h(){let e=f/2,t=p*.38,n=Math.random()*Math.PI*2,r=Math.random()*1.8+.4,i=Math.random()*20,a=Math.floor(Math.random()*c),o=Math.floor(Math.random()*s);return{x:e+Math.cos(n)*i,y:t+Math.sin(n)*i,vx:Math.cos(n)*r,vy:Math.sin(n)*r,gravity:.003+Math.random()*.005,scale:Math.random()*.4+.25,si:a,ci:o,rotation:Math.random()*Math.PI*2,rotationSpeed:(Math.random()-.5)*.04,life:0,maxLife:180+Math.random()*200,fadeIn:15}}let g=Math.min(Math.floor(f*p/6e3),120);t.current=[];for(let e=0;e<g;e++){let e=h(),n=Math.random()*e.maxLife*.8;e.x+=e.vx*n,e.y+=e.vy*n+.5*e.gravity*n*n,e.rotation+=e.rotationSpeed*n,e.life=n,t.current.push(e)}let _=Math.max(1,Math.floor(g/90)),v=0,y=()=>{if(i.clearRect(0,0,f,p),v++,v%2==0)for(let e=0;e<_;e++)t.current.push(h());let e=[];for(let n of t.current){if(n.life++,n.x+=n.vx,n.y+=n.vy,n.vy+=n.gravity,n.rotation+=n.rotationSpeed,n.vx*=.998,n.vy*=.998,n.life>n.maxLife||n.x<-60||n.x>f+60||n.y<-60||n.y>p+60)continue;e.push(n);let t=Math.min(1,n.life/n.fadeIn),r=n.maxLife*.6,a=t*(n.life>r?1-(n.life-r)/(n.maxLife-r):1)*.45;if(a<=.01)continue;let o=d[n.si][n.ci],s=56*n.scale,c=s/2;i.save(),i.translate(n.x,n.y),i.rotate(n.rotation),i.globalAlpha=a,i.drawImage(l,o.x,o.y,56,56,-c,-c,s,s),i.restore()}t.current=e,n.current=requestAnimationFrame(y)};return n.current=requestAnimationFrame(y),window.addEventListener(`resize`,m),()=>{cancelAnimationFrame(n.current),window.removeEventListener(`resize`,m)}},[]),(0,V.jsx)(`canvas`,{ref:e,className:`fixed inset-0 pointer-events-none`,style:{zIndex:0},"aria-hidden":`true`})}var H=[`Welcome`,`Setup`,`Pipeline`,`Agents & Skills`,`Preferences`,`Launch`];function re(){return H}function ie(){return H.length}var ae=[`Setup`,`Pipeline`,`Agents`,`Preferences`,`Launch`];function U(){return ae}var W=[{value:`low`,label:`Low`,icon:D,description:`Quick and light -- fast responses, less thorough`,color:`text-info`},{value:`medium`,label:`Medium`,icon:j,description:`Balanced -- good mix of speed and quality`,color:`text-success`},{value:`high`,label:`High`,icon:P,description:`Thorough -- deeper analysis, takes more time`,color:`text-warning`},{value:`extra-high`,label:`Extra High`,icon:I,description:`Maximum depth -- most thorough, slowest`,color:`text-error`}],G={codex:W,claude:W.filter(e=>e.value!==`extra-high`),gemini:W.filter(e=>e.value!==`extra-high`)};function K(e,t){return G[t?.[e]||`codex`]||W}var q=[{value:`auto`,label:`Auto`},{value:`light`,label:`Light`},{value:`dark`,label:`Dark`},{value:`black`,label:`Black`},{value:`cupcake`,label:`Cupcake`},{value:`night`,label:`Night`},{value:`sunset`,label:`Sunset`}],J=[{role:`planner`,label:`Planner`,description:`Scopes the issue, breaks it into steps, and decides the approach`,icon:P,color:`text-info`},{role:`executor`,label:`Executor`,description:`Implements the plan — writes code, edits files, runs commands`,icon:D,color:`text-primary`},{role:`reviewer`,label:`Reviewer`,description:`Validates the result — checks correctness, scope, and quality`,icon:E,color:`text-secondary`}];async function Y(e,t,n=`ui`){return o.post(`/settings/${encodeURIComponent(e)}`,{value:t,scope:n,source:`user`})}function X(e,t=`medium`){return W.some(t=>t.value===e)?e:t}function oe(e){return!e||typeof e!=`object`||Array.isArray(e)?{planner:`medium`,executor:`medium`,reviewer:`medium`}:{planner:X(e.planner??e.default,`medium`),executor:X(e.executor??e.default,`medium`),reviewer:X(e.reviewer??e.default,`medium`)}}function se(e,t,n={}){return{plan:{provider:e.planner||e.executor||``,model:n.plan||``,effort:t.planner||`medium`},execute:{provider:e.executor||``,model:n.execute||``,effort:t.executor||`medium`},review:{provider:e.reviewer||e.executor||``,model:n.review||``,effort:t.reviewer||`medium`}}}function ce({current:e}){let t=U(),n=e-1;return(0,V.jsx)(`ul`,{className:`steps steps-horizontal w-full max-w-2xl text-xs`,children:t.map((e,t)=>{let r=t<n,i=t===n;return(0,V.jsx)(`li`,{"data-content":r?`✓`:t+1,className:`step ${r||i?`step-primary`:``}`,style:{transition:`color 0.3s ease`},children:e},e)})})}function le({direction:e,stepKey:t,center:n,children:r}){return(0,V.jsx)(`div`,{className:`${e===`forward`?`animate-slide-in-right`:`animate-slide-in-left`} w-full max-w-2xl mx-auto ${n?`my-auto`:``}`,children:r},t)}function ue({step:e,stepCount:t,stepName:n,canProceed:r,launching:i,onBack:a,onNext:o,onLaunch:s}){return e===0?null:(0,V.jsxs)(`div`,{className:`relative z-10 p-4 pb-6 flex items-center max-w-2xl mx-auto w-full justify-between`,children:[(0,V.jsxs)(`button`,{className:`btn btn-ghost gap-1`,onClick:a,disabled:i,children:[(0,V.jsx)(ee,{className:`size-4`}),` Back`]}),e<t-1?(0,V.jsxs)(`button`,{className:`btn btn-primary gap-1`,onClick:o,disabled:!r,children:[`Next `,(0,V.jsx)(F,{className:`size-4`})]}):(0,V.jsx)(`button`,{className:`btn btn-primary btn-lg gap-2 animate-pulse-soft`,onClick:s,disabled:i,children:i?(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(O,{className:`size-5 animate-spin`}),` Launching...`]}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(z,{className:`size-5`}),` Launch fifony`]})})]})}function de({workspacePath:e,onGetStarted:t}){return(0,V.jsxs)(`div`,{className:`flex flex-col items-center text-center gap-6 stagger-children py-4`,children:[(0,V.jsx)(`img`,{src:`/dinofffaur.png`,alt:`fifony mascot`,className:`h-72 sm:h-96 object-contain animate-bounce-in select-none pointer-events-none`,style:{filter:`drop-shadow(0 12px 40px rgba(128, 0, 255, 0.3))`}}),(0,V.jsxs)(`h1`,{className:`text-4xl sm:text-5xl font-bold tracking-tight leading-none`,style:{fontFamily:`'Space Grotesk', system-ui, sans-serif`},children:[`Welcome to `,(0,V.jsx)(`span`,{className:`text-primary`,children:`fifony`})]}),(0,V.jsx)(`p`,{className:`text-base-content/60 text-lg max-w-md`,children:`Let's set up your AI orchestration project in just a few steps.`}),e&&(0,V.jsxs)(`div`,{className:`badge badge-lg badge-soft badge-primary gap-2`,children:[(0,V.jsx)(y,{className:`size-3.5`}),`Project target: `,e]}),(0,V.jsxs)(`button`,{className:`btn btn-primary btn-lg gap-2 mt-2`,onClick:t,children:[`Get Started `,(0,V.jsx)(F,{className:`size-5`})]})]})}var fe=new Set([`main`,`master`]);function Z(){let[e,t]=(0,B.useState)(null),[n,r]=(0,B.useState)(!1),[i,a]=(0,B.useState)(!1);return(0,B.useEffect)(()=>{o.get(`/gitignore/status`).then(t).catch(()=>t({exists:!1,hasFifony:!1}))},[]),e===null||e.hasFifony?null:i?(0,V.jsxs)(`div`,{className:`alert alert-success py-2.5 text-sm animate-fade-in`,children:[(0,V.jsx)(te,{className:`size-4 shrink-0`}),(0,V.jsxs)(`span`,{children:[(0,V.jsx)(`code`,{children:`.fifony/`}),` adicionado ao `,(0,V.jsx)(`code`,{children:`.gitignore`})]})]}):(0,V.jsxs)(`div`,{className:`alert alert-warning py-2.5 text-sm`,children:[(0,V.jsx)(te,{className:`size-4 shrink-0`}),(0,V.jsxs)(`div`,{className:`flex-1`,children:[(0,V.jsxs)(`span`,{children:[(0,V.jsx)(`code`,{children:`.fifony/`}),` não está no `,(0,V.jsx)(`code`,{children:`.gitignore`})]}),(0,V.jsx)(`span`,{className:`text-base-content/50 block text-xs mt-0.5`,children:`O fifony guarda estado local lá — não deve ser commitado.`})]}),(0,V.jsx)(`button`,{className:`btn btn-xs btn-warning`,onClick:async()=>{r(!0);try{await o.post(`/gitignore/add`),a(!0)}catch{}finally{r(!1)}},disabled:n,children:n?(0,V.jsx)(O,{className:`size-3 animate-spin`}):`Adicionar`})]})}function Q({currentBranch:e,onBranchCreated:t}){let[n,r]=(0,B.useState)(null),[i,a]=(0,B.useState)(!1),[c,l]=(0,B.useState)(null),[u,d]=(0,B.useState)(e);(0,B.useEffect)(()=>{o.get(`/git/status`).then(e=>{r(e),e.branch&&d(e.branch)}).catch(()=>r({isGit:!0,branch:e,hasCommits:!0}))},[]);let[f,p]=(0,B.useState)(`develop`),[m,h]=(0,B.useState)(!1),[g,y]=(0,B.useState)(null),[b,C]=(0,B.useState)(!1),w=n===null||n.isGit,T=fe.has(u),E=/^[a-zA-Z0-9/_.-]+$/.test(f.trim())&&f.trim().length>0;async function D(){a(!0),l(null);try{let e=await o.post(`/git/init`,{});if(!e.ok)throw Error(e.error||`Failed to initialize git.`);r({isGit:!0,branch:e.branch,hasCommits:!0}),d(e.branch)}catch(e){l(e instanceof Error?e.message:String(e))}finally{a(!1)}}async function k(){if(!(!E||m)){h(!0),y(null);try{let e=await o.post(`/git/branch`,{branchName:f.trim()});if(!e.ok)throw Error(e.error||`Failed to create branch.`);C(!0),t?.(f.trim())}catch(e){y(e instanceof Error?e.message:String(e))}finally{h(!1)}}}return(0,V.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(_,{className:`size-4 text-primary`}),(0,V.jsx)(`div`,{className:`text-sm font-semibold`,children:`Working branch`})]}),(0,V.jsx)(`p`,{className:`text-xs text-base-content/50 -mt-2`,children:`Agents create worktrees based on the current branch. We recommend not working directly on main.`}),n!==null&&!n.isGit&&(0,V.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,V.jsxs)(`div`,{className:`alert alert-warning py-3`,children:[(0,V.jsx)(S,{className:`size-4 shrink-0`}),(0,V.jsxs)(`div`,{className:`text-sm`,children:[(0,V.jsx)(`p`,{className:`font-semibold`,children:`Not a git repository`}),(0,V.jsx)(`p`,{className:`opacity-80 mt-0.5`,children:`fifony requires git to create agent worktrees. Initialize one here.`})]})]}),c&&(0,V.jsxs)(`p`,{className:`text-xs text-error flex items-center gap-1`,children:[(0,V.jsx)(v,{className:`size-3`}),` `,c]}),(0,V.jsxs)(`button`,{className:`btn btn-primary gap-2 self-start`,onClick:D,disabled:i,children:[i?(0,V.jsx)(O,{className:`size-4 animate-spin`}):(0,V.jsx)(S,{className:`size-4`}),`Initialize git repository`]})]}),w&&(0,V.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,V.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 rounded-box border border-base-300 bg-base-100`,children:[(0,V.jsx)(_,{className:`size-4 opacity-50 shrink-0`}),(0,V.jsx)(`span`,{className:`text-sm opacity-50`,children:`Current branch:`}),(0,V.jsx)(`span`,{className:`font-mono text-sm font-semibold`,children:u||(n===null?`…`:`—`)}),T&&(0,V.jsx)(`span`,{className:`badge badge-warning badge-sm ml-auto shrink-0`,children:`protected`})]}),T&&(0,V.jsxs)(`div`,{className:`alert alert-warning py-3`,children:[(0,V.jsx)(v,{className:`size-4 shrink-0`}),(0,V.jsxs)(`div`,{className:`text-sm`,children:[(0,V.jsxs)(`p`,{className:`font-semibold`,children:[`Working directly on `,(0,V.jsx)(`span`,{className:`font-mono`,children:u})]}),(0,V.jsx)(`p`,{className:`opacity-80 mt-0.5`,children:`In teams with protected branches, local merges are rejected. Create a working branch or use Push PR mode.`})]})]}),b?(0,V.jsxs)(`div`,{className:`alert alert-success py-3 text-sm`,children:[(0,V.jsx)(s,{className:`size-4 shrink-0`}),(0,V.jsxs)(`div`,{children:[(0,V.jsx)(`p`,{className:`font-semibold`,children:`Branch created successfully`}),(0,V.jsxs)(`p`,{className:`opacity-75 font-mono mt-0.5`,children:[`Now on `,(0,V.jsx)(`span`,{className:`text-success-content`,children:f.trim()}),` — agents will use this as the base branch`]})]})]}):(0,V.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,V.jsx)(`label`,{className:`text-sm font-medium`,children:`Create a new branch now`}),(0,V.jsxs)(`div`,{className:`flex gap-2`,children:[(0,V.jsxs)(`label`,{className:`input input-bordered flex items-center gap-2 flex-1`,children:[(0,V.jsx)(_,{className:`size-3.5 opacity-40`}),(0,V.jsx)(`input`,{type:`text`,className:`grow font-mono text-sm`,value:f,onChange:e=>{p(e.target.value),y(null)},onKeyDown:e=>e.key===`Enter`&&k(),placeholder:`develop`,disabled:m})]}),(0,V.jsx)(`button`,{className:`btn btn-primary`,onClick:k,disabled:!E||m,children:m?(0,V.jsx)(x,{className:`size-4 animate-spin`}):`Create`})]}),g&&(0,V.jsxs)(`p`,{className:`text-xs text-error flex items-center gap-1`,children:[(0,V.jsx)(v,{className:`size-3`}),` `,g]}),(0,V.jsxs)(`p`,{className:`text-xs opacity-40`,children:[`Equivalent to: `,(0,V.jsxs)(`span`,{className:`font-mono`,children:[`git checkout -b `,f.trim()||`develop`]})]})]}),(0,V.jsx)(Z,{})]})]})}function pe({projectName:e,setProjectName:t,detectedProjectName:n,projectSource:r,workspacePath:i,currentBranch:o,onBranchCreated:s}){let c=a(e),l=T(c||n),u=c?r===`saved`||r===`detected`?r:`manual`:n?`detected`:`missing`;return(0,V.jsxs)(`div`,{className:`flex flex-col gap-6 py-4`,children:[(0,V.jsxs)(`div`,{className:`text-center space-y-3`,children:[(0,V.jsx)(`div`,{className:`inline-flex size-14 items-center justify-center rounded-full bg-primary/10 text-primary mx-auto`,children:(0,V.jsx)(L,{className:`size-7`})}),(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsx)(`h2`,{className:`text-2xl font-bold tracking-tight`,children:`Set up your workspace`}),(0,V.jsx)(`p`,{className:`text-base-content/60 max-w-xl mx-auto text-sm`,children:`Name your project and configure the working branch`})]})]}),(0,V.jsxs)(`div`,{className:`bg-base-200 rounded-2xl p-5 flex flex-col gap-4`,children:[(0,V.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[(0,V.jsxs)(`div`,{children:[(0,V.jsx)(`div`,{className:`text-sm font-semibold`,children:`Project name`}),(0,V.jsx)(`div`,{className:`text-xs text-base-content/50`,children:`This becomes the default queue title for future runs.`})]}),u===`saved`&&(0,V.jsxs)(`span`,{className:`badge badge-primary badge-soft gap-1.5`,children:[(0,V.jsx)(y,{className:`size-3`}),`Saved configuration`]}),u===`detected`&&(0,V.jsxs)(`span`,{className:`badge badge-secondary badge-soft gap-1.5`,children:[(0,V.jsx)(y,{className:`size-3`}),`Detected automatically`]}),u===`manual`&&(0,V.jsxs)(`span`,{className:`badge badge-accent badge-soft gap-1.5`,children:[(0,V.jsx)(R,{className:`size-3`}),`Edited manually`]}),u===`missing`&&(0,V.jsxs)(`span`,{className:`badge badge-warning badge-soft gap-1.5`,children:[(0,V.jsx)(v,{className:`size-3`}),`Manual entry required`]})]}),(0,V.jsxs)(`label`,{className:`form-control w-full gap-2`,children:[(0,V.jsx)(`span`,{className:`label-text text-sm font-medium`,children:`Project`}),(0,V.jsx)(`input`,{type:`text`,className:`input input-bordered w-full text-base`,placeholder:n||`Enter your project name`,value:e,onChange:e=>t(e.target.value),onBlur:n=>{let r=a(n.target.value);r!==e&&t(r)}})]}),i&&(0,V.jsxs)(`div`,{className:`text-xs text-base-content/50 break-all`,children:[`Workspace: `,i]}),!n&&!c&&(0,V.jsxs)(`div`,{className:`alert alert-warning text-sm`,children:[(0,V.jsx)(v,{className:`size-4 shrink-0`}),(0,V.jsx)(`span`,{children:`We could not detect a project name from the current directory. Enter one to continue.`})]}),(0,V.jsxs)(`div`,{className:`rounded-xl border border-base-300/70 bg-base-100 px-4 py-3`,children:[(0,V.jsx)(`div`,{className:`text-xs uppercase tracking-[0.2em] text-base-content/40`,children:`Queue title preview`}),(0,V.jsx)(`div`,{className:`mt-1.5 text-base font-semibold tracking-tight break-words`,children:l})]})]}),(0,V.jsx)(Q,{currentBranch:o,onBranchCreated:s})]})}var me={planner:`plan`,executor:`execute`,reviewer:`review`};function he({options:e,value:t,onChange:n}){return(0,V.jsx)(`div`,{className:`flex gap-1 flex-wrap`,children:e.map(e=>{let r=e.value===t,i=e.icon;return(0,V.jsxs)(`button`,{type:`button`,onClick:()=>n(e.value),className:`flex items-center gap-1 px-2.5 py-1 rounded-full text-[11px] font-medium border transition-all ${r?`${e.color} border-current bg-base-300`:`text-base-content/35 border-base-content/10 hover:border-base-content/30 hover:text-base-content/60`}`,children:[(0,V.jsx)(i,{className:`size-2.5`}),e.label]},e.value)})})}function ge({providers:e,providersLoading:t,pipeline:n,setPipeline:r,efforts:i,setEfforts:a,models:o,setModels:s,modelsByProvider:l}){let u=Array.isArray(e)?e:[],d=u.filter(e=>e.available!==!1);return(0,B.useEffect)(()=>{for(let e of[`planner`,`executor`,`reviewer`]){let t=K(e,n),r=i[e];r&&!t.some(e=>e.value===r)&&a(t=>({...t,[e]:`high`}))}},[n,i,a]),(0,V.jsxs)(`div`,{className:`flex flex-col gap-5 w-full max-w-lg`,children:[(0,V.jsxs)(`div`,{className:`text-center`,children:[(0,V.jsx)(z,{className:`size-9 text-primary mx-auto mb-2`}),(0,V.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Agent Pipeline`}),(0,V.jsx)(`p`,{className:`text-sm text-base-content/50 mt-1`,children:`Configure which CLI and reasoning depth runs each stage`})]}),t?(0,V.jsxs)(`div`,{className:`flex flex-col items-center gap-3 py-10`,children:[(0,V.jsx)(O,{className:`size-7 text-primary animate-spin`}),(0,V.jsx)(`p`,{className:`text-sm text-base-content/50`,children:`Detecting available CLIs…`})]}):d.length===0?(0,V.jsx)(`div`,{className:`alert alert-warning text-sm`,children:`No providers detected. Install claude, codex, or gemini CLI first.`}):(0,V.jsxs)(V.Fragment,{children:[(0,V.jsx)(`div`,{className:`flex flex-wrap gap-2 justify-center`,children:u.map(e=>{let t=e.id||e.name||e,n=e.available!==!1;return(0,V.jsxs)(`span`,{className:`badge gap-1.5 badge-sm ${n?`badge-success`:`badge-ghost opacity-40`}`,children:[n?(0,V.jsx)(h,{className:`size-3`}):(0,V.jsx)(N,{className:`size-3`}),(0,V.jsx)(`span`,{className:`font-mono`,children:t}),e.path&&(0,V.jsx)(`span`,{className:`opacity-50 text-[9px] hidden sm:inline`,children:e.path})]},t)})}),(0,V.jsx)(`div`,{className:`flex flex-col`,children:J.map((e,t)=>{let u=e.icon,f=n[e.role]||d[0]?.id||d[0]?.name||``,p=me[e.role],m=o?.[p]||``,h=l?.[f]||[],g=K(e.role,n),_=i?.[e.role]||`high`;return(0,V.jsxs)(`div`,{children:[t>0&&(0,V.jsx)(`div`,{className:`flex justify-center py-1.5 text-base-content/20`,children:(0,V.jsx)(c,{className:`size-4`})}),(0,V.jsx)(`div`,{className:`bg-base-200 rounded-xl p-4`,children:(0,V.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,V.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,V.jsx)(`div`,{className:`size-8 rounded-lg flex items-center justify-center bg-base-300 shrink-0 ${e.color}`,children:(0,V.jsx)(u,{className:`size-4`})}),(0,V.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,V.jsx)(`span`,{className:`font-semibold text-sm`,children:e.label}),(0,V.jsx)(`p`,{className:`text-[11px] text-base-content/40 leading-tight mt-0.5 truncate`,children:e.description})]}),(0,V.jsx)(`select`,{className:`select select-sm select-bordered w-28 shrink-0`,value:f,onChange:t=>{let n=t.target.value;r(t=>({...t,[e.role]:n}));let i=l?.[n]?.[0]?.id||``;s(e=>({...e,[p]:i}))},children:d.map(e=>{let t=e.id||e.name||e;return(0,V.jsx)(`option`,{value:t,children:t},t)})})]}),(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`text-[10px] text-base-content/40 shrink-0 w-10`,children:`Effort`}),(0,V.jsx)(he,{options:g,value:_,onChange:t=>a(n=>({...n,[e.role]:t}))})]}),h.length>0&&(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`text-[10px] text-base-content/40 shrink-0 w-10`,children:`Model`}),(0,V.jsx)(`select`,{className:`select select-xs select-bordered flex-1`,value:m,onChange:e=>s(t=>({...t,[p]:e.target.value})),children:h.map(e=>(0,V.jsx)(`option`,{value:e.id,children:e.label||e.id},e.id))})]})]})})]},e.role)})}),(0,V.jsx)(`p`,{className:`text-[11px] text-base-content/35 text-center`,children:`Pipeline runs top to bottom: plan → execute → review`})]})]})}function _e({selectedAgents:e,setSelectedAgents:t,existingAgents:n}){let[r,i]=(0,B.useState)([]),[a,s]=(0,B.useState)(!1),c=(0,B.useRef)(!1),[l,u]=(0,B.useState)([]),[d,f]=(0,B.useState)(!1),[p,m]=(0,B.useState)(``),[h,_]=(0,B.useState)(()=>new Set),[v,y]=(0,B.useState)({}),b=(0,B.useRef)(!1),[x,S]=(0,B.useState)(``),C=(0,B.useCallback)(()=>o.get(`/catalog/agents`).catch(()=>({agents:[]})).then(e=>{let t=e?.agents||[];return i(t),t}),[]);(0,B.useEffect)(()=>{c.current||(c.current=!0,s(!0),C().then(r=>{let i=new Set((n||[]).map(e=>e.name)),a=r.filter(e=>!i.has(e.name)).map(e=>e.name);a.length>0&&e.length===0&&t(a)}).finally(()=>s(!1)))},[]);let w=(0,B.useCallback)(()=>(m(``),f(!0),o.get(`/reference-repositories`).then(e=>{u(e?.repositories||[])}).catch(e=>{let t=e?.message||`Failed to load reference repositories.`;t.toLowerCase().includes(`route not found`)?m(`Backend route not loaded. Start Fifony with --dev (or run pnpm build:server) and retry.`):m(t)}).finally(()=>f(!1))),[]);(0,B.useEffect)(()=>{b.current||(b.current=!0,w())},[w]);let T=(0,B.useMemo)(()=>new Set((n||[]).map(e=>e.name)),[n]),D=(0,B.useMemo)(()=>{let e=x.trim().toLowerCase();return e?r.filter(t=>[t?.name,t?.displayName,t?.description].filter(Boolean).join(` `).toLowerCase().includes(e)):r},[x,r]),k=(0,B.useCallback)(e=>{t(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e])},[t]),j=(0,B.useCallback)(()=>{t(r.filter(e=>!T.has(e.name)).map(e=>e.name))},[r,T,t]),N=(0,B.useCallback)(()=>t([]),[t]),P=(0,B.useCallback)(async e=>{_(t=>new Set([...t,e])),y(t=>({...t,[e]:``}));try{let t=((await o.post(`/reference-repositories/sync`,{repository:e}))?.results||[]).find(t=>t.id===e);if(t?.action===`failed`){y(n=>({...n,[e]:t.message||`Sync failed.`}));return}await o.post(`/reference-repositories/import`,{repository:e,kind:`agents`,global:!1}),await Promise.all([w(),C()]),y(t=>({...t,[e]:`Synced & imported.`}))}catch(t){y(n=>({...n,[e]:t?.message||`Failed.`}))}finally{_(t=>{let n=new Set(t);return n.delete(e),n})}},[w,C]);return a?(0,V.jsxs)(`div`,{className:`flex flex-col items-center gap-3 py-12`,children:[(0,V.jsx)(O,{className:`size-8 text-primary animate-spin`}),(0,V.jsx)(`p`,{className:`text-sm text-base-content/50`,children:`Loading catalog...`})]}):(0,V.jsxs)(`div`,{className:`flex flex-col gap-6 stagger-children`,children:[(0,V.jsxs)(`div`,{className:`text-center`,children:[(0,V.jsx)(g,{className:`size-10 text-primary mx-auto mb-3`}),(0,V.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Agents`}),(0,V.jsx)(`p`,{className:`text-base-content/60 mt-1`,children:`Choose which agents to install`})]}),(0,V.jsx)(`div`,{className:`card bg-base-200`,children:(0,V.jsxs)(`div`,{className:`card-body gap-3 p-4`,children:[(0,V.jsx)(`h3`,{className:`font-semibold text-sm`,children:`Sources`}),p&&(0,V.jsx)(`div`,{className:`alert alert-warning text-xs`,children:p}),d?(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-xs text-base-content/60`,children:[(0,V.jsx)(O,{className:`size-3 animate-spin`}),` Loading...`]}):(0,V.jsx)(`div`,{className:`grid grid-cols-2 xl:grid-cols-4 gap-2`,children:l.map(e=>{let t=h.has(e.id),n=e?.artifactCounts??null,r=e?.present&&e?.synced;return(0,V.jsxs)(`div`,{className:`rounded-lg border border-base-300/70 bg-base-100 p-2 flex flex-col gap-1.5`,children:[(0,V.jsx)(`div`,{className:`font-medium text-xs truncate`,children:e.name}),r&&n?(0,V.jsxs)(`div`,{className:`text-[11px] text-base-content/60`,children:[n.agents,` agents`]}):(0,V.jsx)(`span`,{className:`badge badge-xs badge-warning`,children:`Not synced`}),v[e.id]&&(0,V.jsx)(`p`,{className:`text-[11px] text-base-content/60 truncate`,children:v[e.id]}),(0,V.jsxs)(`button`,{className:`btn btn-xs btn-outline gap-1 mt-auto`,onClick:()=>P(e.id),disabled:t,children:[t?(0,V.jsx)(O,{className:`size-3 animate-spin`}):(0,V.jsx)(A,{className:`size-3`}),t?`Syncing…`:r?`Re-sync`:`Sync`]})]},e.id)})})]})}),(0,V.jsxs)(`div`,{className:`space-y-2`,children:[(0,V.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,V.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,V.jsx)(g,{className:`size-4 opacity-50`}),`Agents (`,r.length,`)`]}),(0,V.jsxs)(`div`,{className:`flex gap-1`,children:[(0,V.jsx)(`button`,{className:`btn btn-xs btn-ghost`,onClick:j,children:`Select All`}),(0,V.jsx)(`button`,{className:`btn btn-xs btn-ghost`,onClick:N,children:`None`})]})]}),(0,V.jsxs)(`label`,{className:`input input-bordered input-sm flex items-center gap-2`,children:[(0,V.jsx)(E,{className:`size-4 opacity-60`}),(0,V.jsx)(`input`,{type:`text`,className:`grow`,placeholder:`Search agents...`,value:x,onChange:e=>S(e.target.value)})]}),D.length===0&&r.length>0&&(0,V.jsx)(`div`,{className:`text-sm text-base-content/60`,children:`No agents match your search.`}),(0,V.jsx)(`div`,{className:`space-y-1 pt-1`,children:D.map(t=>{let n=T.has(t.name),r=n||e.includes(t.name);return(0,V.jsx)(`button`,{className:`w-full rounded-md border border-transparent px-2 py-2 text-left transition-all ${n?`opacity-70 bg-base-100/40`:`hover:bg-base-100`} ${r&&!n?`ring-1 ring-primary ring-offset-1 ring-offset-base-200`:``}`,onClick:()=>!n&&k(t.name),disabled:n,children:(0,V.jsxs)(`div`,{className:`flex items-start gap-2`,children:[(0,V.jsx)(`span`,{className:`mt-0.5 text-base`,children:t.emoji||`🤖`}),(0,V.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,V.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,V.jsx)(`span`,{className:`font-medium text-sm truncate`,children:t.displayName||t.name}),t.source&&(0,V.jsx)(`span`,{className:`badge badge-xs badge-ghost shrink-0`,children:t.source}),n?(0,V.jsxs)(`span`,{className:`badge badge-xs badge-success gap-1 shrink-0`,children:[(0,V.jsx)(M,{className:`size-3`}),` Installed`]}):(0,V.jsx)(`input`,{type:`checkbox`,className:`checkbox checkbox-primary checkbox-sm self-start mt-0.5 shrink-0`,checked:r,readOnly:!0,tabIndex:-1})]}),t.description&&(0,V.jsx)(`p`,{className:`text-xs text-base-content/60 mt-1 truncate`,children:t.description})]})]})},t.name)})})]}),r.length===0&&(0,V.jsx)(`div`,{className:`alert alert-info text-sm`,children:`No agents found in the catalog. Sync a source above or add them later from the settings page.`})]})}var ve={auto:{bg:null,label:`Auto`},light:{bg:`#ffffff`,accent:`#7c3aed`},dark:{bg:`#1d232a`,accent:`#661ae6`},black:{bg:`#000000`,accent:`#ffffff`},cupcake:{bg:`#faf7f5`,accent:`#ef9fbc`},night:{bg:`#0f172a`,accent:`#38bdf8`},sunset:{bg:`#1a1019`,accent:`#ff865b`}};function ye({theme:e,selected:t,onClick:n}){let r=ve[e.value];return(0,V.jsxs)(`button`,{onClick:n,title:e.label,className:`flex flex-col items-center gap-1.5 group focus:outline-none`,children:[(0,V.jsx)(`div`,{className:`w-10 h-10 rounded-xl border-2 transition-all overflow-hidden flex-shrink-0 ${t?`border-primary ring-2 ring-primary ring-offset-2 ring-offset-base-200 scale-110`:`border-base-300 group-hover:border-base-content/30 group-hover:scale-105`}`,style:r.bg?{background:r.bg}:void 0,children:r.bg?(0,V.jsxs)(`div`,{className:`w-full h-full flex flex-col`,children:[(0,V.jsx)(`div`,{className:`flex-1`,style:{background:r.bg}}),(0,V.jsx)(`div`,{className:`h-3 w-full`,style:{background:r.accent}})]}):(0,V.jsxs)(`div`,{className:`w-full h-full flex`,children:[(0,V.jsx)(`div`,{className:`flex-1 bg-white`}),(0,V.jsx)(`div`,{className:`flex-1 bg-neutral`})]})}),(0,V.jsx)(`span`,{className:`text-xs font-medium transition-colors ${t?`text-primary`:`text-base-content/50 group-hover:text-base-content/80`}`,children:e.label})]})}function be({concurrency:e,setConcurrency:t,selectedTheme:n,setSelectedTheme:r}){let i=Number.isFinite(e)?Math.max(1,Math.min(10,e)):1;return(0,V.jsxs)(`div`,{className:`flex flex-col gap-6 stagger-children`,children:[(0,V.jsxs)(`div`,{className:`text-center`,children:[(0,V.jsx)(C,{className:`size-10 text-primary mx-auto mb-3`}),(0,V.jsx)(`h2`,{className:`text-2xl font-bold`,children:`Workers & Theme`}),(0,V.jsx)(`p`,{className:`text-base-content/60 mt-1 text-sm`,children:`Configure parallel workers and visual theme`})]}),(0,V.jsx)(`div`,{className:`card bg-base-200`,children:(0,V.jsxs)(`div`,{className:`card-body p-5 gap-3`,children:[(0,V.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,V.jsx)(C,{className:`size-4 opacity-50`}),`Worker Concurrency`]}),(0,V.jsxs)(`p`,{className:`text-xs text-base-content/60`,children:[`How many agents can work in parallel (`,i,` worker`,i===1?``:`s`,`)`]}),(0,V.jsxs)(`div`,{className:`w-full max-w-xs`,children:[(0,V.jsx)(`input`,{type:`range`,min:1,max:10,step:1,value:i,onChange:e=>t(Math.round(Number(e.target.value))),"aria-label":`Number of parallel workers`,className:`range range-primary range-sm w-full`}),(0,V.jsx)(`div`,{className:`flex justify-between px-2.5 mt-2 text-xs`,children:Array.from({length:10},(e,t)=>(0,V.jsx)(`span`,{children:`|`},t))}),(0,V.jsx)(`div`,{className:`flex justify-between px-2.5 mt-2 text-xs`,children:Array.from({length:10},(e,t)=>(0,V.jsx)(`span`,{children:t+1},t))})]}),(0,V.jsxs)(`p`,{className:`text-xs text-base-content/50 bg-base-100 rounded-lg px-3 py-2 mt-1`,children:[(0,V.jsx)(`span`,{className:`font-medium text-base-content/70`,children:`Tip:`}),` 2–4 workers is recommended for most projects. More workers consume more API quota and may hit rate limits.`]})]})}),(0,V.jsx)(`div`,{className:`card bg-base-200`,children:(0,V.jsxs)(`div`,{className:`card-body p-5 gap-4`,children:[(0,V.jsxs)(`h3`,{className:`font-semibold text-sm flex items-center gap-2`,children:[(0,V.jsx)(b,{className:`size-4 opacity-50`}),`Theme`]}),(0,V.jsx)(`div`,{className:`flex flex-wrap gap-5 justify-center py-1`,children:q.map(e=>(0,V.jsx)(ye,{theme:e,selected:n===e.value,onClick:()=>r(e.value)},e.value))})]})})]})}function xe({config:e,launching:t}){return(0,V.jsxs)(`div`,{className:`flex flex-col items-center text-center gap-6 stagger-children py-4`,children:[(0,V.jsx)(`div`,{className:`animate-bounce-in`,children:(0,V.jsx)(z,{className:`size-16 sm:size-20 text-primary mx-auto`})}),(0,V.jsx)(`h2`,{className:`text-2xl sm:text-3xl font-bold`,children:`You're All Set!`}),(0,V.jsx)(`p`,{className:`text-base-content/60 max-w-md`,children:`Here's a summary of your configuration. Hit launch when you're ready.`}),(0,V.jsx)(`div`,{className:`card bg-base-200 w-full max-w-sm`,children:(0,V.jsxs)(`div`,{className:`card-body p-4 gap-2 text-sm text-left`,children:[(0,V.jsxs)(`div`,{className:`flex justify-between gap-4`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Queue title`}),(0,V.jsx)(`span`,{className:`font-semibold text-right break-words`,children:e.queueTitle||`fifony`})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Pipeline`}),(0,V.jsxs)(`span`,{className:`font-semibold capitalize text-xs font-mono`,children:[e.pipeline?.planner||`?`,` → `,e.pipeline?.executor||`?`,` → `,e.pipeline?.reviewer||`?`]})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Domains`}),(0,V.jsx)(`span`,{className:`font-semibold`,children:e.domains?.length>0?e.domains.length+` selected`:`none`})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Agents`}),(0,V.jsxs)(`span`,{className:`font-semibold`,children:[e.agents?.length||0,` to install`]})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Skills`}),(0,V.jsxs)(`span`,{className:`font-semibold`,children:[e.skills?.length||0,` to install`]})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Plan`}),(0,V.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.planner})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Execute`}),(0,V.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.executor})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Review`}),(0,V.jsx)(`span`,{className:`font-semibold capitalize`,children:e.efforts.reviewer})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Workers`}),(0,V.jsx)(`span`,{className:`font-semibold`,children:e.concurrency})]}),(0,V.jsx)(`div`,{className:`divider my-0`}),(0,V.jsxs)(`div`,{className:`flex justify-between`,children:[(0,V.jsx)(`span`,{className:`text-base-content/60`,children:`Theme`}),(0,V.jsx)(`span`,{className:`font-semibold capitalize`,children:e.theme})]})]})}),t&&(0,V.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-base-content/50`,children:[(0,V.jsx)(O,{className:`size-4 animate-spin`}),`Saving configuration & installing agents...`]})]})}function Se({onComplete:e}){let t=r(),n=m(),i=p(n.data),[s,c]=(0,B.useState)(0),[h,g]=(0,B.useState)(`forward`),[_,v]=(0,B.useState)(!1),[y,b]=(0,B.useState)(null),x=(0,B.useRef)(!1),S=(0,B.useRef)(!1),[C,E]=(0,B.useState)({planner:``,executor:``,reviewer:``}),[D,O]=(0,B.useState)(()=>oe(null)),[A,j]=(0,B.useState)(3),[M,N]=(0,B.useState)(`auto`),[P,ee]=(0,B.useState)(``),[F,I]=(0,B.useState)(`missing`),[L,R]=(0,B.useState)(null),[z,te]=(0,B.useState)([]),[H,ae]=(0,B.useState)([]),U=ie(),W=re()[s]||``,[G,K]=(0,B.useState)(null),[q,J]=(0,B.useState)(!1),[X,fe]=(0,B.useState)({}),[Z,Q]=(0,B.useState)({plan:``,execute:``,review:``}),[me,he]=(0,B.useState)(``),[ve,ye]=(0,B.useState)(``);(0,B.useEffect)(()=>{o.get(`/state`).then(e=>{R(e||{}),he(e?.sourceRepoUrl||e?.config?.sourceRepo||``),ye(e?.config?.defaultBranch||``)}).catch(()=>{R({})})},[]),(0,B.useEffect)(()=>{if(x.current||n.isLoading)return;x.current=!0;let e=d(i,`runtime.pipeline`,null),t=d(i,`runtime.workflowConfig`,null),r=d(i,`runtime.defaultEffort`,null),a=d(i,`ui.theme`,`auto`),o=d(i,`runtime.workerConcurrency`,3);if(Array.isArray(e)&&e.length>0){let t=Object.fromEntries(e.map(e=>[e.role,e.provider]));E({planner:t.planner||``,executor:t.executor||``,reviewer:t.reviewer||``})}t&&typeof t==`object`&&Q({plan:t.plan?.model||``,execute:t.execute?.model||``,review:t.review?.model||``}),O(oe(r)),typeof a==`string`&&a.trim()&&N(a);let s=Number.parseInt(String(o??2),10);Number.isFinite(s)&&j(Math.min(10,Math.max(1,s)))},[i,n.isLoading]),(0,B.useEffect)(()=>{if(S.current||n.isLoading||L===null)return;S.current=!0;let e=w(i,L);ee(e.projectName),I(e.source)},[L,i,n.isLoading]);let Se=(0,B.useCallback)(e=>{ee(e),I(`manual`)},[]),$=a(P),Ce=T($);(0,B.useEffect)(()=>{document.title=T($||L?.detectedProjectName||L?.projectName||``)},[$,L]),(0,B.useEffect)(()=>{s>=1&&G===null&&(J(!0),Promise.all([o.get(`/providers`),o.get(`/config/workflow?details=1`).catch(()=>null)]).then(([e,t])=>{let n=Array.isArray(e)?e:e?.providers||[];K(n);let r=t?.models||{};fe(r);let i=n.filter(e=>e.available!==!1),a=i[0]?.id||i[0]?.name||``,o=i.find(e=>(e.id||e.name)===`claude`),s=a,c=o?`claude`:s,l={planner:c,executor:s,reviewer:c};E(e=>({planner:e.planner||l.planner,executor:e.executor||l.executor,reviewer:e.reviewer||l.reviewer})),Q(e=>({plan:e.plan||r[c]?.[0]?.id||``,execute:e.execute||r[s]?.[0]?.id||``,review:e.review||r[c]?.[0]?.id||``}))}).catch(()=>{K([])}).finally(()=>{J(!1)}))},[s,G]),(0,B.useEffect)(()=>{let e=M===`auto`?window.matchMedia(`(prefers-color-scheme: dark)`).matches?`dark`:`light`:M;document.documentElement.setAttribute(`data-theme`,e)},[M]);let we=(0,B.useCallback)(e=>{if(e===`Setup`)$&&Y(f,$,`system`).catch(()=>{});else if(e===`Pipeline`){let e=[{provider:C.planner,role:`planner`},{provider:C.executor,role:`executor`},{provider:C.reviewer,role:`reviewer`}];Y(`runtime.agentProvider`,C.executor,`runtime`).catch(()=>{}),Y(`runtime.pipeline`,e,`runtime`).catch(()=>{}),Y(`runtime.defaultEffort`,D,`runtime`).catch(()=>{}),Y(`runtime.workflowConfig`,se(C,D,Z),`runtime`).catch(()=>{})}else e===`Preferences`&&(Y(`ui.theme`,M,`ui`).catch(()=>{}),o.post(`/config/concurrency`,{concurrency:A}).catch(()=>{}))},[C,D,Z,A,M,$]),Te=(0,B.useCallback)(()=>{s<U-1&&(we(W),g(`forward`),c(e=>e+1))},[s,U,W,we]),Ee=(0,B.useCallback)(()=>{s>0&&(g(`backward`),c(e=>e-1))},[s]),De=(0,B.useCallback)(async()=>{if($){v(!0);try{let n=[Y(f,$,`system`),Y(`ui.theme`,M,`ui`),Y(`ui.onboarding.completed`,!0,`ui`)],r=[{provider:C.planner,role:`planner`},{provider:C.executor,role:`executor`},{provider:C.reviewer,role:`reviewer`}];n.push(Y(`runtime.agentProvider`,C.executor,`runtime`)),n.push(Y(`runtime.pipeline`,r,`runtime`)),n.push(Y(`runtime.defaultEffort`,D,`runtime`)),n.push(Y(`runtime.workflowConfig`,se(C,D,Z),`runtime`)),n.push(o.post(`/config/concurrency`,{concurrency:A})),z.length>0&&n.push(o.post(`/install/agents`,{agents:z})),H.length>0&&n.push(o.post(`/install/skills`,{skills:H})),await Promise.allSettled(n),t.setQueryData(u,e=>l(e,{id:f,scope:`system`,value:$,source:`user`,updatedAt:new Date().toISOString()})),t.setQueryData(u,e=>l(e,{id:`ui.onboarding.completed`,scope:`ui`,value:!0,source:`user`,updatedAt:new Date().toISOString()})),b({x:window.innerWidth/2,y:window.innerHeight/3}),setTimeout(()=>{t.invalidateQueries({queryKey:u}),e?.()},1200)}catch{t.setQueryData(u,e=>l(e,{id:f,scope:`system`,value:$,source:`user`,updatedAt:new Date().toISOString()})),t.setQueryData(u,e=>l(e,{id:`ui.onboarding.completed`,scope:`ui`,value:!0,source:`user`,updatedAt:new Date().toISOString()})),await Y(`ui.onboarding.completed`,!0,`ui`).catch(()=>{}),t.invalidateQueries({queryKey:u}),e?.()}}},[$,C,D,Z,A,M,z,H,t,e]),Oe=W===`Welcome`||W===`Setup`&&!!$||W===`Pipeline`&&(C.executor||q)||W===`Agents & Skills`||W===`Preferences`||W===`Launch`,ke=[],Ae=[],je={projectName:$,queueTitle:Ce,pipeline:C,efforts:D,concurrency:A,theme:M,agents:z,skills:H};return(0,V.jsxs)(`div`,{className:`fixed inset-0 z-50 bg-base-100 flex flex-col overflow-hidden`,children:[s===0&&(0,V.jsx)(ne,{}),y&&(0,V.jsx)(k,{x:y.x,y:y.y,active:!0,onDone:()=>b(null)}),s>0&&(0,V.jsx)(`div`,{className:`relative z-10 pt-6 pb-2 px-4 flex justify-center`,children:(0,V.jsx)(ce,{current:s})}),(0,V.jsx)(`div`,{className:`relative z-10 flex-1 flex flex-col items-center justify-start px-4 py-6 overflow-y-auto`,children:(0,V.jsxs)(le,{direction:h,stepKey:s,center:W===`Welcome`||W===`Setup`||W===`Pipeline`||W===`Launch`,children:[W===`Welcome`&&(0,V.jsx)(de,{workspacePath:me,onGetStarted:Te}),W===`Setup`&&(0,V.jsx)(pe,{projectName:P,setProjectName:Se,detectedProjectName:L?.detectedProjectName||``,projectSource:F,workspacePath:me,currentBranch:ve,onBranchCreated:e=>ye(e)}),W===`Pipeline`&&(0,V.jsx)(ge,{providers:G||[],providersLoading:q,pipeline:C,setPipeline:E,efforts:D,setEfforts:O,models:Z,setModels:Q,modelsByProvider:X}),W===`Agents & Skills`&&(0,V.jsx)(_e,{selectedAgents:z,setSelectedAgents:te,selectedSkills:H,setSelectedSkills:ae,existingAgents:ke,existingSkills:Ae}),W===`Preferences`&&(0,V.jsx)(be,{concurrency:A,setConcurrency:j,selectedTheme:M,setSelectedTheme:N}),W===`Launch`&&(0,V.jsx)(xe,{config:je,launching:_})]})}),(0,V.jsx)(ue,{step:s,stepCount:U,stepName:W,canProceed:Oe,launching:_,onBack:Ee,onNext:Te,onLaunch:De})]})}export{Se as default};
Binary file
@@ -1,8 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title">
2
- <title id="title">Fifony</title>
3
- <rect width="512" height="512" fill="#0f172a"/>
4
- <rect x="88" y="88" width="336" height="336" rx="72" fill="#13223d"/>
5
- <path fill="#4ade80" d="M154 160h204c11 0 20 9 20 20v26H134v-26c0-11 9-20 20-20z"/>
6
- <path fill="#22d3ee" d="M130 212h252l-24 138c-3 15-16 26-31 26H185c-15 0-28-11-31-26L130 212z"/>
7
- <circle cx="256" cy="326" r="24" fill="#0f172a"/>
8
- </svg>
@@ -1,7 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title">
2
- <title id="title">Fifony</title>
3
- <rect width="512" height="512" rx="96" fill="#0f172a"/>
4
- <path fill="#4ade80" d="M130 132h252c13 0 24 11 24 24v32H106v-32c0-13 11-24 24-24z"/>
5
- <path fill="#22d3ee" d="M102 192h308l-30 170c-3 18-19 32-38 32H170c-19 0-35-14-38-32L102 192z"/>
6
- <circle cx="256" cy="332" r="26" fill="#0f172a"/>
7
- </svg>
@@ -1,49 +0,0 @@
1
- {
2
- "id": "/",
3
- "name": "fifony Dashboard",
4
- "short_name": "fifony",
5
- "description": "fifony local orchestrator dashboard (React + PWA)",
6
- "lang": "en-US",
7
- "start_url": "/kanban",
8
- "scope": "/",
9
- "display": "standalone",
10
- "display_override": ["window-controls-overlay", "standalone", "browser"],
11
- "background_color": "#020617",
12
- "theme_color": "#0f172a",
13
- "orientation": "portrait-primary",
14
- "prefer_related_applications": false,
15
- "categories": ["productivity", "developer", "business"],
16
- "shortcuts": [
17
- {
18
- "name": "Kanban",
19
- "short_name": "Kanban",
20
- "url": "/kanban",
21
- "icons": [{ "src": "/icon.svg", "sizes": "any", "type": "image/svg+xml" }]
22
- },
23
- {
24
- "name": "Issues",
25
- "short_name": "Issues",
26
- "url": "/issues",
27
- "icons": [{ "src": "/icon.svg", "sizes": "any", "type": "image/svg+xml" }]
28
- },
29
- {
30
- "name": "Agents",
31
- "short_name": "Agents",
32
- "url": "/agents",
33
- "icons": [{ "src": "/icon.svg", "sizes": "any", "type": "image/svg+xml" }]
34
- }
35
- ],
36
- "icons": [
37
- {
38
- "src": "/icon.svg",
39
- "type": "image/svg+xml",
40
- "sizes": "any"
41
- },
42
- {
43
- "src": "/icon-maskable.svg",
44
- "type": "image/svg+xml",
45
- "sizes": "any",
46
- "purpose": "any maskable"
47
- }
48
- ]
49
- }
@@ -1,86 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <meta name="theme-color" content="#0f172a" />
7
- <title>Offline · fifony</title>
8
- <style>
9
- :root {
10
- color-scheme: dark;
11
- --bg: #020617;
12
- --panel: #0f172a;
13
- --line: rgba(148, 163, 184, 0.18);
14
- --text: #e2e8f0;
15
- --muted: #94a3b8;
16
- --accent: #22d3ee;
17
- --accent-2: #4ade80;
18
- }
19
- * { box-sizing: border-box; }
20
- body {
21
- margin: 0;
22
- min-height: 100vh;
23
- display: grid;
24
- place-items: center;
25
- background:
26
- radial-gradient(circle at top, rgba(34, 211, 238, 0.14), transparent 42%),
27
- radial-gradient(circle at bottom, rgba(74, 222, 128, 0.12), transparent 36%),
28
- var(--bg);
29
- color: var(--text);
30
- font: 16px/1.5 ui-sans-serif, system-ui, sans-serif;
31
- padding: 24px;
32
- }
33
- main {
34
- width: min(100%, 520px);
35
- padding: 28px;
36
- border-radius: 24px;
37
- border: 1px solid var(--line);
38
- background: linear-gradient(180deg, rgba(15, 23, 42, 0.96), rgba(15, 23, 42, 0.84));
39
- box-shadow: 0 20px 60px rgba(2, 6, 23, 0.45);
40
- }
41
- .eyebrow {
42
- display: inline-flex;
43
- padding: 6px 10px;
44
- border-radius: 999px;
45
- border: 1px solid var(--line);
46
- color: var(--muted);
47
- font-size: 12px;
48
- letter-spacing: 0.08em;
49
- text-transform: uppercase;
50
- }
51
- h1 { margin: 16px 0 8px; font-size: clamp(28px, 5vw, 40px); line-height: 1.05; }
52
- p { margin: 0; color: var(--muted); }
53
- .actions { display: flex; gap: 12px; margin-top: 24px; flex-wrap: wrap; }
54
- a, button {
55
- appearance: none;
56
- border: 0;
57
- border-radius: 999px;
58
- padding: 12px 18px;
59
- font: inherit;
60
- text-decoration: none;
61
- cursor: pointer;
62
- }
63
- a {
64
- color: #082f49;
65
- background: linear-gradient(135deg, var(--accent), var(--accent-2));
66
- font-weight: 700;
67
- }
68
- button {
69
- color: var(--text);
70
- background: rgba(148, 163, 184, 0.12);
71
- border: 1px solid var(--line);
72
- }
73
- </style>
74
- </head>
75
- <body>
76
- <main>
77
- <div class="eyebrow">Offline</div>
78
- <h1>fifony is temporarily disconnected.</h1>
79
- <p>The dashboard shell is available, but live runtime data needs the local server connection to come back.</p>
80
- <div class="actions">
81
- <a href="/kanban">Try again</a>
82
- <button type="button" onclick="location.reload()">Reload</button>
83
- </div>
84
- </main>
85
- </body>
86
- </html>
@@ -1,145 +0,0 @@
1
- const CACHE_VERSION = "__BUILD_TIMESTAMP__";
2
- const CORE_CACHE = `fifony-core-${CACHE_VERSION}`;
3
- const ASSET_CACHE = `fifony-assets-${CACHE_VERSION}`;
4
- const APP_SHELL_ROUTES = ["/kanban", "/issues", "/agents", "/settings", "/onboarding"];
5
- const APP_SHELL_FILES = ["/offline.html", "/manifest.webmanifest", "/icon.svg", "/icon-maskable.svg"];
6
- const API_PREFIXES = ["/api/", "/docs", "/ws"];
7
-
8
- self.addEventListener("install", (event) => {
9
- event.waitUntil((async () => {
10
- const cache = await caches.open(CORE_CACHE);
11
- // Cache each route individually so one failure doesn't block the rest
12
- await Promise.allSettled(
13
- [...APP_SHELL_ROUTES, ...APP_SHELL_FILES].map(async (url) => {
14
- try {
15
- const response = await fetch(url);
16
- if (response.ok) await cache.put(url, response);
17
- } catch {}
18
- }),
19
- );
20
- await self.skipWaiting();
21
- })());
22
- });
23
-
24
- self.addEventListener("activate", (event) => {
25
- event.waitUntil((async () => {
26
- const names = await caches.keys();
27
- await Promise.all(
28
- names
29
- .filter((name) => name !== CORE_CACHE && name !== ASSET_CACHE)
30
- .map((name) => caches.delete(name)),
31
- );
32
- await self.clients.claim();
33
-
34
- // Notify all clients that a new version activated (they may show a refresh banner)
35
- const clients = await self.clients.matchAll({ type: "window" });
36
- for (const client of clients) {
37
- client.postMessage({ type: "SW_UPDATED", version: CACHE_VERSION });
38
- }
39
- })());
40
- });
41
-
42
- self.addEventListener("message", (event) => {
43
- if (event.data?.type === "SKIP_WAITING") {
44
- self.skipWaiting();
45
- }
46
-
47
- if (event.data?.type === "GET_OFFLINE_STATUS") {
48
- const port = event.ports?.[0];
49
- if (port) {
50
- // Probe the API to determine online/offline state
51
- fetch("/health", { signal: AbortSignal.timeout(3000) })
52
- .then((res) => port.postMessage({ offline: !res.ok }))
53
- .catch(() => port.postMessage({ offline: true }));
54
- }
55
- }
56
-
57
- if (event.data?.type === "GET_VERSION") {
58
- const port = event.ports?.[0];
59
- if (port) {
60
- port.postMessage({ version: CACHE_VERSION });
61
- }
62
- }
63
- });
64
-
65
- self.addEventListener("fetch", (event) => {
66
- const request = event.request;
67
- if (request.method !== "GET") return;
68
-
69
- const url = new URL(request.url);
70
- if (url.origin !== self.location.origin) return;
71
- if (API_PREFIXES.some((prefix) => url.pathname.startsWith(prefix))) return;
72
-
73
- if (request.mode === "navigate") {
74
- event.respondWith((async () => {
75
- try {
76
- const response = await fetch(request);
77
- const cache = await caches.open(CORE_CACHE);
78
- await cache.put(request, response.clone());
79
- return response;
80
- } catch {
81
- // Offline: notify clients
82
- notifyClientsOffline();
83
-
84
- const cache = await caches.open(CORE_CACHE);
85
- return (
86
- await cache.match(request) ||
87
- await cache.match("/kanban") ||
88
- await cache.match("/offline.html")
89
- );
90
- }
91
- })());
92
- return;
93
- }
94
-
95
- const isStaticAsset =
96
- url.pathname.startsWith("/assets/") ||
97
- url.pathname.endsWith(".css") ||
98
- url.pathname.endsWith(".js") ||
99
- url.pathname.endsWith(".svg") ||
100
- url.pathname.endsWith(".webmanifest");
101
-
102
- if (!isStaticAsset) return;
103
-
104
- event.respondWith((async () => {
105
- const cache = await caches.open(ASSET_CACHE);
106
- const cached = await cache.match(request);
107
-
108
- if (cached) {
109
- event.waitUntil((async () => {
110
- try {
111
- const fresh = await fetch(request);
112
- if (fresh?.ok) {
113
- await cache.put(request, fresh.clone());
114
- }
115
- } catch {}
116
- })());
117
- return cached;
118
- }
119
-
120
- try {
121
- const response = await fetch(request);
122
- if (response?.ok) {
123
- await cache.put(request, response.clone());
124
- }
125
- return response;
126
- } catch {
127
- if (cached) return cached;
128
- return new Response("Offline", {
129
- status: 503,
130
- statusText: "Service Unavailable",
131
- headers: { "content-type": "text/plain; charset=utf-8" },
132
- });
133
- }
134
- })());
135
- });
136
-
137
- // Broadcast offline status to all window clients
138
- async function notifyClientsOffline() {
139
- try {
140
- const clients = await self.clients.matchAll({ type: "window" });
141
- for (const client of clients) {
142
- client.postMessage({ type: "OFFLINE" });
143
- }
144
- } catch {}
145
- }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/agents/cli-wrapper.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * fifony-wrap — man-in-the-middle wrapper for CLI agents\n *\n * Protocol:\n * FIFONY_WRAP_COMMAND (required) real CLI command to run, e.g. \"claude -p $FIFONY_TURN_PROMPT_FILE\"\n * FIFONY_WRAP_BEFORE_HOOK (optional) shell script run before the CLI; can modify $FIFONY_TURN_PROMPT_FILE in place\n * FIFONY_WRAP_AFTER_HOOK (optional) shell script run after the CLI; receives FIFONY_WRAP_OUTPUT_FILE pointing\n * to a temp file with the captured output — modify it in place to change what fifony sees\n *\n * Configure via the API, MCP, or s3db — set agentCommand on the workflow config to:\n * FIFONY_WRAP_COMMAND=\"claude -p $FIFONY_TURN_PROMPT_FILE\" FIFONY_WRAP_BEFORE_HOOK=./hooks/before.sh fifony-wrap\n */\nimport { readFileSync, writeFileSync, rmSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { env, exit } from \"node:process\";\nimport { spawn } from \"node:child_process\";\n\nfunction runShell(command: string, extraEnv: Record<string, string> = {}): Promise<{ code: number }> {\n return new Promise((resolve) => {\n const child = spawn(command, {\n shell: true,\n stdio: \"inherit\",\n env: { ...env, ...extraEnv },\n });\n child.on(\"close\", (code) => resolve({ code: code ?? 1 }));\n child.on(\"error\", () => resolve({ code: 1 }));\n });\n}\n\nfunction runAndCapture(command: string): Promise<{ code: number | null; output: string }> {\n return new Promise((resolve) => {\n const child = spawn(command, { shell: true, stdio: [\"inherit\", \"pipe\", \"pipe\"] });\n let output = \"\";\n child.stdout?.on(\"data\", (chunk: Buffer) => { output += String(chunk); });\n child.stderr?.on(\"data\", (chunk: Buffer) => { output += String(chunk); });\n child.on(\"close\", (code) => resolve({ code, output }));\n child.on(\"error\", () => resolve({ code: null, output: `Command execution error: ${command}` }));\n });\n}\n\nasync function main() {\n const wrapCommand = env.FIFONY_WRAP_COMMAND?.trim();\n if (!wrapCommand) {\n process.stderr.write(\"fifony-wrap: FIFONY_WRAP_COMMAND is required\\n\");\n exit(1);\n }\n\n const workspacePath = env.FIFONY_WORKSPACE_PATH ?? process.cwd();\n const beforeHook = env.FIFONY_WRAP_BEFORE_HOOK?.trim();\n const afterHook = env.FIFONY_WRAP_AFTER_HOOK?.trim();\n const outputFile = join(workspacePath, \".wrap-output.txt\");\n\n if (beforeHook) {\n const { code } = await runShell(beforeHook);\n if (code !== 0) {\n process.stderr.write(`fifony-wrap: before hook exited ${code}\\n`);\n exit(code);\n }\n }\n\n const { code, output } = await runAndCapture(wrapCommand);\n\n writeFileSync(outputFile, output, \"utf8\");\n\n if (afterHook) {\n const { code: hookCode } = await runShell(afterHook, { FIFONY_WRAP_OUTPUT_FILE: outputFile });\n if (hookCode !== 0) {\n process.stderr.write(`fifony-wrap: after hook exited ${hookCode} — using original output\\n`);\n writeFileSync(outputFile, output, \"utf8\");\n }\n }\n\n let finalOutput = output;\n try {\n finalOutput = readFileSync(outputFile, \"utf8\");\n } catch {}\n try { rmSync(outputFile, { force: true }); } catch {}\n\n process.stdout.write(finalOutput);\n exit(code ?? 1);\n}\n\nmain().catch((err) => {\n process.stderr.write(`fifony-wrap: fatal: ${String(err)}\\n`);\n exit(1);\n});\n"],"mappings":";;;AAaA,SAAS,cAAc,eAAe,cAAc;AACpD,SAAS,YAAY;AACrB,SAAS,KAAK,YAAY;AAC1B,SAAS,aAAa;AAEtB,SAAS,SAAS,SAAiB,WAAmC,CAAC,GAA8B;AACnG,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,MAAM,SAAS;AAAA,MAC3B,OAAO;AAAA,MACP,OAAO;AAAA,MACP,KAAK,EAAE,GAAG,KAAK,GAAG,SAAS;AAAA,IAC7B,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,SAAS,QAAQ,EAAE,MAAM,QAAQ,EAAE,CAAC,CAAC;AACxD,UAAM,GAAG,SAAS,MAAM,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAAA,EAC9C,CAAC;AACH;AAEA,SAAS,cAAc,SAAmE;AACxF,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,UAAM,QAAQ,MAAM,SAAS,EAAE,OAAO,MAAM,OAAO,CAAC,WAAW,QAAQ,MAAM,EAAE,CAAC;AAChF,QAAI,SAAS;AACb,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAAE,gBAAU,OAAO,KAAK;AAAA,IAAG,CAAC;AACxE,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAkB;AAAE,gBAAU,OAAO,KAAK;AAAA,IAAG,CAAC;AACxE,UAAM,GAAG,SAAS,CAAC,SAAS,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC;AACrD,UAAM,GAAG,SAAS,MAAM,QAAQ,EAAE,MAAM,MAAM,QAAQ,4BAA4B,OAAO,GAAG,CAAC,CAAC;AAAA,EAChG,CAAC;AACH;AAEA,eAAe,OAAO;AACpB,QAAM,cAAc,IAAI,qBAAqB,KAAK;AAClD,MAAI,CAAC,aAAa;AAChB,YAAQ,OAAO,MAAM,gDAAgD;AACrE,SAAK,CAAC;AAAA,EACR;AAEA,QAAM,gBAAgB,IAAI,yBAAyB,QAAQ,IAAI;AAC/D,QAAM,aAAa,IAAI,yBAAyB,KAAK;AACrD,QAAM,YAAY,IAAI,wBAAwB,KAAK;AACnD,QAAM,aAAa,KAAK,eAAe,kBAAkB;AAEzD,MAAI,YAAY;AACd,UAAM,EAAE,MAAAA,MAAK,IAAI,MAAM,SAAS,UAAU;AAC1C,QAAIA,UAAS,GAAG;AACd,cAAQ,OAAO,MAAM,mCAAmCA,KAAI;AAAA,CAAI;AAChE,WAAKA,KAAI;AAAA,IACX;AAAA,EACF;AAEA,QAAM,EAAE,MAAM,OAAO,IAAI,MAAM,cAAc,WAAW;AAExD,gBAAc,YAAY,QAAQ,MAAM;AAExC,MAAI,WAAW;AACb,UAAM,EAAE,MAAM,SAAS,IAAI,MAAM,SAAS,WAAW,EAAE,yBAAyB,WAAW,CAAC;AAC5F,QAAI,aAAa,GAAG;AAClB,cAAQ,OAAO,MAAM,kCAAkC,QAAQ;AAAA,CAA4B;AAC3F,oBAAc,YAAY,QAAQ,MAAM;AAAA,IAC1C;AAAA,EACF;AAEA,MAAI,cAAc;AAClB,MAAI;AACF,kBAAc,aAAa,YAAY,MAAM;AAAA,EAC/C,QAAQ;AAAA,EAAC;AACT,MAAI;AAAE,WAAO,YAAY,EAAE,OAAO,KAAK,CAAC;AAAA,EAAG,QAAQ;AAAA,EAAC;AAEpD,UAAQ,OAAO,MAAM,WAAW;AAChC,OAAK,QAAQ,CAAC;AAChB;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,OAAO,MAAM,uBAAuB,OAAO,GAAG,CAAC;AAAA,CAAI;AAC3D,OAAK,CAAC;AACR,CAAC;","names":["code"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/boot.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { mkdirSync } from \"node:fs\";\nimport { env, exit, argv } from \"node:process\";\nimport { CLI_ARGS, PACKAGE_ROOT, STATE_ROOT, TARGET_ROOT } from \"./concerns/constants.ts\";\nimport { debugBoot, fail, now, sleep, parseIntArg } from \"./concerns/helpers.ts\";\nimport { initLogger, logger } from \"./concerns/logger.ts\";\nimport { initStateStore, loadPersistedState, persistState, persistStateFull, closeStateStore } from \"./persistence/store.ts\";\nimport { initQueueWorkers, stopQueueWorkers, enqueueForPlanning, enqueueForExecution, enqueueForReview } from \"./persistence/plugins/queue-workers.ts\";\nimport { createContainer } from \"./persistence/container.ts\";\nimport {\n applyPersistedSettings,\n loadRuntimeSettings,\n persistDetectedProvidersSetting,\n syncRuntimeConfigSettings,\n} from \"./persistence/settings.ts\";\nimport { buildQueueTitle, detectProjectName, resolveProjectMetadata } from \"./domains/project.ts\";\nimport {\n detectAvailableProviders,\n resolveDefaultProvider,\n getProviderDefaultCommand,\n} from \"./agents/providers.ts\";\nimport { setSkipSource, detectDefaultBranch } from \"./domains/workspace.ts\";\nimport { deriveConfig, applyWorkflowConfig, buildRuntimeState, computeMetrics, addEvent, validateConfig } from \"./domains/issues.ts\";\nimport { hasDirtyState } from \"./persistence/dirty-tracker.ts\";\nimport { executeTransition } from \"./persistence/plugins/issue-state-machine.ts\";\nimport { startApiServer } from \"./persistence/plugins/api-server.ts\";\nimport { installGracefulShutdown, isShuttingDown, ensureNotStale, hasTerminalQueue } from \"./persistence/plugins/scheduler.ts\";\nimport { cleanWorkspace, isAgentStillRunning, cleanStalePidFile } from \"./agents/agent.ts\";\nimport { recoverPlanningSession } from \"./agents/planning/issue-planner.ts\";\nimport { hydrate as hydrateTokenLedger } from \"./domains/tokens.ts\";\nimport { resolve } from \"node:path\";\nimport type { RuntimeState } from \"./types.ts\";\n\nfunction parsePort(args: string[]): number | undefined {\n for (let i = 0; i < args.length; i += 1) {\n const arg = args[i];\n if (arg === \"--port\") {\n const value = args[i + 1];\n if (!value || !/^\\d+$/.test(value)) {\n fail(`Invalid value for --port: ${value ?? \"<empty>\"}`);\n }\n return parseIntArg(value, 4040);\n }\n }\n return undefined;\n}\n\nasync function startDevFrontend(apiPort: number, devPort: number): Promise<void> {\n const VITE_CONFIG_PATH = resolve(PACKAGE_ROOT, \"app/vite.config.js\");\n let createViteServer: typeof import(\"vite\").createServer;\n try {\n const vite = await import(\"vite\");\n createViteServer = vite.createServer;\n } catch {\n logger.warn(\"Vite not installed (devDependency). Run 'pnpm install' in the project to enable --dev mode.\");\n return;\n }\n // Wait for the API server to be ready before starting the proxy\n for (let attempt = 0; attempt < 20; attempt++) {\n try {\n const res = await fetch(`http://localhost:${apiPort}/api/health`);\n if (res.ok) break;\n } catch {\n await new Promise((r) => setTimeout(r, 250));\n }\n }\n\n try {\n const server = await createViteServer({\n configFile: VITE_CONFIG_PATH,\n customLogger: {\n info: (msg: string) => logger.info(`[Vite] ${msg}`),\n warn: (msg: string) => logger.warn(`[Vite] ${msg}`),\n warnOnce: (msg: string) => logger.warn(`[Vite] ${msg}`),\n error: (msg: string) => {\n if (msg.includes(\"ws proxy error\") || msg.includes(\"ws proxy socket error\")) {\n logger.debug(`[Vite] ${msg.split(\"\\n\")[0]} (transient, suppressed)`);\n return;\n }\n logger.error(`[Vite] ${msg}`);\n },\n hasErrorLogged: () => false,\n clearScreen: () => {},\n hasWarned: false,\n },\n server: {\n port: devPort,\n host: true,\n proxy: {\n \"/api\": `http://localhost:${apiPort}`,\n \"/ws\": {\n target: `ws://localhost:${apiPort}`,\n ws: true,\n configure: (proxy) => {\n const silence = (err: any) => {\n logger.debug(`[Vite] WS proxy transient: ${err.code || err.message}`);\n };\n proxy.on(\"error\", silence);\n proxy.on(\"proxyReqWs\", (_proxyReq: any, _req: any, socket: any) => {\n socket.on(\"error\", silence);\n });\n },\n },\n \"/docs\": `http://localhost:${apiPort}`,\n \"/health\": `http://localhost:${apiPort}`,\n \"/manifest.webmanifest\": `http://localhost:${apiPort}`,\n \"/service-worker.js\": `http://localhost:${apiPort}`,\n \"/icon.svg\": `http://localhost:${apiPort}`,\n \"/icon-maskable.svg\": `http://localhost:${apiPort}`,\n \"/offline.html\": `http://localhost:${apiPort}`,\n },\n },\n });\n await server.listen();\n logger.info(`Dev frontend available at http://localhost:${devPort}`);\n } catch (error) {\n logger.warn(`Failed to start Vite dev server: ${String(error)}`);\n }\n}\n\nfunction usage() {\n console.log(\n `Usage: ${argv[1]} [options]\\n` +\n \"Options:\\n\" +\n \" --workspace <path> Target workspace root (default: current directory)\\n\" +\n \" --persistence <path> Persistence root (default: current directory)\\n\" +\n \" --port <n> Start local dashboard\\n\" +\n \" --concurrency <n> Maximum number of local workers\\n\" +\n \" --attempts <n> Maximum attempts per issue\\n\" +\n \" --poll <ms> Scheduler interval in ms\\n\" +\n \" --timeout <ms> Agent command timeout in ms (default: 1800000)\\n\" +\n \" --dev Start Vite dev server alongside API (HMR on port+1)\\n\" +\n \" --once Process once and exit\\n\" +\n \" --skip-source Skip source snapshot copy\\n\" +\n \" --skip-scan Skip project analysis\\n\" +\n \" --skip-recovery Skip orphaned agent recovery\\n\" +\n \" --fast-boot Equivalent to --skip-source --skip-scan --skip-recovery\\n\",\n );\n}\n\nasync function main() {\n debugBoot(\"main:start\");\n\n const args = CLI_ARGS;\n if (args.includes(\"--help\") || args.includes(\"-h\")) {\n usage();\n return;\n }\n\n mkdirSync(STATE_ROOT, { recursive: true });\n initLogger(STATE_ROOT);\n logger.info(\"[Boot] Fifony runtime starting\");\n logger.info({ stateRoot: STATE_ROOT, cwd: process.cwd() }, \"[Boot] State root initialized\");\n\n // Detect available providers\n const detectedProviders = detectAvailableProviders();\n for (const p of detectedProviders) {\n logger.info(`Provider ${p.name}: ${p.available ? `available at ${p.path}` : \"not found\"}`);\n }\n\n const interfaceMode = (env.FIFONY_INTERFACE ?? \"cli\").trim().toLowerCase();\n const runOnce = args.includes(\"--once\");\n const devMode = args.includes(\"--dev\") || env.NODE_ENV === \"development\";\n const fastBoot = args.includes(\"--fast-boot\");\n const skipSource = fastBoot || args.includes(\"--skip-source\");\n if (skipSource) setSkipSource(true);\n\n debugBoot(\"main:state-root-ready\");\n\n const port = parsePort(args);\n let config = applyWorkflowConfig(deriveConfig(args), port);\n\n // Auto-resolve provider command if not configured\n if (!config.agentCommand.trim()) {\n const defaultProvider = resolveDefaultProvider(detectedProviders);\n if (defaultProvider) {\n const defaultCommand = getProviderDefaultCommand(defaultProvider);\n if (defaultCommand) {\n config = { ...config, agentProvider: defaultProvider, agentCommand: defaultCommand };\n logger.info(`Auto-detected provider: ${defaultProvider} → ${defaultCommand}`);\n }\n }\n }\n\n const dashboardPort = port ?? (config.dashboardPort ? Number.parseInt(config.dashboardPort, 10) : undefined);\n const skipRecovery = args.includes(\"--skip-recovery\") || args.includes(\"--fast-boot\");\n const detectedProjectName = detectProjectName(TARGET_ROOT);\n\n // ── Phase B: Parallel initialization ────────────────────────────────────────\n debugBoot(\"main:phase-b-start\");\n logger.debug(\"[Boot] Initializing state store (s3db)\");\n await initStateStore();\n logger.info(\"[Boot] State store initialized\");\n debugBoot(\"main:store-initialized\");\n\n // ── Early API start: dashboard available while boot continues ─────────────\n // Build a minimal placeholder state for the early API server\n const earlyState: RuntimeState = {\n projectName: detectedProjectName,\n detectedProjectName,\n projectNameSource: detectedProjectName ? \"detected\" : \"missing\",\n queueTitle: buildQueueTitle(detectedProjectName),\n startedAt: now(),\n updatedAt: now(),\n trackerKind: \"filesystem\",\n sourceRepoUrl: TARGET_ROOT,\n sourceRef: \"workspace\",\n config,\n issues: [],\n events: [],\n metrics: { total: 0, planning: 0, queued: 0, inProgress: 0, blocked: 0, done: 0, merged: 0, cancelled: 0, activeWorkers: 0 },\n notes: [],\n booting: true,\n };\n\n let apiState = earlyState;\n // Initialize container early so API routes can use commands immediately\n createContainer(apiState);\n debugBoot(\"main:container-early-init\");\n\n if (dashboardPort) {\n await startApiServer(apiState, dashboardPort);\n debugBoot(\"main:api-server-early-start\");\n\n if (devMode) {\n const devPort = dashboardPort + 1;\n await startDevFrontend(dashboardPort, devPort);\n }\n }\n\n // ── Phase C: Parallel state loading ─────────────────────────────────────────\n debugBoot(\"main:phase-c-start\");\n logger.debug(\"[Boot] Loading persisted state, settings, and recovering sessions\");\n const [previous, persistedSettings] = await Promise.all([\n loadPersistedState(),\n loadRuntimeSettings(),\n persistDetectedProvidersSetting(detectedProviders),\n recoverPlanningSession(),\n ]);\n logger.info({ hadPreviousState: previous !== null, issueCount: previous?.issues?.length ?? 0, settingsCount: persistedSettings.length }, \"[Boot] State loaded from persistence\");\n debugBoot(\"main:state-loaded\");\n\n config = applyPersistedSettings(config, persistedSettings);\n await syncRuntimeConfigSettings(config, persistedSettings);\n const projectMetadata = resolveProjectMetadata(persistedSettings, TARGET_ROOT);\n const state = buildRuntimeState(previous, config, projectMetadata);\n debugBoot(\"main:state-merged\");\n\n state.config.dashboardPort = dashboardPort ? String(dashboardPort) : undefined;\n state.updatedAt = now();\n state.booting = false;\n\n // Reconcile in-memory state with FSM persisted state (source of truth)\n try {\n const { getIssueStateMachinePlugin, ISSUE_STATE_MACHINE_ID } = await import(\"./persistence/plugins/issue-state-machine.ts\");\n const fsmPlugin = getIssueStateMachinePlugin();\n if (fsmPlugin?.getState) {\n for (const issue of state.issues) {\n try {\n const fsmState = await fsmPlugin.getState(ISSUE_STATE_MACHINE_ID, issue.id);\n if (fsmState && fsmState !== issue.state) {\n logger.warn({ issueId: issue.id, memoryState: issue.state, fsmState }, \"[Boot] Reconciling desync — FSM is source of truth\");\n issue.state = fsmState as typeof issue.state;\n }\n } catch { /* FSM entity may not exist yet */ }\n }\n }\n } catch { /* FSM plugin may not be ready */ }\n\n // Detect and lock the default branch once at startup\n if (!state.config.defaultBranch) {\n try {\n const detectedBranch = detectDefaultBranch(TARGET_ROOT);\n state.config.defaultBranch = detectedBranch;\n logger.info({ defaultBranch: detectedBranch }, \"[Agent] Default branch detected\");\n } catch {\n // Not a git repo or detection failed — leave undefined\n }\n }\n\n if (state.config.agentCommand) {\n state.notes.push(`Using agent command: ${state.config.agentCommand}`);\n }\n state.notes.push(`Agent session max turns: ${state.config.maxTurns}`);\n state.notes.push(`Agent provider: ${state.config.agentProvider}`);\n state.notes.push(`Interface mode: ${interfaceMode}`);\n\n if (!state.config.agentCommand.trim()) {\n const available = detectedProviders.filter((p) => p.available).map((p) => p.name);\n fail(\n available.length === 0\n ? \"No agent command configured and no providers (claude, codex) found in PATH.\\nInstall claude or codex, or set FIFONY_AGENT_COMMAND.\"\n : \"No agent command configured. Set FIFONY_AGENT_COMMAND.\",\n );\n }\n\n // Validate config at startup (spec §6.3)\n const configErrors = validateConfig(config);\n if (configErrors.length > 0) {\n for (const err of configErrors) logger.warn(`Config validation: ${err}`);\n }\n\n // Clean terminal workspaces in background (non-blocking boot)\n const terminalIssues = state.issues.filter((i) => i.state === \"Merged\" || i.state === \"Cancelled\");\n if (terminalIssues.length > 0) {\n logger.info(`Scheduling cleanup of ${terminalIssues.length} terminal workspace(s) in background...`);\n setImmediate(async () => {\n for (const issue of terminalIssues) {\n try { await cleanWorkspace(issue.id, issue, state); } catch {}\n }\n logger.info(\"Background workspace cleanup complete.\");\n });\n }\n\n // Recover orphaned agent processes from previous session\n if (!skipRecovery) {\n logger.debug({ issueCount: state.issues.filter((i) => i.state === \"Running\" || i.state === \"Queued\").length }, \"[Boot] Checking for orphaned agent processes\");\n for (const issue of state.issues) {\n if (issue.state === \"Running\" || issue.state === \"Queued\") {\n const { alive, pid } = isAgentStillRunning(issue);\n if (alive && pid) {\n logger.info(`Agent for ${issue.identifier} still alive (PID ${pid.pid}), keeping state as Running.`);\n if (issue.state !== \"Running\") {\n try { await executeTransition(issue, \"RUN\", { issue, note: `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.` }); }\n catch { issue.state = \"Running\"; }\n }\n addEvent(state, issue.id, \"info\", `Orphaned agent detected (PID ${pid.pid}), still alive — tracking resumed.`);\n } else {\n // Agent died — clean PID file, mark as Queued for resumption\n if (issue.workspacePath) cleanStalePidFile(issue.workspacePath);\n if (issue.state === \"Running\") {\n try { await executeTransition(issue, \"REQUEUE\", { issue, note: `Agent process not found on boot — marked Queued.` }); }\n catch { issue.state = \"Queued\"; }\n addEvent(state, issue.id, \"info\", `Agent for ${issue.identifier} not found, marked Queued.`);\n }\n }\n }\n }\n }\n\n state.metrics = computeMetrics(state.issues);\n\n // Swap state into API server IMMEDIATELY so the dashboard shows real data\n if (dashboardPort) {\n Object.assign(apiState, state);\n debugBoot(\"main:api-state-swapped\");\n }\n createContainer(apiState);\n logger.info(\"[Boot] DI container initialized with full state\");\n\n await persistStateFull(state);\n\n // Initialize queue workers (can be slow — dashboard already has real data)\n try {\n await initQueueWorkers(state);\n } catch (error) {\n logger.warn({ err: error }, \"[Boot] Queue workers failed to initialize — continuing without queue-based dispatch\");\n }\n\n const running = new Set<string>();\n installGracefulShutdown(state, running);\n\n logger.info(\"[Boot] Runtime ready\");\n hydrateTokenLedger(state.issues);\n logger.info(`Loaded issues: ${state.issues.length}`);\n logger.info(`Worker concurrency: ${state.config.workerConcurrency}`);\n logger.info(`Max attempts: ${state.config.maxAttemptsDefault}`);\n logger.info(`Max turns: ${state.config.maxTurns}`);\n logger.info(`Agent provider: ${state.config.agentProvider}`);\n logger.info(`Interface mode: ${interfaceMode}`);\n\n try {\n addEvent(state, undefined, \"info\", `Runtime started in local-only mode (filesystem tracker).`);\n const runForever = !runOnce && (Boolean(dashboardPort) || interfaceMode === \"mcp\");\n logger.info({ runForever, runOnce, dashboardPort, interfaceMode }, \"[Boot] Entering queue supervisor loop\");\n\n // Boot recovery: enqueue all in-progress issues so queue workers pick them up\n for (const issue of state.issues) {\n try {\n if (issue.state === \"Planning\" && issue.planningStatus !== \"planning\") {\n await enqueueForPlanning(issue);\n } else if (issue.state === \"Queued\" || issue.state === \"Running\") {\n await enqueueForExecution(issue);\n } else if (issue.state === \"Reviewing\") {\n await enqueueForReview(issue);\n }\n } catch (err) {\n logger.error({ err, issueId: issue.id, state: issue.state }, \"[Boot] Failed to enqueue issue for recovery\");\n }\n }\n\n const PERSIST_DEBOUNCE_MS = 5_000;\n let lastPersistAt = 0;\n\n if (runForever) {\n while (!isShuttingDown()) {\n // Take a snapshot of states before stale recovery so we can detect transitions\n const statesBefore = new Map(state.issues.map((i) => [i.id, i.state]));\n await ensureNotStale(state, state.config.staleInProgressTimeoutMs);\n\n // Re-enqueue any issues that just changed state due to stale recovery or retry eligibility\n for (const issue of state.issues) {\n const prev = statesBefore.get(issue.id);\n if (prev !== issue.state) {\n if (issue.state === \"Queued\") enqueueForExecution(issue).catch(() => {});\n else if (issue.state === \"Reviewing\") enqueueForReview(issue).catch(() => {});\n else if (issue.state === \"Planning\") enqueueForPlanning(issue).catch(() => {});\n }\n }\n\n state.updatedAt = now();\n if (hasDirtyState() || Date.now() - lastPersistAt > PERSIST_DEBOUNCE_MS) {\n await persistState(state);\n lastPersistAt = Date.now();\n }\n await sleep(1_000);\n }\n } else {\n // Batch mode: wait until all issues reach terminal states\n while (!hasTerminalQueue(state)) {\n await sleep(state.config.pollIntervalMs);\n }\n }\n } catch (error) {\n console.error(\"FATAL STACK TRACE:\", error);\n addEvent(state, undefined, \"error\", `Fatal runtime error: ${String(error)}`);\n await persistState(state);\n throw error;\n } finally {\n state.updatedAt = now();\n state.metrics = computeMetrics(state.issues);\n await persistStateFull(state);\n try { await stopQueueWorkers(); } catch {}\n await closeStateStore();\n }\n}\n\nmain().catch((error) => {\n logger.error({ err: error }, `Fatal runtime error: ${String(error)}`);\n exit(1);\n});\n"],"mappings":"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","names":[]}